Type inference on method return type

Why does Scala fail to infer the return type of the method when there's an explicit return statement used in the method?

For instance, why does the following code compile?

object Main {
    def who = 5
    def main(args: Array[String]) = println(who)
}

But the following doesn't.

object Main {
    def who = return 5
    def main(args: Array[String]) = println(who)
}

The return type of a method is either the type of the last statement in the block that defines it, or the type of the expression that defines it, in the absence of a block.

When you use return inside a method, you introduce another statement from which the method may return. That means Scala can't determine the type of that return at the point it is found. Instead, it must proceed until the end of the method, then combine all exit points to infer their types, and then go back to each of these exit points and assign their types.

To do so would increase the complexity of the compiler and slow it down, for the sole gain of not having to specify return type when using return. In the present system, on the other hand, inferring return type comes for free from the limited type inference Scala already uses.

So, in the end, in the balance between compiler complexity and the gains to be had, the latter was deemed to be not worth the former.


It would increase the complexity of the compiler (and language). It's just really funky to be doing type inference on something like that. As with anything type inference related, it all works better when you have a single expression. Scattered return statements effectively create a lot of implicit branching that gets to be very sticky to unify. It's not that it's particularly hard, just sticky. For example:

def foo(xs: List[Int]) = xs map { i => return i; i }

What, I ask you, does the compiler infer here? If the compiler were doing inference with explicit return statements, it would need to be Any. In fact, a lot of methods with explicit return statements would end up returning Any, even if you don't get sneaky with non-local returns. Like I said, sticky.

And on top of that, this isn't a language feature that should be encouraged. Explicit returns do not improve code clarity unless there is just one explicit return and that at the end of the function. The reason is pretty easy to see if you view code paths as a directed graph. As I said earlier, scattered returns produce a lot of implicit branching that produces weird leaves on your graph, as well as a lot of extra paths in the main body. It's just funky. Control flow is much easier to see if your branches are all explicit (pattern matching or if expressions) and your code will be much more functional if you don't rely on side-effecting return statements to produce values.

So, like several other "discouraged" features in Scala (e.g. asInstanceOf rather than as), the designers of the language made a deliberate choice to make things less pleasant. This combined with the complexity that it introduces into type inference and the practical uselessness of the results in all but the most contrived of scenarios. It just doesn't make any sense for scalac to attempt this sort of inference.

Moral of the story: learn not to scatter your returns! That's good advice in any language, not just Scala.


Given this (2.8.Beta1):

object Main {
  def who = return 5
  def main(args: Array[String]) = println(who)
}
<console>:5: error: method who has return statement; needs result type
         def who = return 5

...it seems not inadvertent.