Return in Scala

It's not as simple as just omitting the return keyword. In Scala, if there is no return then the last expression is taken to be the return value. So, if the last expression is what you want to return, then you can omit the return keyword. But if what you want to return is not the last expression, then Scala will not know that you wanted to return it.

An example:

def f() = {
  if (something)
    "A"
  else
    "B"
}

Here the last expression of the function f is an if/else expression that evaluates to a String. Since there is no explicit return marked, Scala will infer that you wanted to return the result of this if/else expression: a String.

Now, if we add something after the if/else expression:

def f() = {
  if (something)
    "A"
  else
    "B"

  if (somethingElse)
    1
  else
    2
}

Now the last expression is an if/else expression that evaluates to an Int. So the return type of f will be Int. If we really wanted it to return the String, then we're in trouble because Scala has no idea that that's what we intended. Thus, we have to fix it by either storing the String to a variable and returning it after the second if/else expression, or by changing the order so that the String part happens last.

Finally, we can avoid the return keyword even with a nested if-else expression like yours:

def f() = {
  if(somethingFirst) {
    if (something)      // Last expression of `if` returns a String
     "A"
    else
     "B"
  }
  else {
    if (somethingElse)
      1
    else
      2

    "C"                // Last expression of `else` returns a String
  }

}


This topic is actually a little more complicated as described in the answers so far. This blogpost by Rob Norris explains it in more detail and gives examples on when using return will actually break your code (or at least have non-obvious effects).

At this point let me just quote the essence of the post. The most important statement is right in the beginning. Print this as a poster and put it to your wall :-)

The return keyword is not “optional” or “inferred”; it changes the meaning of your program, and you should never use it.

It gives one example, where it actually breaks something, when you inline a function

// Inline add and addR
def sum(ns: Int*): Int = ns.foldLeft(0)((n, m) => n + m) // inlined add

scala> sum(33, 42, 99)
res2: Int = 174 // alright

def sumR(ns: Int*): Int = ns.foldLeft(0)((n, m) => return n + m) // inlined addR

scala> sumR(33, 42, 99)
res3: Int = 33 // um.

because

A return expression, when evaluated, abandons the current computation and returns to the caller of the method in which return appears.

This is only one of the examples given in the linked post and it's the easiest to understand. There're more and I highly encourage you, to go there, read and understand.

When you come from imperative languages like Java, this might seem odd at first, but once you get used to this style it will make sense. Let me close with another quote:

If you find yourself in a situation where you think you want to return early, you need to re-think the way you have defined your computation.

Tags:

Return

Scala