Reputation: 263088
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 ;)
Upvotes: 1
Views: 179
Reputation: 30453
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
.
Upvotes: 3
Reputation: 42037
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
}
Upvotes: 1
Reputation: 55569
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.
Upvotes: 1
Reputation: 20285
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)
}
Upvotes: 1
Reputation: 179109
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
}
Upvotes: 5