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
scala> def id(x : String) = x
id: (x: String)String
scala> id("hello")
res0: String = hello
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 ().
scala> def foo() = while(false){}
foo: ()Unit
scala> if (foo() == ()) "yes!" else "no"
res2: java.lang.String = yes!
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> def forever() = while(true){}
forever: ()Unit
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...)
scala> def wtf() : String = while(true){}
<console>:5: error: type mismatch;
found : Unit
required: String
def wtf() : String = while(true){}
Answer: add an exception at the end
scala> def wtfOk() : String = {
| while(true){}
| error("seriously, wtf? how did I get here?")
| }
wtfOk: ()String