Consider the following example
def futureFoo() = {
Future.successful(true)
}
def recFoo(x: List[Int]): Unit = {
if (x.isEmpty) return
for {
b <- futureFoo()
v = getNewListOfValues(x.last)
_ = recFoo(v)
} yield b
}
I need to wait for futureFoo to finish and only then call recFoo again. The problem is no matter what I try I get the following error:
discarded non-Unit value
I also tried to convert it into a while loop but because of the future I either get the same error or the while condition doesn't update because it must be updated in a for comprehension or map.
Any ideas on how to prevent that error?
Try this.
def recFoo(x: List[Int]): Unit =
if (x.nonEmpty)
futureFoo().foreach(_ => recFoo(getNewListOfValues(x.last)))
The specific reason that you are getting
discarded non-Unit value
in your error message is that you have an expression after return.
Note that in Scala, the return keyword should almost never be used. Scala is an expression-oriented language; each block (such as a function body) evaluates to the value returned from the last line in the block.
So, for example, consider the following snippet:
val foo = {
import scala.util.Random
if (Random.nextInt() % 2 == 0) {
17
} else {
"bar"
}
}
Everything from if to the closing brace after "bar" is a single expression -- NOT a statement. Scala, in fact, does not have "if-statements" in the way that Java and other languages do. In particular, the compiler needs to infer a type for the name foo, and since foo could concretely be either the Int 17 or the String "bar", that inferred type is the closest common ancestor of both Int and String, which is Any.
In your question, the last expression in the body of recFoo is the following:
for {
b <- futureFoo()
v = getNewListOfValues(x.last)
_ = recFoo(v)
} yield b
What is the type of this expression? In many languages, for introduces a statement, but that's not true of Scala -- this is an expression, not a statement, and like all expressions it will have a value once we evaluate it. That value has type Future[Unit], and like all non-Unit values, the compiler is warning you that you are discarding a value, which is (almost) always a mistake. (Why would you go to the trouble of producing a non-Unit value and then not make use of it?, goes the thinking.)
Related
Wondering why this code is not working, Am I missing something?
def treemin(lst: List[Any]): Int = {
var MaVar: Int = 1000{
case (sum,leaf: Int) =>
if(leaf < MaVar) {MaVar = leaf}
}
}
The error I have occur here :
if(leaf < MaVar) {MaVar = leaf}
Error :
Error: type mismatch; found : Unit required: Int
I already had a look here but I didn't manage to solve this issue since I am new to scala, it might be a silly error.
Note : Is this a good approach to get the minimum leaf of a tree?
I got a Tree :
And I am trying to do a function which will return the min leaf, for example here it would return 2.
There are actually two errors in your code:
def treemin(lst: List[Any]): Int = {
var MaVar: Int = 1000{
case (sum,leaf: Int) =>
if(leaf < MaVar) {MaVar = leaf}
}
}
The first error is this one:
var MaVar: Int = 1000{
^
On line 2: error: Int(1000) does not take parameters
}
^
Here, you are trying to call 1000 with an argument, as if it were a function. It is not quite clear what you are trying to achieve here. Are you trying to create a new lexical scope? Then, you need to add an empty line so that Scala doesn't interpret your curly braces as an argument to 1000:
def treemin(lst: List[Any]): Int = {
var MaVar: Int = 1000
{
case (sum,leaf: Int) =>
if(leaf < MaVar) {MaVar = leaf}
}
}
However, now you get another error, because now the curly braces are interpreted as creating an anonymous function:
{
^
On line 4: error: missing parameter type for expanded function
The argument types of an anonymous function must be fully known. (SLS 8.5)
Expected type was: Int
There are ways to work around that, but the thing is: it doesn't make sense to create a new lexical scope here, since you don't define any variables in it, so there is nothing to "scope" in the first place.
Just get rid of it:
def treemin(lst: List[Any]): Int = {
var MaVar: Int = 1000
case (sum,leaf: Int) =>
if(leaf < MaVar) {MaVar = leaf}
}
Now, we get another error:
case (sum,leaf: Int) =>
^
On line 3: error: '}' expected but 'case' found.
Which essentially tells us that a case should go together with a match statement. Since it is not really clear to me what you are trying to match against, I cannot fix the code any further.
This brings us to the second error, which is actually pretty simple:
}
^
On line 6: error: type mismatch;
found : Unit
required: Int
This is pointing to the closing curly brace of your method, and it says essentially that you promised in your method definition that the method returns an Int, but you are actually returning Unit. In fact, you are not explicitly returning anything at all. If you don't explicitly return anything, then the value of the last expression evaluated inside the method is returned.
In this case, it is actually hard to understand what the last expression that is evaluated is going to be, since there is an error in the method, and so the method will never be evaluated at all anyway. But, let's look at the two candidates:
var MaVar: Int = 1000
This is an assignment. Assignments evaluate to Unit, so if this were the last expression evaluated, then the return value would indeed be () which is the singleton instance of Unit.
The other candidate for the last expression evaluated inside the method is the conditional expression:
if(leaf < MaVar) {MaVar = leaf}
Now, what is the value of a conditional expression? Well, it is the value of whatever branch was taken, and the type of the conditional expression is the lowest common ancestor of the types of the two branches.
The "true" branch in your conditional expression is again an assignment, and as we established above, an assignment evaluates to () aka Unit.
The "false" branch in your conditional doesn't exist, but it has to evaluate to something if it is taken, because in Scala, everything is an expression (there are no statements) and thus everything evaluates to a value. Well, the value that represents the absence of a sensible return value is (you guessed it) () aka Unit.
So, however you look at it, your method always returns Unit whereas it actually promises to return an Int. That's why get the type error.
There are a couple of other oddities with your method: It takes an argument, but never uses it. And, the argument is of type List[Any], which is a huge red flag. Scala has a very powerful type system, there is almost never the case that you don't know what specific type something is. Any is the most useless type, since it does not tell you anything about what the type is and what it can do.
Both of the following function definations compile even though one uses = and other doesn't. Why? Is there an advantage of this behaviour?
def 1
def doWork(index:Int) = {
sleep((math.random*1000).toLong);
index;
}
def 2
def doWork(index:Int) {
sleep((math.random*1000).toLong);
index;
}
def 1 is what you want to use.
def 2 is called procedure syntax (discouraged) and actually means this:
def doWork(index:Int): Unit = {
sleep((math.random*1000).toLong)
index
}
So it's probably now what you want (since it doesn't return anything).
Not including an = sign declares a procedure. Procedures return Unit, i.e., don't return a value at all. As explained in the Scala language specification (from the link above):
A procedure definition is a function definition where the result type and the equals sign are omitted; its defining expression must be a block. E.g., def f(ps) {stats} is equivalent to def f(ps): Unit = {stats}.
In your second case, the return value simply gets suppressed to turn a function that returns Int into a procedure that returns Unit. While doing so, the compiler should issue a warning similar to
warning: a pure expression does nothing in a statement position
This should let you know that something fishy is going on, i.e., there is a statement that would normally result in the block returning a value (index; in your case), but it goes unused.
When you don't use "=" with def, it means your defined function will return unit.
And in the second function, you don't use "=", that means the defined function will return unit, but your function is returning index.
That's why it throws warning as it expects unit and discard the value.
Thanks
I'm trying to write a simple function that will swap a (Int, String) tuple in Scala. I've tried a number of things and I keep getting compiler errors, for example:
def swap (p:(Int,String)) : (String,Int) = {
var s = p._1
var t = p._2
var u = (p._2, p.1)
}
[error] found : Unit
[error] required: (String, Int)
[error] }
[error] ^
[error] one error found
Why does it keep saying it finds a "Unit" type? I've tried different variations, and even using the "swap" function built into Scala, but I keep getting these kinds of errors stating that my return type isn't (String, Int). Any suggestions are appreciated. Thank you!
The return value of a method (or more generally, the value of any block) is the value of the last expression inside the block. The last expression in your block is
var u = (p._2, p.1)
The value of an assignment is () (which is the singleton value of the Unit type): an assignment is a side-effect, it doesn't have a value, and () is the value (and Unit the type) which denotes the absence of a value (think "void" if you are familiar with C, C++, D, Objective-C, Objective-C++, Java, or C♯); ergo, your method returns (), which is of type Unit.
Here's a more Scala-ish way to write your method:
def swap[A, B](p: (A, B)) = (p._2, p._1)
All you need is this:
def swap(p: (Int,String)): (String,Int) = (p._2, p._1)
And to make it work on any tuple (of size 2):
def swap[A,B](p: (A,B)): (B,A) = (p._2, p._1)
In Scala, the last expression in a function is the returned value. It also supports an explicit return expression, that would be like this:
def swap(p: (Int,String)): (String,Int) = {
return (p._2, p._1)
}
or more like what you intended:
def swap(p: (Int,String)): (String,Int) = {
val result = (p._2, p._1)
return result
}
Keep in mind this explicit return syntax is not recommended.
Because Scala is a functional language, everything is an expression. Expressions are anything you can evaluate and get back a resulting value, which, being a value, has a type.
Even things that you would think more like "statements", like println("a") or var a = 1 are expressions. When evaluated, they return a meaningless/empty value, that is of type Unit. Therefore, your function returns the last statement, that is a variable assignment, which has a value of type Unit.
You can also achieve it using pattern matching and function literal:
def swap[X,Y]: ((X,Y)) => ((Y,X)) = { case (x, y) => (y, x) }
In the following code, the implicit conversion is applied around the println(2) line; I had foolishly expected it to apply around the entire block { println(1); println(2) }. How should I reason about where the compiler places the implicit?
object Executor {
private var runnable: Runnable = _
def setRunnable(runnable: Runnable) {
this.runnable = runnable
}
def execute() { runnable.run() }
}
object Run extends App {
implicit def blockToRunnable(p: ⇒ Any): Runnable =
new Runnable { def run() = p }
Executor.setRunnable {
println(1)
println(2)
}
println("Before execute")
Executor.execute()
}
I rationalize this behavior like this: according to the spec, the type of a block {s1; s2; ...; sn; e } is the type of the last expression e.
So the compiler takes e and type checks it against Runnable. That fails, so it searches for an implicit conversion that will convert e to Runnable. So it would like this:
{ s1; s2; ... sn; convert(e) }
This is confirmed with scala -Xprint:typer on this small example:
class A
implicit def convert(a: A): String = a.toString
def f(s: String) { println(s) }
f{ println(1); new A }
prints:
private[this] val res0: Unit = $line3.$read.$iw.$iw.f({
scala.this.Predef.println(1);
$line2.$read.$iw.$iw.convert(new $line1.$read.$iw.$iw.A())
});
According to the spec, an implicit conversion is applied when the type of an expression does not match the expected type. The key observation is how the expected type is threaded when typing blocks.
if an expression e is of type T, and T does not conform to the expression’s expected type pt. In this case an implicit v is searched which is applicable to e and whose result type conforms to pt.
In Section 6.11 Blocks, the expected type of a block's last expression is defined as
The expected type of the final expression e is the expected type of the block.
Given this spec, it seems the compiler has to behave this way. The expected type of the block is Runnable, and the expected type of println(2) becomes Runnable as well.
A suggestion: if you want to know what implicits are applied, you can use a nightly build for 2.1 of the Scala IDE for Eclipse. It can 'highlight implicits'.
Edited: I admit it is surprising when there's a call-by-name implicit in scope.
The problem is that you are thinking of blocks as if they were thunks, as if they were pieces of code. They aren't. { a; b; c } is not a piece of code that can be passed around.
So, how should you reason about implicits? Actually, how should you reason about views, which are implicit conversions. Views are applied to the value that needs to be changed. In your example, the value of
{
println(1)
println(2)
}
is being passed to setRunnable. The value of a block is the value of its last expression, so it is passing the result of println(2) to setRunnable. Since that is Unit and setRunnable requires a Runnable, then an implicit is searched for and found, so println(2) is passed to the grossly misnamed blockToRunnable.
Bottom line is, and this is an advice I have given many times already on Stack Overflow (lots of people try to do the same thing) is to get the following in your head:
THERE ARE NO BLOCKS IN SCALA.
There are functions, but not blocks.
Technically, that statement is incorrect -- there are blocks in Scala, but they are not what you think they are, so just completely remove them from your mind. You can learn what blocks in Scala are latter, from a clean slate. Otherwise, you're bound to try to get them to work in ways they don't, or infer that things work in a certain way when they work in a different way.
I liked a lot the explanation given in the first scala puzzle.
In other words, what will be the output of:
List(1, 2).map { i => println("Hi"); i + 1 }
List(1, 2).map { println("Hi"); _ + 1 }
I have been looking at type inference in Scala and there are a couple of things I'd like to understand a bit better around why expression/method-return types have to be explicitly declared in a few cases.
Explicit return declaration
Example (works if return keyword is ommitted):
def upCase(s: String) = {
if (s.length == 0)
return s // COMPILE ERROR - forces return type of upCase to be declared.
else
s.toUpperCase()
}
Why can't I use the explicitly typed parameter as a return value without declaring the return type? And that's not only for direct parameter references, just for any 'type-inferable' expression.
Method overloading
Example (fails to compile when the second joiner method is added):
def joiner(ss: List[String], sep: String) = ss.mkString(sep)
def joiner(ss: List[String]) = joiner(strings, " ") // COMPILE ERROR WHEN ADDED
Well most obvious answer is: because it stated in specification see part 6.20 of scala reference. But why it was designed this way is indeed very intresting question. I suspect it connected to the fact that compiler can't predict that expression will be the last one, since return changes execution flow.
EDIT:
Consider if return doesn't require explicit return type following code:
def bar() = {
if(guard())
return "SS"
else if(gurard1())
return true
2
}
that return type should bar have in this situation? Well there is option with most common supertype, but I think it will get us to returning Any in many cases. Well this is just my thoughts which may be totally incorrect =)
The type of a function or method is inferred from the type of its last statement. Usually, that's an expression.
Now, "return" breaks the control flow. It is an "immediate interrupt", so to speak. Because of that, the normal rules used to infer the type of an expression can't be used anymore. It still could be done, of course, but I'm guessing the cost in compiler complexity was deemed to high for the return.
Here's an example of how the flow is broken:
def toNumber(s: String) = {
if (s == null)
return ""
if (s matches """\d+""")
s.toInt
else
0
}
Normally, the type of the second if statement would be used to infer the type of the whole function. But the return on the first if introduces a second return point from the function, so this rule won't work.
Type inference infers the return type of a method when it can, which is more or less in any case that the method isn't recursive.
Your example would work if you changed it to:
def upCase(s: String) = {
if (s.length == 0)
s // note: no return
else
s.toUpperCase()
}
I don't know offhand why the return changes this.
Disclaimer - this answer was directed to the question as it was originally posted
Scala's type inference already does infer the return type of a method / expression:
scala> def foo(s : String) = s + " Hello"
foo: (String)java.lang.String
scala> var t = foo("World")
t: java.lang.String = World Hello
and:
scala> def bar( s : String) = s.toInt
bar: (String)Int
scala> var i = bar("3")
i: Int = 3
and:
scala> var j = if (System.getProperty("user.name") == "oxbow") 4 else "5".toInt
j: Int = 5
EDIT - I didn't realize that the inclusion of the return keyword meant that the return type of an expression had to be explicitly declared: I've pretty much stopped using return myself - but it's an interesting question. For the joiner example, the return type must be declared because of overloading. Again, I don't know the details as to why and would be interested to find out. I suspect a better-phrased question subject would elicit an answer from the likes of James Iry, Dan Spiewak or Daniel Sobral.
I suspect the method overloading (lack of) inference is related to the similar problem with recursive calls, because if the overloaded methods doesn't call each other, it works perfectly:
def joiner1(ss: List[String], sep: String) = ss.mkString(sep)
def joiner(ss: List[String], sep: String) = ss.mkString(sep)
def joiner(ss: List[String]) = joiner1(ss, " ")
There's two overloaded joiner methods, but the types are inferred correctly the code compiles.