Thursday, 7 June 2012

Scala: return from closures


"Funny" code


Functions are first class citizens in Scala. JVM, that doesn't know anything on Functions. All the magic is coming from the Scala Library and compiler. Sometimes we should know about "workarounds" were applied to support rich language features.
Lets look into the example:
class TestClass {
def func(inFunc: => Unit) {
println("Before")
try { inFunc }
catch { case _ => }
println("After")
}
}
view raw TestClass.scala hosted with ❤ by GitHub
Code is ugly, it is, - but the evil is hidden deeper :)
object Program {
def main(args: Array[String]) {
val obj = new TestClass
obj func { println("inside") }
}
}
view raw Program.scala hosted with ❤ by GitHub
It's clear that code prints to output expected flow:
    Before
    inside
    After
Sweat, still code smells, but works as expected. And last one example:
object Program {
def main(args: Array[String]) {
val obj = new TestClass
obj func { println("inside"); return }
}
}
view raw Program.scala hosted with ❤ by GitHub
Produces output:
    Before
    inside
    After
After should not be here!

Return form closures rule


Return from closures must force return from the method that declared (wraps) closure. This part is really hard to get for Java dudes, that is why please look into example that makes it clean:
def isGreate0(list:List[Int]):Boolean = {
for (i <- list)
if (i <= 0)
return false
true
}
view raw isGreater.scala hosted with ❤ by GitHub
If return didn't return from method but only from closure - method would always return false!

Implemented via Exception


The only one way to stop a stack execution from any point is throwing an exception. As U already got try-catch construction eats an return Exception ( scala.util.control.ControlThrowable):

    trait ControlThrowable extends Throwable with NoStackTrace

Of corse we should never use:

    try {...} catch {case _ => }

Unfortunately it's equals to catch (Throwable e) in Java and will catch ControlThrowable((. _ is supporting compatibility with pattern matching, but Java error handling practices. 

Enjoy the hacking Scala :p

1 comment:

  1. But why it would return false? Shouldn't it be true if we just return from loop body and not from isGreate0 method?

    > If return didn't return from method but only from closure - method would always return false!

    ReplyDelete