Why following code
def doSomething() = "Something"
var availableRetries: Int = 10
def process(): String = {
while (true) {
availableRetries -= 1
try {
return doSomething()
} catch {
case e: Exception => {
if (availableRetries < 0) {
throw e
}
}
}
}
}
produces following compiler error
error: type mismatch;
found : Unit
required: String
while (true) {
^
?
This works ok in C#. The while loops forever, so it cannot terminate, therefore it cannot result something else than string. Or how to make infinite loop in Scala?
Unlike C# (and Java and C and C++) which are statement based languages, Scala is an expression based language. That's mostly a big plus in terms of composibility and readability but in this case the difference has bitten you.
A Scala method implicitly returns the value of the last expression in the method
In Scala pretty much everything is an expression. Things that look like statements are still expressions that return a value of a type called Unit. The value can be written as ().
No compiler for a Turing-equivalent language can detect all non-terminating loops (c.f. Turing halting problem) so most compilers do very little work to detect any. In this case the type of "while(someCondition){...}" is Unit no matter what someCondition is, even if it's the constant true.
Scala determines that the declared return type (String) isn't compatible with the actual return type (Unit), which is the type of the last expression (while...)
Answer: add an exception at the end
Functional way to define an infinite loop is recursion:
elbowich's
retry
function without innerloop
function:The compiler isn't smart enough to know that you can't exit the while loop, unfortunately. It's easy to trick, though, even if you can't sensibly generate a member of the return type--just throw an exception.
Now the compiler will realize that even if it escapes the while loop, it can't return a value there, so it doesn't worry that the while loop has return type
Unit
(i.e. does not return a value).Based on senia, elbowich and dave's solutions I used following:
Which can be then used as elbowich and dave's solutions:
edit: I just noticed the actual return statement. The return statement inside the while loop will be ignored. For example, in the REPL:
You told the compiler that the
process()
method returns aString
, but your method body is just awhile
loop, which doesn't return anything (it's aUnit
, or a Javavoid
). Either change the return type or add a String after the while loop.or