Scala type mismatch in if statement - scala

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.

Related

How to handle tail recursion with futures

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.)

Why does the absence of an else block translate to Unit type return for a function?

I noticed there is a type mismatch caused in the line else if(r1 == 0 || divisors.tail.isEmpty || !divisors.tail.contains(r1)){newAcc}. Because there is no else clause to my if ... else if ...
def euclidianDivision(dividend:Int,divisor:Int):(Int,Int)={
val quotient = dividend/divisor
val remainder = dividend%divisor
(quotient,remainder)
}
def firstExpansion(dividend:Int,divisors:List[Int]):List[(Int,Int)]={
def firstExpansionIter(dividend:Int,divisors:List[Int], acc:List[(Int,Int)]):List[(Int,Int)]= {
val div1:Int = divisors.head
val (q1,r1):(Int,Int) = euclidianDivision(dividend,div1)
val newAcc:List[(Int,Int)] = acc:::List((div1,q1))
if (divisors.tail.contains(r1)){
firstExpansionIter(r1,divisors.tail,newAcc)
}else if(r1 == 0 || divisors.tail.isEmpty || !divisors.tail.contains(r1)){newAcc}
}
firstExpansionIter(dividend,divisors,List((0,0))).tail
}
Here's the error code:
Error:(32, 15) type mismatch; found : Unit required: List[(Int,
Int)]
}else if(r1 == 0 || divisors.tail.isEmpty || !divisors.tail.contains(r1)){newAcc}
I can correct this by adding the else clause, but how come if there is no outcome handled by default, the function tries to return a Unit?
N.B : Corrected code :
def firstExpansion(dividend:Int,divisors:List[Int]):List[(Int,Int)]={
def firstExpansionIter(dividend:Int,divisors:List[Int], acc:List[(Int,Int)]):List[(Int,Int)]= {
val div1:Int = divisors.head
val (q1,r1):(Int,Int) = euclidianDivision(dividend,div1)
val newAcc:List[(Int,Int)] = acc:::List((div1,q1))
if (divisors.tail.contains(r1)){
firstExpansionIter(r1,divisors.tail,newAcc)
}else if(r1 == 0 || divisors.tail.isEmpty || !divisors.tail.contains(r1)){newAcc}
else throw new RuntimeException("Something unexpected happened.")
}
firstExpansionIter(dividend,divisors,List((0,0))).tail
}
I can correct this by adding the else clause, but how come if there is no outcome handled by default, the function tries to return a Unit?
In Scala, unlike more "imperative" languages, (almost) everything is an expression (there are very few statements), and every expression evaluates to a value (which also means that every method returns a value).
This means that, for example, the conditional expression if (condition) consequence else differentConsequence is an expression that evaluates to a value.
For example, in this piece of code:
val foo = if (someRandomCondition) 42 else "Hello"
the then part of the expression will evaluate to 42, the else part of the expression will evaluate to "Hello", which means the if expression as a whole will evaluate to either 42 or "Hello".
So, what is the type of foo going to be? Well, in the then case, the value is of type Int and in the else case, the value is of type String. But, this depends on the runtime value of someRandomCondition, which is unknown at compile time. So, the only choice we have as the type for the whole if expression is the lowest common ancestor (technically, the weak least upper bound) of Int and String, which is Any.
In a language with union types, we could give it a more precise type, namely the union type Int | String. (Scala 3 has union types, so we could give the expression this exact type, although Scala 3 will not infer union types.) In Scala 3, we could even annotate it with the even more precise type 42 | "Hello", which is actually the type that TypeScript is going to infer for the equivalent conditional expression:
const foo = someRandomCondition ? 42 : "Hello"
Now, let's move forward towards the code in the question:
val bar = if (someRandomCondition) 42
What is the type of bar going to be? We said above that it is the lowest common ancestor of the types of the then and else branch, but … what is the type of the else branch? What does the else branch evaluate to?
Remember, we said that every expression evaluates to a value, so the else branch must evaluate to some value. It can't just evaluate to "nothing".
This is solved by a so-called unit value of a unit type. The unit value and type are called the "unit" value and type, because the type is designed in such a way that it can only possibly be inhabited by a single value. The unit type has no members, no properties, no fields, no semantics, no nothing. As such, it is impossible to distinguish two values of the unit type from one another, or put another way: there can only be one value of the unit type, because very other value of the unit type must be identical.
In many programming languages, the unit value and type use the same notation as a tuple value and type, and are simply identified with the empty tuple (). An empty tuple and a unit value are the same thing: they have no content, no meaning. In Haskell, for example, both the type and the value are written ().
Scala also has a unit value, and it is also written (). The unit type, however, is scala.Unit.
So, the unit value, which is a useless value, is used to signify a meaningless return value.
A related, but different concept in some imperative languages is the void type (or in some languages, it is more a "pseudo-type").
Note that "returns nothing" is different from "doesn't return", which will become important in the second part of this answer.
So the first half of the puzzle is: the Scala Language Specification says that
if (condition) expression
is equivalent to
if (condition) expression else ()
Which means that in the (implicit) else case, the return type is Unit, which is not compatible with List[(Int, Int)], and therefore, you get a type error.
But why does throwing an exception fix this?
This brings us to the second special type: Nothing. Nothing is a so-called bottom type, which means that it is a subtype of every type. Nothing does not have any value. So, what then, would a return type of Nothing signify?
It signifies an expression that doesn't return. And I repeat what I said above: this is different from returning nothing.
A method that has only a side-effect returns nothing, but it does return. Its return type is Unit and its return value is (). It doesn't have a meaningful return value.
A method that has an infinite loop or throws an exception doesn't return at all. Its return type is Nothing and it doesn't have a return value.
And that is why throwing an exception in the else clause fixes the problem: this means that the type of the else clause is Nothing, and since Nothing is a subtype of every type, it doesn't even matter what the type of the then clause is, the lowest common supertype of the type of the then clause and Nothing will always be the type of the then clause. (Think about it: the lowest common ancestor of a father and any of his children, grandchildren, great-grandchildren, etc. will always be the father himself. The lowest common ancestor of T and any subtype of T will always be T. Since Nothing is a subtype of all types, the lowest common ancestor of T and Nothing will always be T because Nothing is always a subtype of T, no matter what T is.)

why = is optional in def in Scala

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

Swapping tuples of different types in Scala

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) }

Simple Type Inference in Scala

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.