Scala while(true) type mismatch? Infinite loop in scala?

TN. picture TN. · May 29, 2012 · Viewed 11k times · Source

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?

Answer

James Iry picture James Iry · May 29, 2012

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