Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What does "to close over the enclosing scope/class" mean?

Tags:

closures

akka

The Akka documentation is documenting dangerous variants of using Props:

// NOT RECOMMENDED within another actor:
// encourages to close over enclosing class
val props7 = Props(new MyActor)

Then carries on stating:

This method is not recommended to be used within another actor because it encourages to close over the enclosing scope, resulting in non-serializable Props and possibly race conditions (breaking the actor encapsulation).

Could someone please explain the meaning of "closing over the enclosing scope"? Been looking all over and found nothing. Thanks.

like image 596
Peter Avatar asked Nov 13 '14 05:11

Peter


2 Answers

It's a bit tricky to see in this example, that the new Actor is passed in as a so called "by name" parameter. Think of it as if it is turned into a function of type () => Actor. This function will be called every time the actor will be (re)created by it's supervisor during a restart.

The problem is that this function is a "closure" (very easy to Google ;)), which means it captures and remembers everything in the surrounding scope that it needs (sometimes, but very rarely referred to as "stack ripping"). E.g val f = (a: Int) => a + x. Where does the x come from? It comes from the surrounding scope. The function litetal, assigned to f is called an "open term". At runtime the function literal becomes a function value (that's a fancy way of saying "object"), which when executed closes the open term, while capturing everything in the surrounding scope. That's where the name "closure" comes from.

Closures are very very useful, but you have to be careful what you close over. Sometimes x is a def or god forbid a var, which leads to unpredictable results for f, because you don't have control over the time when f will be called/executed. Try it out!

Two very common anti paterns in Akka are/were:

  1. Closing over (the outer) this reference when creating an Actor from an inner class.
  2. Closing over def sender when responding to a message with a future.

I gave you a bunch of fancy terms to Google on purpose, btw ;)

Cheers and happy coding

like image 130
agilesteel Avatar answered Nov 13 '22 07:11

agilesteel


As a supplement to @agilesteel's fine answer, some references:

Explains what closures are: Programming in Scala, 8.7, Closures

Explains why closures can cause serialization problems: SIP-21 - Spores

And here is a code example of creating a Props object that is not serializable because of closing over a non-serializable object, based on the example in SIP-21:

case class Helper(name: String)

object MyNonserializableObject {

    val helper = Helper("the helper")

    val props7 = Props(new MyActor(helper))
}

Even though helper itself is serializable, the "new MyActor(helper)" is passed by name and so captures this.helper, and this is not serializable.

You can see that the actor parameter is passed by name from the signature of the Props apply method where there is a ⇒ in the creator parameter:

def apply[T <: Actor](creator: ⇒ T)(implicit arg0: ClassTag[T]): Props
like image 8
Eric Zoerner Avatar answered Nov 13 '22 07:11

Eric Zoerner