Ryan Leach
Ryan Leach

Reputation: 4470

Does Scala have an equivalent to golangs defer?

Does Scala have an equivelent to golangs defer?

from: http://golang.org/doc/effective_go.html#defer

Go's defer statement schedules a function call (the deferred function) to be run immediately before the function executing the defer returns. It's an unusual but effective way to deal with situations such as resources that must be released regardless of which path a function takes to return. The canonical examples are unlocking a mutex or closing a file.

Upvotes: 9

Views: 2500

Answers (3)

itsbruce
itsbruce

Reputation: 4843

No. Go has this construct precisely because it doesn't support exceptions and has no try...finally syntax.

Personally, I think it invites a maintenance nightmare; calls to defer can be buried anywhere in a function. Even where responsible coders put the defers right beside the thing to be cleaned up, I think it's less clear than a finally block and as for what it lets the messy coders do... at least finally blocks put all the clean-up in one place.

defer is the opposite of idiomatic Scala. Scala offers monadic ways to control program flow and defer magic does not contribute at all. Monads offer a functional improvement over try...finally which let you

  • Define your own error handling flow
  • Manipulate defined flows functionally
  • Make a function's anticipated errors part of its signature

defer has no place in this.

Upvotes: 2

nemo
nemo

Reputation: 57757

Scala does not offer defer by design, however you can create it yourself by wrapping your function in another function, passing an object which keeps track of functions to call.

Example:

class DeferTracker() {
  class LazyVal[A](val value:() => A)

  private var l = List[LazyVal[Any]]()
  def apply(f: => Any) = { l = new LazyVal(() => f) :: l }
  def makeCalls() = l.foreach { x => x.value() }
}

def Deferrable[A](context: DeferTracker => A) = {
  val dt = new DeferTracker()
  val res = context(dt)
  dt.makeCalls
  res
}

In this example, Deferable would be the wrapping function which calls context and returns it contents, giving it an object which tracks defer calls.

You can use this construct like this:

def dtest(x:Int) = println("dtest: " + x)

def someFunction(x:Int):Int = Deferrable { defer =>
  defer(dtest(x))
  println("before return")
  defer(dtest(2*x))

  x * 3
}

println(someFunction(3))

The output would be:

before return
dtest: 6
dtest: 3
3

I'm aware that this can be solved differently but it is really just an example that Scala supports the concept of defer without too much fuss.

Upvotes: 9

fresskoma
fresskoma

Reputation: 25791

I can't think of a Scala specific way, but wouldn't this be equivalent (though not as pretty):

try {
    // Do stuff   
} finally {
    // "defer"
}

Upvotes: 6

Related Questions