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

末鹿安然 提交于 2019-12-20 11:57:04

问题


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.


回答1:


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




回答2:


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


来源:https://stackoverflow.com/questions/26901963/what-does-to-close-over-the-enclosing-scope-class-mean

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!