foreach in method to return value - scala

def a: Int = {
for(i <- Array(1,2,3,4,5)){
if(i == 3)
return i
}
}
The above method will not compile, I get the following error:
error: type mismatch;
found : Unit
required: Int
for(i <- Array(1,2,3,4,5)){
^
The expected behaviour is that the method returns 3. What is wrong with my code?

That is because your lambda in the foreach does guarantee to return a value. If you provide a default return value it should work.
def a: Int = {
for(i <- Array(1,2,3,4,5)){
if(i == 3)
return i
}
0
}

It's because there is no else or a default return value.
If a method has return type Int, than all paths in that method must return an Int. This is not the case in your implementation. For example, if in the Array there would not be the number 3, nothing would be returned, which means the return type would be Unit.

Don't Use Return in #Scala .
The return keyword is not “optional” or “inferred”; it changes the meaning of your program, and you should never use it.
https://tpolecat.github.io/2014/05/09/return.html

Related

Issues returning a value in Scala inside an if statement

I've got this 'if' condition inside a recursion function :
if (tmpList.size == 14) {
val FBData = Entry (tmpList(0), tmpList(1),tmpList(2),tmpList(3),tmpList(4),tmpList(5).toInt,tmpList(6).toInt,tmpList(7).toInt,tmpList(8).toInt,tmpList(9).toInt,tmpList(10).toInt,tmpList(11).toInt,tmpList(12).toInt,tmpList(13).toInt)
if (index == lines.size - 1) {
List(FBData)
} else {
val Data = pRecurrsioon(lines, index + 1) ++ FBData.toList
}
}
When I runt this through a Scala compiler I get this issue:
31: error: type mismatch;
found : Unit
required: List[HelloWorld.Entry]
}
I don't know why this keeps happening or how to fix it. Apparently im returning an Unsigned integer at some point but I can't see where.
In Scala, the body of the if and the else do return values. The following is also valid (and still has your bug):
val ifResult = if (index == lines.size - 1) {
//this works, and List(FBData) will be assigned to ifResult
List(FBData)
} else {
//this returns Unit as a result of the assignment operation
val Data = pRecurrsioon(lines, index + 1) ++ FBData.toList
}
The compiler tries to assign to ifResult either the body of the if or the else. For this to work, it has to unify the types. This causes the error message you see, while checking the body of the else and trying to get the same type of it as from the if-body:
31: error: type mismatch; found : Unit required: List[HelloWorld.Entry] }

Why Scala return in for-loop give Unit value type?

I have written a for loop to traverse Map, I want this function return key immediately when found some value (both of key and value is Int type)
var hs:Map[Int,Int] = Map(1 -> 1, 2 -> 2)
for ((k,v) <- hs) {
if (v == 1)
return k
}
but, scala give me the error message:
error: type mismatch;
found : Unit
required: Int
for ((k,v) <- hst)
^
one error found
then I change to
var result = 0
for ((k, v) <- hst){
if (v == 1)
result = k
}
result
then, it works well. Why the first version has type issues?
The compile error is explained by #D.Peter, It's lack of a return for this clause.
In Scala, you can use find to do that, like:
hs.find(_._2 == 1).map(_._1).getOrElse(0) // get or return default value.
You forgot to return something if you function never enters in the if statement
def a() : Int = {
var hs:Map[Int,Int] = Map(1 -> 1, 2 -> 2)
for ((k,v) <- hs) {
if (v == 1){
return k
}
}
return -1
}
The accepted answer is not very accurate because it's not about entering if statement, even if you remove if condition it will still not compile.
The problem is the for loop itself. Without yield it simply acts as a construct for side effects. Meaning it returns Unit. Pretty much like foreach semantics.
Read more here.

How do you print an integer value within an object in scala?

object perMissing {
def solution(A: Array[Int]): Int = {
def findMissing(i: Int, L: List[Int]): Int = {
if (L.isEmpty || L.head != i+1) {
i+1
println(i+1)}
else findMissing(i+1, L.tail)
}
if (A.length == 0) 1
else findMissing(0, A.toList.sorted)
}
solution(Array(2,3,1,5))
}
I'm new to the world of Scala. I come from Python and C world.
How do we print an integer value, eg. for debugging? For instance, if I want to see the value of i in every iteration.
I compile my code using scalac and run it using scala.
According to the signature of your findMissing function, it should return an Int. However, if you look at the implementation of that function, only one of the code paths (namely the else part) returns an Int - the if part on the other hand does not return anything (besides Unit), since the call to println is the last line of that particular code block. To fix this issue, just return the increased value by putting it at the end of the block:
def findMissing(i: Int, l: List[Int]): Int = {
val inc = i + 1
if (l.isEmpty || l.head != inc) {
println(inc)
inc
}
else findMissing(inc, l.tail)
}
Since findMissing is tail recursive, you could additionally annotate it with #tailrec to ensure it will be compiled with tail call optimization.

Infinite loop seems to confuse Scala's type system

Here is an artificial toy example that demonstrates my problem:
def sscce(): Int = {
val rand = new Random()
var count = 0
while (true) { // type mismatch; found: Unit, required: Int
count += 1
if (rand.nextInt() == 42) return count
}
}
How can I help the compiler understand that this method will always return an Int?
I know the above toy example could easily be refactored to get rid of the infinite loop altogether, but I really want to have the infinite loop in my actual code. Trust me on this ;)
Always return an Int:
def sscce(): Int = {
val rand = new Random()
var count = 0
while (true) {
count += 1
if (rand.nextInt() == 42) return count
}
count // <-- this
}
You can also do:
def foo: Int = {
...
while(true) {
... return ...
}
throw new IllegalStateException // unreachable
}
this will typecheck because the type of the throw is Nothing, which is a subtype of Int.
See this question. While loops don't return a value. i.e. they return Unit which is the last statement in your function. So, the definition says it returns an Int but it actually returns Unit thus the type error. #ionut's answer fixes the type error by returning count as the last statement or here is a recursive approach.
def sscce(): Int = {
val rand = new Random()
def ssccer(count: Int): Int = {
if(rand.nextInt == 42) return count
else ssccer(count + 1)
}
ssccer(0)
}
Per the SLS, a while loop is executed similarly to:
def whileLoop(cond: => Boolean)(body: => Unit): Unit =
if (cond) { body ; whileLoop(cond)(body) } else {}
ie., it returns Unit. So the compiler sees the while as the last statement in sscce(), and therefore assumes that you're trying to return Unit. I don't think it's smart enough to realize that return count will eventually always return an Int.
The simple solution is to follow the suggestion of #Brian or #IonutGStan, and force it to return count, whether it truly needs it or not.
From a code quality standpoint, it would be good to ditch the while(true) loop and replace it with something more readable. As a nice side effect, it also solves your problem:
def sscce(): Int = {
val rand = new Random()
var count = 1
while (rand.nextInt() != 42) {
count += 1
}
count
}

How to tell the Scala compiler that a while loop will return a value?

Some algorithms execute a while loop with condition true and will (for sure) end at some point with a return statement inside the body of the while loop. E.g.:
def foo: Int = {
while(true) {
// At some time, the while loop will do a return statement inside its body
if( ... )
return 0
}
}
Simple example (without semantic sense):
def foo: Int = {
var i = 0
while(true) {
i += 1
if(i == 10)
return 0
}
}
The Scala compiler complains about a type mismatch, because the while loop has type Unit and the compiler does not know, that the while loop will at some point return a value. We could fix this with a workaround like:
def foo: Int = {
var i = 0
while(true) {
i += 1
if(i == 10)
return 0
}
0 // !
}
But this looks ugly. Is there a better workaround ? Or even a better solution for this kind of problem ?
You could throw an exception:
def foo: Int = {
var i = 0
while(true) {
i += 1
if(i == 10)
return 0
}
throw new IllegalStateException("This should never happen")
}
The compiler will stop complaining about the type mismatch, and since the while loop always returns something, the exception will never be thrown. And if it is, you will quickly find out where you did something wrong :).
There are other ways to write this loop which are more idomatic and Scala-esque, but given the code you provided, this will get the job done in a clear and simple way.
Maybe you should just use tail recursion instead. It should end up compiling down to very similar bytecode:
import scala.annotation.tailrec
def foo: Int = {
#tailrec def bar(i: Int): Int = {
val j = i + 1
if (j == 10) return 0
else bar(j)
}
bar(0)
}
You might even want to make use of the default parameter value support:
#tailrec def foo(i: Int = 0): Int = {
val j = i + 1
if (j == 10) return 0
else foo(j)
}
Note that this way requires you to call the function as foo() not foo since it has an argument.
A more idiomatic way would be to use recursion. Something like this:
def foo: Int = {
import scala.annotation.tailrec
#tailrec def whileUnderTen(i: Int):Int = if ( i < 10) whileUnderTen(i+1) else 0
whileUnderTen(0)
}
For just these occasions, I have a "forever" construct defined in my personal standard library.
forever{
}
is in all ways equivalent to
while(true){
}
except that forever has type Nothing while the equivalent while construct has type Unit. Just one of those small extension capabilities that makes Scala such a joy.