References:
Scala return keyword
handling errors in scala controllers
EDIT3
This is the \"final\" solution, again thanks to Dan Burton.<
Scala internally uses the throw/catch mechanism to handle returns in places where returns are syntactically okay but it actually has to jump out of several methods. So you can either let it do this:
def save = Action { implicit request =>
def result(): Foo = {
/* All your logic goes in here, including returns */
}
result()
}
or, if you prefer, you can use your own data-passing throwable class (without stack trace):
import scala.util.control.ControlThrowable
case class Return[A](val value: A) extends ControlThrowable {}
def save = Action { implicit request =>
try {
/* Logic */
if (exitEarly) throw Return(Ok(blahBlah))
/* More logic */
}
catch {
case Return(x: Foo) => x
}
}
Or you could get a little fancier and add your own exception handling:
case class Return[A](val value: A) extends ControlThrowable {}
class ReturnFactory[A]{ def apply(a: A) = throw new Return(a) }
def returning[A: ClassManifest](f: ReturnFactory[A] => A) = {
try { f(new ReturnFactory[A]) } catch {
case r: Return[_] =>
if (implicitly[ClassManifest[A]].erasure.isAssignableFrom(r.value.getClass)) {
r.value.asInstanceOf[A]
} else {
throw new IllegalArgumentException("Wrong Return type")
}
}
}
(If you want to be able to nest the returnings, just rethrow the Return instead of throwing an IllegalArgumentException when the type doesn't match.) You can use this like so:
def bar(i: Int) = returning[String] { ret =>
if (i<0) ret("fish")
val j = i*4
if (j>=20) ret("dish")
"wish"*j
}
bar(-3) // "fish"
bar(2) // "wishwishwishwishwishwishwishwish"
bar(5) // "dish"
or in your particular case
def save = Action{ implicit request => returning[Foo] { ret =>
/* Logic goes here, using ret(foo) as needed */
}}
It's not built in, but it shouldn't be terribly hard to explain to people how to use this even if it's not so easy to understand how the capability is built. (Note: Scala does have built in break capability in scala.util.control.Breaks which uses something very much like this strategy.)