15

The following two code generate different result:

def x = try{
  true
} finally false

invoke x gets true

def y:Boolean = try{
  return true
} finally {
  return false
}

invoke y gets false

the return version behave same as Java.

Personally I never use 'return' in scala. But it's good to know how scala evaluate the value of a try-catch-finally block. Thanks.

xiefei
  • 6,563
  • 2
  • 26
  • 44

2 Answers2

13

You should not have a return statement in a finally block (even though it is technically allowed, at least in Java, C# for example forbids it).

If the Scala finally block had an implicit return, that would always clobber the intended return value. So that makes no sense.

But I suppose it cannot help you if you explicitly write it that way.

Community
  • 1
  • 1
Thilo
  • 257,207
  • 101
  • 511
  • 656
  • But what is "an implicit return" ? – xiefei Dec 09 '11 at 10:03
  • "Implicit return": Maybe the wrong word, but what I meant is that Scala uses the result of the last line in the code block as the return value for the block. – Thilo Dec 09 '11 at 10:09
  • 2
    Thilo is right. Putting a `return` statement in a `finally` block should be considered a mistake, and actually not allowed. `Finally` is to clean up stuff no matter whether the method body succeeds or throws an exception. It's not the place to decide a return value! Therefore, the body of the `finally` clause is taken to evaluate to `Unit`. In your first example, the `false` is implicitly converted to `Unit`. – 0__ Dec 09 '11 at 13:45
  • So the conclusion is: Never use `return` in a `finally` block and in Scala the body of `finally` has no effect on the evaluation of the whole try-catch-finally expression. Sciss make this answer complete. – xiefei Dec 10 '11 at 01:54
10

According to the Scala language spec:

A try expression try { b } finally e evaluates the block b. If evaluation of b does not cause an exception to be thrown, the expression e is evaluated. If an exception is thrown during evaluation of e, the evaluation of the try expression is aborted with the thrown exception. If no exception is thrown during evaluation of e, the result of b is returned as the result of the try expression.

This behaviour would seem to be in contradiction with that spec. I would guess that, since 'return' causes an immediate return from the function, this results in overriding the standard behaviour for a try block. An illuminating example is:

def z : Boolean = {
  val foo = try { true } finally { return false }
  true
}

Invoking z returns false.

Submonoid
  • 2,809
  • 2
  • 20
  • 25
  • 3
    Yes, returning from a finally block breaks flow control. It should be forbidden. – Thilo Dec 09 '11 at 10:08
  • 11
    `return` always breaks flow control. It only gets especially weird in that case. – Debilski Dec 09 '11 at 11:52
  • It's according to the spec. The following paragraph says that the type of `e` is expected to conform to `Unit`, meaning `e` is evaluated only for its side-effects. When `e` is `return ..`, the evaluation rules say that the control flow leaves the currently executed method, returning the given argument. – Iulian Dragos Dec 09 '11 at 16:08