Skip to content

Drop Nonlocal Return #4240

@odersky

Description

@odersky

Nonlocal returns can have surprising behavior due to the way they interact with try. It turns out that with implicit function types one can delegate non-local returns to a library at basically the same efficiency as what is implemented now.

The idea is to express a non-local return like this:

returning {  ....    throwReturn(x)  .... }

The name throwReturn is chosen so that it is made clear that the return is non-local and involves throwing an exception. The exception is caught at the Returning point where the
transmitted result is returned.

Here's an implementation of this functionality:

package scala.util.control

object NonLocalReturns {

  class ReturnThrowable[T] extends ControlThrowable {
    private var myResult: T = _
    def throwReturn(result: T): Nothing = {
      myResult = result
      throw this
    }
    def result: T = myResult
  }

  def throwReturn[T](result: T)(implicit returner: ReturnThrowable[T]): Nothing =
    returner.throwReturn(result)

  def returning[T](op: implicit ReturnThrowable[T] => T): T = {
    val returner = new ReturnThrowable[T]
    try op(returner)
    catch {
      case ex: ReturnThrowable[_] =>
       if (ex `eq` returner) ex.result.asInstanceOf[T] else throw ex
    }
  }

Here's a test case:

def has(xs: List[Int], elem: Int) =
    returning {
      for (x <- xs)
        if (x == elem) throwReturn(true)
      false
    }

Advantages: a simpler language spec and less surprises for the users
Disadvantages: a bit more verbose (which might be a good thing, after all!)

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions