7
votes

Background

i want to send a closure to a remote actor. remote actor should run the closure on its data and send back the result. May be it is not advisable, but for curiosity's sake that's i want to do now

But i observe that if a closure is created as an anonymous function, it captures the outer object also and tries to marshal it, which fails if the outer object is not serializable, as in this case.

class Client(server: ActorRef) extends Actor {

  var every = 2

  override def preStart() = {
    println("client started. sending message....")
    server ! new Message((x) => x % every == 0)
  }

}

the above code generates exception while calling the remote actor. i could define a local variable in the method preStart()

val every_ = every

and use it in place of actor member variable. But i feel it is a workaround not a solution. and i will have to be very careful if the closure is any bit more complex.

Alternative is to define a class inheriting from Function1[A,B] and send its instances as closure.

class MyFunc(every : Int) extends Function1[Int,Boolean] with Serializable {

  def apply(v1 :Int) : Boolean = {
    v1 % every == 0
  }  
}


server ! new Message(new MyFunc(every))

But this separates the closure definition from the place it is used, and defeats the whole purpose of using a functional language. and also makes defining the closure logic more difficult.

Specific Query

Is there a way i can defer defining the body of the Function1.apply and assign the body of apply when i create the instance of MyFunc from a locally defined closure?

e.g.

server ! new Message(new MyFunc(every){ // not valid scala code
  x % every == 0
})

where every is a local variable?

basically i want to combine the two approaches i.e. send an object of Function1 over to remote actor with the body of Function1 defined by an anon function defined in place where Function1 instance is created.

Thanks,

1
I guess you know what you are doing but I want to make sure you are aware that sending closures is considered a bad practice as clearly explained in the documentation - paragraph Actor Best Practices alinea 3Bruno Grieder
thanks for pointing it out. alternatively can i encapsulate that behavior in an actor and create it dynamically? i.e. dictate the behavior of the actor based on the closure rather than sending closure itself over to the actor.weima
There is a lot you can do but I have a feeling you are trying to implement the "wrong"/awkward solution to a specific problem. I believe if you edit your question and describe what you are trying to achieve, you will get better responses on SOBruno Grieder
OK. i rephrase the question to the specific query. How to define the body of Funtion1[A,B] 's apply() method dynamically? like how we define anonymous class methods in Java when instantiating an interfaceweima
Thanks i just checked it is indeed possible to define the body of Function1 at the time of creation. Thx :)weima

1 Answers

4
votes

Sure, you could send behaviour to actor, but it considered to be a bad practice, and your questions is a good answer on question: "why".

As BGR pointed out there is special section in documentation on this question, but it has no example.

So, when you sending a closure as message you sending some extra "implicit" state with it. It could be not mutable as said in documentation, but even in this case it can create problems.

The problem with scala here is that it not strictly functional language - it is multiparadigm language. In other words you could have code in functional paradigm side by side with code in imperative style. There is no such problems in, for example haskell, which is purely functional.

In case of your "specific query" I'll suggest you to use set of predefined functions. This is full equivalent of variant with closures but with a bit chatty syntax. Since you do not generate code during runtime all functions you use are defined in limited set and (looks like) parameterized by value. This makes your code not so flexible like with closures, but in the end it will be equivalent cases.

So, as a leitmotif of all my post: if you going to send behaviour to actor it should be rock solid atomic (in meaning have no any dependencies)