Re: [akka-user] Re: How can I reconcile untyped actors with typeful programming?

2014-03-09 Thread Endre Varga
Hi Daniel,

The issue is that type systems are designed for local and not distributed
computations. Let's look at an example.

Imagine an actor that has three states, A, B and C

In state A it accepts messages of type X, and when received one, it
transitions to B
In state B it accepts messages of type X and Y. When X is received,
transitions to C, if Y, then stays in B
In state C it accepts messages of type Z

Now you send to an actor starting from state A a message X. Two things can
happen:
 - X is delivered, so the possible accepted types are {X, Y}
 - X is lost, so the accepted type is {X}
The intersection of those is {X}.

Now imagine that you send another message X. Three things can happen:
 - both X's were delivered, so the accepted type is {Z}
 - only one of the X's were delivered, the other is lost, so the accepted
types are {X, Y}
 - both X's were lost, the accepted type is {X}
The intersection of the above cases is the empty set.

So what should be the local type representation of an actor that you have
sent two messages of type X?

Let's modify the example, and assume that there was no message loss, but
let's take the viewpoint of another sender. This sender knows that two X's
were sent to our example actor by the other sender. What messages can we
send? There are three scenarios:
 - both X's sent by the other sender has arrived already, so the accepted
type is {Z}
 - only the first X sent by the other sender has arrived yet, so the
accepted types are {X, Y}
 - no X's has arrived yet, accepted type is {X}
The intersection of the above cases is the empty set.

As you see, without receiving a reply from an actor, the provable type of
an actor is usually Nothing, or something useless. Only replies can convey
the *possible* type of an actor, and even that cannot be guaranteed if
there are concurrent senders.

-Endre


On Sat, Mar 8, 2014 at 8:08 PM, Daniel Armak danar...@gmail.com wrote:

 My intent was definitely to throw away type safety. In my example you can
 wrap any ActorRef using any trait, and you can extract and use the raw
 ActorRef from a typed wrapper. The only thing I was trying to salvage was
 for the sender to declare what kind of actor / behavior they thought they
 were dealing with.

 But I'm taking your advice to heart. I'll try to use pure actors until I
 have more of a sense of how problematic various issues are.

 Thanks!

 Daniel Armak


 On Sat, Mar 8, 2014 at 8:59 PM, Derek Wyatt de...@derekwyatt.org wrote:

 On 8 March 2014 13:31, Daniel Armak danar...@gmail.com wrote:

 Hi Derek.

 Yes, I'm aware of the tradeoffs and the reasons for them. It just seems
 to me there ought to be a middle road.

 Here's an idea off the top of my head. If remoting is going to be
 transparent, there won't be compile time type assurance. So let's give up
 on local type assurance too, and just use types for documentation and
 refactoring; that still seems a lot better than nothing.

 Suppose for each actor I wanted to implement, I declare a trait with a
 method for each message it might receive. Each method must receive exactly
 one parameter, which is the message, and return Unit:

 trait Printer {
   def print(msg: String): Unit
 }

 The method name 'print' is just for documentation; only the parameter is
 sent as the message. This preserves transparency with the actor model; you
 don't rely on the trait implementation to build the actual message.

 The user of an ActorRef would use a wrapper (value type around the
 ActorRef) generated by a macro to implement this trait. The macro would
 also validate the trait: each method has one argument, returns Unit, and
 all argument types are distinct. Each method call would be implemented as a
 send().

 val actor : ActorRef = ???
 val typedActor: Printer = mymacro.wrap[Printer](actor) // Or is there a
 way to declare types with macros? I forget.
 typedActor.print(my message)

 The macro would add an (implicit sender: ActorRef) argument to each
 method.

 The actor itself would extend the Printer trait and implement its
 methods. Another macro would concatenate them to implement receive:

 class PrinterActor extends Actor with Printer with
 TypedActorMacro[Printer] {
   def print(msg: String):
 }

 To use become/unbecome, we could introduce something more complicated.
 Or, even, use the Printer trait only on the sender side - it would still be
 useful. This is just a rough outline. Do you think it might be useful, or
 do you think I shouldn't go down this road and trying to marry akka actors
 and (actor) types is a futile endeavour?


 Not futile, but highly suspect.  You've barely scratched the surface with
 the above and much research is way ahead of you here.

 The ??? you have above isn't exactly trivial to implement, for example.
 What's more is that you've probably thrown away a ton more features in the
 process.  e.g.:

 class MyActor(printActor: PrinterActor) { ... }

 // later...

 val myActor =
   

Re: [akka-user] Re: How can I reconcile untyped actors with typeful programming?

2014-03-09 Thread OlegYch
Derek, the loadbalancer can remain an Actor[Any] and we can safely wrap 
Actor[T] with Actor[Any] and cast the reference back to Actor[T] if we 
trust that untyped actor.
That doesn't mean forfeiting type safety in all other cases is way to go.
One thing that is more difficult to handle (both using types or 
documentation) is the fact that we 're not really sure what a reply to a 
particular message will be or even how much or replies there will be.
I would welcome any advances in this area, be it typed channels or 
something else. 
At the moment i don't feel comfortable with the current situation, e.g. 
even with a simplistic application i wrote a couple of months ago there is 
a lot of time even for myself required to understand wtf is going, who 
sends what/when and where.
Another example of frustration i've recently had was with IO api, as even 
the docs are not enough to understand the flow of messages.

Thanks, Aleh

On Saturday, March 8, 2014 9:59:31 PM UTC+3, Derek Wyatt wrote:

 On 8 March 2014 13:31, Daniel Armak dana...@gmail.com javascript:wrote:

 Hi Derek.

 Yes, I'm aware of the tradeoffs and the reasons for them. It just seems 
 to me there ought to be a middle road.

 Here's an idea off the top of my head. If remoting is going to be 
 transparent, there won't be compile time type assurance. So let's give up 
 on local type assurance too, and just use types for documentation and 
 refactoring; that still seems a lot better than nothing.

 Suppose for each actor I wanted to implement, I declare a trait with a 
 method for each message it might receive. Each method must receive exactly 
 one parameter, which is the message, and return Unit:

 trait Printer {
   def print(msg: String): Unit
 }

 The method name 'print' is just for documentation; only the parameter is 
 sent as the message. This preserves transparency with the actor model; you 
 don't rely on the trait implementation to build the actual message.

 The user of an ActorRef would use a wrapper (value type around the 
 ActorRef) generated by a macro to implement this trait. The macro would 
 also validate the trait: each method has one argument, returns Unit, and 
 all argument types are distinct. Each method call would be implemented as a 
 send().

 val actor : ActorRef = ???
 val typedActor: Printer = mymacro.wrap[Printer](actor) // Or is there a 
 way to declare types with macros? I forget.
 typedActor.print(my message)

 The macro would add an (implicit sender: ActorRef) argument to each 
 method.

 The actor itself would extend the Printer trait and implement its 
 methods. Another macro would concatenate them to implement receive:

 class PrinterActor extends Actor with Printer with 
 TypedActorMacro[Printer] {
   def print(msg: String): 
 }

 To use become/unbecome, we could introduce something more complicated. 
 Or, even, use the Printer trait only on the sender side - it would still be 
 useful. This is just a rough outline. Do you think it might be useful, or 
 do you think I shouldn't go down this road and trying to marry akka actors 
 and (actor) types is a futile endeavour?


 Not futile, but highly suspect.  You've barely scratched the surface with 
 the above and much research is way ahead of you here.

 The ??? you have above isn't exactly trivial to implement, for example. 
 What's more is that you've probably thrown away a ton more features in the 
 process.  e.g.:

 class MyActor(printActor: PrinterActor) { ... }

 // later...

 val myActor = 
   MyActor.props(loadBalancer(printerActor.props()))
 // oops. Does the loadBalancer now have to
 // implement Printer?  What if it's a load
 // balancer in front of scatter gather routers
 // that talk to forwarders that talk to various
 // different versions of Printers?  Does everyone
 // have to implement the same API?  If not, how
 // are you not throwing away type safety?  And, if so
 // how am I doing anything but writing annoying code
 // that keeps me a slave to the API?  And how do I
 // easily manage API changes, and so on, and so forth?

 Maybe not theoretically futile, but practically?  Probably :)

 To be perfectly honest, it seems as though you're trying to fix a 
 problem without having travelled a mile in its shoes yet.  There are 
 subsets of the problem that are much more important and more possible to 
 cage, and you will see them as you progress.  When you do, focusing on 
 those (should you still believe them to be worth it) might be the far 
 better option.
  


 Thanks!

 On Sat, Mar 8, 2014 at 7:51 PM, Derek Wyatt 
 de...@derekwyatt.orgjavascript:
  wrote:

 What you're experiencing is a trade-off.  Actors provide a trade-off 
 that you don't seem to be taking into account; endpoints (Actors) are 
 untyped and the messages that they handle are strongly typed.

 You can't have an Actor be able to process anything with a 
 type-specific receive method.  With Actor programming, I should be able to 
 add as many intermediaries in the message flow as 

Re: [akka-user] Re: How can I reconcile untyped actors with typeful programming?

2014-03-09 Thread OlegYch
Endre, i don't think this is related to distributed computations  at all.
Any method call can fail even locally. The way to represent that is with 
sum types e.g. Either.

Thanks, Aleh

On Sunday, March 9, 2014 8:42:11 PM UTC+3, drewhk wrote:

 Hi Daniel,

 The issue is that type systems are designed for local and not distributed 
 computations. Let's look at an example.

 Imagine an actor that has three states, A, B and C

 In state A it accepts messages of type X, and when received one, it 
 transitions to B
 In state B it accepts messages of type X and Y. When X is received, 
 transitions to C, if Y, then stays in B
 In state C it accepts messages of type Z

 Now you send to an actor starting from state A a message X. Two things can 
 happen:
  - X is delivered, so the possible accepted types are {X, Y}
  - X is lost, so the accepted type is {X}
 The intersection of those is {X}.

 Now imagine that you send another message X. Three things can happen:
  - both X's were delivered, so the accepted type is {Z}
  - only one of the X's were delivered, the other is lost, so the accepted 
 types are {X, Y}
  - both X's were lost, the accepted type is {X}
 The intersection of the above cases is the empty set.

 So what should be the local type representation of an actor that you have 
 sent two messages of type X?

 Let's modify the example, and assume that there was no message loss, but 
 let's take the viewpoint of another sender. This sender knows that two X's 
 were sent to our example actor by the other sender. What messages can we 
 send? There are three scenarios:
  - both X's sent by the other sender has arrived already, so the accepted 
 type is {Z}
  - only the first X sent by the other sender has arrived yet, so the 
 accepted types are {X, Y}
  - no X's has arrived yet, accepted type is {X}
 The intersection of the above cases is the empty set.

 As you see, without receiving a reply from an actor, the provable type of 
 an actor is usually Nothing, or something useless. Only replies can convey 
 the *possible* type of an actor, and even that cannot be guaranteed if 
 there are concurrent senders.

 -Endre


 On Sat, Mar 8, 2014 at 8:08 PM, Daniel Armak dana...@gmail.comjavascript:
  wrote:

 My intent was definitely to throw away type safety. In my example you can 
 wrap any ActorRef using any trait, and you can extract and use the raw 
 ActorRef from a typed wrapper. The only thing I was trying to salvage was 
 for the sender to declare what kind of actor / behavior they thought they 
 were dealing with. 

 But I'm taking your advice to heart. I'll try to use pure actors until I 
 have more of a sense of how problematic various issues are.

 Thanks!

 Daniel Armak


 On Sat, Mar 8, 2014 at 8:59 PM, Derek Wyatt 
 de...@derekwyatt.orgjavascript:
  wrote:

 On 8 March 2014 13:31, Daniel Armak dana...@gmail.com javascript:wrote:

 Hi Derek.

 Yes, I'm aware of the tradeoffs and the reasons for them. It just seems 
 to me there ought to be a middle road.

 Here's an idea off the top of my head. If remoting is going to be 
 transparent, there won't be compile time type assurance. So let's give up 
 on local type assurance too, and just use types for documentation and 
 refactoring; that still seems a lot better than nothing.

 Suppose for each actor I wanted to implement, I declare a trait with a 
 method for each message it might receive. Each method must receive exactly 
 one parameter, which is the message, and return Unit:

 trait Printer {
   def print(msg: String): Unit
 }

 The method name 'print' is just for documentation; only the parameter 
 is sent as the message. This preserves transparency with the actor model; 
 you don't rely on the trait implementation to build the actual message.

 The user of an ActorRef would use a wrapper (value type around the 
 ActorRef) generated by a macro to implement this trait. The macro would 
 also validate the trait: each method has one argument, returns Unit, and 
 all argument types are distinct. Each method call would be implemented as 
 a 
 send().

 val actor : ActorRef = ???
 val typedActor: Printer = mymacro.wrap[Printer](actor) // Or is there a 
 way to declare types with macros? I forget.
 typedActor.print(my message)

 The macro would add an (implicit sender: ActorRef) argument to each 
 method.

 The actor itself would extend the Printer trait and implement its 
 methods. Another macro would concatenate them to implement receive:

 class PrinterActor extends Actor with Printer with 
 TypedActorMacro[Printer] {
   def print(msg: String): 
 }

 To use become/unbecome, we could introduce something more complicated. 
 Or, even, use the Printer trait only on the sender side - it would still 
 be 
 useful. This is just a rough outline. Do you think it might be useful, or 
 do you think I shouldn't go down this road and trying to marry akka actors 
 and (actor) types is a futile endeavour?


 Not futile, but highly suspect.  You've barely scratched the 

Re: [akka-user] Re: How can I reconcile untyped actors with typeful programming?

2014-03-09 Thread Endre Varga
Hi Aleh,


On Sun, Mar 9, 2014 at 6:56 PM, OlegYch olegl...@gmail.com wrote:

 Endre, i don't think this is related to distributed computations  at all.
 Any method call can fail even locally.


This is true of course, but way more relevant in distributed cases where
failures are orders of magnitudes more common.


 The way to represent that is with sum types e.g. Either.


Won't work. Either supposes that you received a reply (even if it is a
failure notification). No replies are guaranteed in general (distributed)
settings.

-Endre



 Thanks, Aleh


 On Sunday, March 9, 2014 8:42:11 PM UTC+3, drewhk wrote:

 Hi Daniel,

 The issue is that type systems are designed for local and not distributed
 computations. Let's look at an example.

 Imagine an actor that has three states, A, B and C

 In state A it accepts messages of type X, and when received one, it
 transitions to B
 In state B it accepts messages of type X and Y. When X is received,
 transitions to C, if Y, then stays in B
 In state C it accepts messages of type Z

 Now you send to an actor starting from state A a message X. Two things
 can happen:
  - X is delivered, so the possible accepted types are {X, Y}
  - X is lost, so the accepted type is {X}
 The intersection of those is {X}.

 Now imagine that you send another message X. Three things can happen:
  - both X's were delivered, so the accepted type is {Z}
  - only one of the X's were delivered, the other is lost, so the accepted
 types are {X, Y}
  - both X's were lost, the accepted type is {X}
 The intersection of the above cases is the empty set.

 So what should be the local type representation of an actor that you have
 sent two messages of type X?

 Let's modify the example, and assume that there was no message loss, but
 let's take the viewpoint of another sender. This sender knows that two X's
 were sent to our example actor by the other sender. What messages can we
 send? There are three scenarios:
  - both X's sent by the other sender has arrived already, so the accepted
 type is {Z}
  - only the first X sent by the other sender has arrived yet, so the
 accepted types are {X, Y}
  - no X's has arrived yet, accepted type is {X}
 The intersection of the above cases is the empty set.

 As you see, without receiving a reply from an actor, the provable type of
 an actor is usually Nothing, or something useless. Only replies can convey
 the *possible* type of an actor, and even that cannot be guaranteed if
 there are concurrent senders.

 -Endre


 On Sat, Mar 8, 2014 at 8:08 PM, Daniel Armak dana...@gmail.com wrote:

 My intent was definitely to throw away type safety. In my example you
 can wrap any ActorRef using any trait, and you can extract and use the raw
 ActorRef from a typed wrapper. The only thing I was trying to salvage was
 for the sender to declare what kind of actor / behavior they thought they
 were dealing with.

 But I'm taking your advice to heart. I'll try to use pure actors until I
 have more of a sense of how problematic various issues are.

 Thanks!

 Daniel Armak


 On Sat, Mar 8, 2014 at 8:59 PM, Derek Wyatt de...@derekwyatt.orgwrote:

 On 8 March 2014 13:31, Daniel Armak dana...@gmail.com wrote:

 Hi Derek.

 Yes, I'm aware of the tradeoffs and the reasons for them. It just
 seems to me there ought to be a middle road.

 Here's an idea off the top of my head. If remoting is going to be
 transparent, there won't be compile time type assurance. So let's give up
 on local type assurance too, and just use types for documentation and
 refactoring; that still seems a lot better than nothing.

 Suppose for each actor I wanted to implement, I declare a trait with a
 method for each message it might receive. Each method must receive exactly
 one parameter, which is the message, and return Unit:

 trait Printer {
   def print(msg: String): Unit
 }

 The method name 'print' is just for documentation; only the parameter
 is sent as the message. This preserves transparency with the actor model;
 you don't rely on the trait implementation to build the actual message.

 The user of an ActorRef would use a wrapper (value type around the
 ActorRef) generated by a macro to implement this trait. The macro would
 also validate the trait: each method has one argument, returns Unit, and
 all argument types are distinct. Each method call would be implemented as 
 a
 send().

 val actor : ActorRef = ???
 val typedActor: Printer = mymacro.wrap[Printer](actor) // Or is there
 a way to declare types with macros? I forget.
 typedActor.print(my message)

 The macro would add an (implicit sender: ActorRef) argument to each
 method.

 The actor itself would extend the Printer trait and implement its
 methods. Another macro would concatenate them to implement receive:

 class PrinterActor extends Actor with Printer with
 TypedActorMacro[Printer] {
   def print(msg: String):
 }

 To use become/unbecome, we could introduce something more complicated.
 Or, even, use the Printer trait only on 

Re: [akka-user] Re: How can I reconcile untyped actors with typeful programming?

2014-03-09 Thread √iktor Ҡlang
On Sun, Mar 9, 2014 at 8:04 PM, Endre Varga endre.va...@typesafe.comwrote:

 Hi Aleh,


 On Sun, Mar 9, 2014 at 6:56 PM, OlegYch olegl...@gmail.com wrote:

 Endre, i don't think this is related to distributed computations  at all.
 Any method call can fail even locally.


 This is true of course, but way more relevant in distributed cases where
 failures are orders of magnitudes more common.


There is a huge difference here where the caller knows when a method call
fails.




 The way to represent that is with sum types e.g. Either.


 Won't work. Either supposes that you received a reply (even if it is a
 failure notification). No replies are guaranteed in general (distributed)
 settings.


It also assumes that replies are always sent to the sender and are never
forwarded.



 -Endre



 Thanks, Aleh


 On Sunday, March 9, 2014 8:42:11 PM UTC+3, drewhk wrote:

 Hi Daniel,

 The issue is that type systems are designed for local and not
 distributed computations. Let's look at an example.

 Imagine an actor that has three states, A, B and C

 In state A it accepts messages of type X, and when received one, it
 transitions to B
 In state B it accepts messages of type X and Y. When X is received,
 transitions to C, if Y, then stays in B
 In state C it accepts messages of type Z

 Now you send to an actor starting from state A a message X. Two things
 can happen:
  - X is delivered, so the possible accepted types are {X, Y}
  - X is lost, so the accepted type is {X}
 The intersection of those is {X}.

 Now imagine that you send another message X. Three things can happen:
  - both X's were delivered, so the accepted type is {Z}
  - only one of the X's were delivered, the other is lost, so the
 accepted types are {X, Y}
  - both X's were lost, the accepted type is {X}
 The intersection of the above cases is the empty set.

 So what should be the local type representation of an actor that you
 have sent two messages of type X?

 Let's modify the example, and assume that there was no message loss, but
 let's take the viewpoint of another sender. This sender knows that two X's
 were sent to our example actor by the other sender. What messages can we
 send? There are three scenarios:
  - both X's sent by the other sender has arrived already, so the
 accepted type is {Z}
  - only the first X sent by the other sender has arrived yet, so the
 accepted types are {X, Y}
  - no X's has arrived yet, accepted type is {X}
 The intersection of the above cases is the empty set.

 As you see, without receiving a reply from an actor, the provable type
 of an actor is usually Nothing, or something useless. Only replies can
 convey the *possible* type of an actor, and even that cannot be guaranteed
 if there are concurrent senders.

 -Endre


 On Sat, Mar 8, 2014 at 8:08 PM, Daniel Armak dana...@gmail.com wrote:

 My intent was definitely to throw away type safety. In my example you
 can wrap any ActorRef using any trait, and you can extract and use the raw
 ActorRef from a typed wrapper. The only thing I was trying to salvage was
 for the sender to declare what kind of actor / behavior they thought they
 were dealing with.

 But I'm taking your advice to heart. I'll try to use pure actors until
 I have more of a sense of how problematic various issues are.

 Thanks!

 Daniel Armak


 On Sat, Mar 8, 2014 at 8:59 PM, Derek Wyatt de...@derekwyatt.orgwrote:

 On 8 March 2014 13:31, Daniel Armak dana...@gmail.com wrote:

 Hi Derek.

 Yes, I'm aware of the tradeoffs and the reasons for them. It just
 seems to me there ought to be a middle road.

 Here's an idea off the top of my head. If remoting is going to be
 transparent, there won't be compile time type assurance. So let's give up
 on local type assurance too, and just use types for documentation and
 refactoring; that still seems a lot better than nothing.

 Suppose for each actor I wanted to implement, I declare a trait with
 a method for each message it might receive. Each method must receive
 exactly one parameter, which is the message, and return Unit:

 trait Printer {
   def print(msg: String): Unit
 }

 The method name 'print' is just for documentation; only the parameter
 is sent as the message. This preserves transparency with the actor model;
 you don't rely on the trait implementation to build the actual message.

 The user of an ActorRef would use a wrapper (value type around the
 ActorRef) generated by a macro to implement this trait. The macro would
 also validate the trait: each method has one argument, returns Unit, and
 all argument types are distinct. Each method call would be implemented 
 as a
 send().

 val actor : ActorRef = ???
 val typedActor: Printer = mymacro.wrap[Printer](actor) // Or is there
 a way to declare types with macros? I forget.
 typedActor.print(my message)

 The macro would add an (implicit sender: ActorRef) argument to each
 method.

 The actor itself would extend the Printer trait and implement its
 methods. Another macro would 

Re: [akka-user] Re: How can I reconcile untyped actors with typeful programming?

2014-03-09 Thread Daniel Armak
Part of the difficulty I'm experiencing is that most of the time I want to
write code that is definitely local - a set of actors that are guaranteed
to run on the same JVM - but communication between them has to deal with
complications that only really arise from distributed computation, like
loss of type safety.

Maybe the concepts of an actor as concurrency unit with private mutable
state and failure management, and actor as a possibly-remote entity with no
guaranteed delivery, would be better partially separated. In my admittedly
limited experience, separating actors into deployment sets is part of the
system design, needs careful planning, and doesn't change often. Inside
each local set, the benefits of guaranteed locality would be large
(messages aren't lost, static typing, etc.)


On Sun, Mar 9, 2014 at 7:42 PM, Endre Varga endre.va...@typesafe.comwrote:

 Hi Daniel,

 The issue is that type systems are designed for local and not distributed
 computations. Let's look at an example.

 Imagine an actor that has three states, A, B and C

 In state A it accepts messages of type X, and when received one, it
 transitions to B
 In state B it accepts messages of type X and Y. When X is received,
 transitions to C, if Y, then stays in B
 In state C it accepts messages of type Z

 Now you send to an actor starting from state A a message X. Two things can
 happen:
  - X is delivered, so the possible accepted types are {X, Y}
  - X is lost, so the accepted type is {X}
 The intersection of those is {X}.

 Now imagine that you send another message X. Three things can happen:
  - both X's were delivered, so the accepted type is {Z}
  - only one of the X's were delivered, the other is lost, so the accepted
 types are {X, Y}
  - both X's were lost, the accepted type is {X}
 The intersection of the above cases is the empty set.

 So what should be the local type representation of an actor that you have
 sent two messages of type X?

 Let's modify the example, and assume that there was no message loss, but
 let's take the viewpoint of another sender. This sender knows that two X's
 were sent to our example actor by the other sender. What messages can we
 send? There are three scenarios:
  - both X's sent by the other sender has arrived already, so the accepted
 type is {Z}
  - only the first X sent by the other sender has arrived yet, so the
 accepted types are {X, Y}
  - no X's has arrived yet, accepted type is {X}
 The intersection of the above cases is the empty set.

 As you see, without receiving a reply from an actor, the provable type of
 an actor is usually Nothing, or something useless. Only replies can convey
 the *possible* type of an actor, and even that cannot be guaranteed if
 there are concurrent senders.

 -Endre


 On Sat, Mar 8, 2014 at 8:08 PM, Daniel Armak danar...@gmail.com wrote:

 My intent was definitely to throw away type safety. In my example you can
 wrap any ActorRef using any trait, and you can extract and use the raw
 ActorRef from a typed wrapper. The only thing I was trying to salvage was
 for the sender to declare what kind of actor / behavior they thought they
 were dealing with.

 But I'm taking your advice to heart. I'll try to use pure actors until I
 have more of a sense of how problematic various issues are.

 Thanks!

 Daniel Armak


 On Sat, Mar 8, 2014 at 8:59 PM, Derek Wyatt de...@derekwyatt.org wrote:

 On 8 March 2014 13:31, Daniel Armak danar...@gmail.com wrote:

 Hi Derek.

 Yes, I'm aware of the tradeoffs and the reasons for them. It just seems
 to me there ought to be a middle road.

 Here's an idea off the top of my head. If remoting is going to be
 transparent, there won't be compile time type assurance. So let's give up
 on local type assurance too, and just use types for documentation and
 refactoring; that still seems a lot better than nothing.

 Suppose for each actor I wanted to implement, I declare a trait with a
 method for each message it might receive. Each method must receive exactly
 one parameter, which is the message, and return Unit:

 trait Printer {
   def print(msg: String): Unit
 }

 The method name 'print' is just for documentation; only the parameter
 is sent as the message. This preserves transparency with the actor model;
 you don't rely on the trait implementation to build the actual message.

 The user of an ActorRef would use a wrapper (value type around the
 ActorRef) generated by a macro to implement this trait. The macro would
 also validate the trait: each method has one argument, returns Unit, and
 all argument types are distinct. Each method call would be implemented as a
 send().

 val actor : ActorRef = ???
 val typedActor: Printer = mymacro.wrap[Printer](actor) // Or is there a
 way to declare types with macros? I forget.
 typedActor.print(my message)

 The macro would add an (implicit sender: ActorRef) argument to each
 method.

 The actor itself would extend the Printer trait and implement its
 methods. Another macro would 

Re: [akka-user] Re: How can I reconcile untyped actors with typeful programming?

2014-03-09 Thread Endre Varga
Hi Daniel,

Please read carefully, in my second example there is no message loss.
Concurrency is enough to have the same result since arbitrary delay is
indistinguishable from message loss in any finite window of time.

-Endre


On Sun, Mar 9, 2014 at 8:31 PM, Daniel Armak danar...@gmail.com wrote:

 Part of the difficulty I'm experiencing is that most of the time I want to
 write code that is definitely local - a set of actors that are guaranteed
 to run on the same JVM - but communication between them has to deal with
 complications that only really arise from distributed computation, like
 loss of type safety.

 Maybe the concepts of an actor as concurrency unit with private mutable
 state and failure management, and actor as a possibly-remote entity with no
 guaranteed delivery, would be better partially separated. In my admittedly
 limited experience, separating actors into deployment sets is part of the
 system design, needs careful planning, and doesn't change often. Inside
 each local set, the benefits of guaranteed locality would be large
 (messages aren't lost, static typing, etc.)


 On Sun, Mar 9, 2014 at 7:42 PM, Endre Varga endre.va...@typesafe.comwrote:

 Hi Daniel,

 The issue is that type systems are designed for local and not distributed
 computations. Let's look at an example.

 Imagine an actor that has three states, A, B and C

 In state A it accepts messages of type X, and when received one, it
 transitions to B
 In state B it accepts messages of type X and Y. When X is received,
 transitions to C, if Y, then stays in B
 In state C it accepts messages of type Z

 Now you send to an actor starting from state A a message X. Two things
 can happen:
  - X is delivered, so the possible accepted types are {X, Y}
  - X is lost, so the accepted type is {X}
 The intersection of those is {X}.

 Now imagine that you send another message X. Three things can happen:
  - both X's were delivered, so the accepted type is {Z}
  - only one of the X's were delivered, the other is lost, so the accepted
 types are {X, Y}
  - both X's were lost, the accepted type is {X}
 The intersection of the above cases is the empty set.

 So what should be the local type representation of an actor that you have
 sent two messages of type X?

 Let's modify the example, and assume that there was no message loss, but
 let's take the viewpoint of another sender. This sender knows that two X's
 were sent to our example actor by the other sender. What messages can we
 send? There are three scenarios:
  - both X's sent by the other sender has arrived already, so the accepted
 type is {Z}
  - only the first X sent by the other sender has arrived yet, so the
 accepted types are {X, Y}
  - no X's has arrived yet, accepted type is {X}
 The intersection of the above cases is the empty set.

 As you see, without receiving a reply from an actor, the provable type of
 an actor is usually Nothing, or something useless. Only replies can convey
 the *possible* type of an actor, and even that cannot be guaranteed if
 there are concurrent senders.

 -Endre


 On Sat, Mar 8, 2014 at 8:08 PM, Daniel Armak danar...@gmail.com wrote:

 My intent was definitely to throw away type safety. In my example you
 can wrap any ActorRef using any trait, and you can extract and use the raw
 ActorRef from a typed wrapper. The only thing I was trying to salvage was
 for the sender to declare what kind of actor / behavior they thought they
 were dealing with.

 But I'm taking your advice to heart. I'll try to use pure actors until I
 have more of a sense of how problematic various issues are.

 Thanks!

 Daniel Armak


 On Sat, Mar 8, 2014 at 8:59 PM, Derek Wyatt de...@derekwyatt.orgwrote:

 On 8 March 2014 13:31, Daniel Armak danar...@gmail.com wrote:

 Hi Derek.

 Yes, I'm aware of the tradeoffs and the reasons for them. It just
 seems to me there ought to be a middle road.

 Here's an idea off the top of my head. If remoting is going to be
 transparent, there won't be compile time type assurance. So let's give up
 on local type assurance too, and just use types for documentation and
 refactoring; that still seems a lot better than nothing.

 Suppose for each actor I wanted to implement, I declare a trait with a
 method for each message it might receive. Each method must receive exactly
 one parameter, which is the message, and return Unit:

 trait Printer {
   def print(msg: String): Unit
 }

 The method name 'print' is just for documentation; only the parameter
 is sent as the message. This preserves transparency with the actor model;
 you don't rely on the trait implementation to build the actual message.

 The user of an ActorRef would use a wrapper (value type around the
 ActorRef) generated by a macro to implement this trait. The macro would
 also validate the trait: each method has one argument, returns Unit, and
 all argument types are distinct. Each method call would be implemented as 
 a
 send().

 val actor : ActorRef = ???
 val typedActor: 

Re: [akka-user] Re: How can I reconcile untyped actors with typeful programming?

2014-03-09 Thread Haoyi Li
 I'm sorry if I'm being obtuse here and missing something fundamental.

Don't worry, you're not the only one who's been confused by this! I'm
following this thread because I'd want to see any explanations too =P

- Someone who likes Futures but thinks Actors are hard to use.


On Sun, Mar 9, 2014 at 3:32 PM, Daniel Armak danar...@gmail.com wrote:

 Hi Endre,

 Concurrency alone isn't a reason to give up type safety. Future-based APIs
 are typed even though futures may never complete.

 (I'm not sure what you refer to with message loss; I didn't talk about
 that.)

 It's true that in the actor model each state change can change the set of
 valid message types. But with regular objects, some method calls are also
 invalid depending on the current state, they may even be invalid based on
 parameter values and not types, and yet we don't give up on static typing.

 I understand that with the current actor model, static typing probably
 isn't possible. But I don't understand why a different model couldn't in
 principle capture most or all of the benefits of actors, certainly
 including concurrency and indeterminacy, and still preserve typing.

 I'm sorry if I'm being obtuse here and missing something fundamental.


 On Sun, Mar 9, 2014 at 10:30 PM, Endre Varga endre.va...@typesafe.comwrote:

 Hi Daniel,

 Please read carefully, in my second example there is no message loss.
 Concurrency is enough to have the same result since arbitrary delay is
 indistinguishable from message loss in any finite window of time.

 -Endre


 On Sun, Mar 9, 2014 at 8:31 PM, Daniel Armak danar...@gmail.com wrote:

 Part of the difficulty I'm experiencing is that most of the time I want
 to write code that is definitely local - a set of actors that are
 guaranteed to run on the same JVM - but communication between them has to
 deal with complications that only really arise from distributed
 computation, like loss of type safety.

 Maybe the concepts of an actor as concurrency unit with private mutable
 state and failure management, and actor as a possibly-remote entity with no
 guaranteed delivery, would be better partially separated. In my admittedly
 limited experience, separating actors into deployment sets is part of the
 system design, needs careful planning, and doesn't change often. Inside
 each local set, the benefits of guaranteed locality would be large
 (messages aren't lost, static typing, etc.)


 On Sun, Mar 9, 2014 at 7:42 PM, Endre Varga endre.va...@typesafe.comwrote:

 Hi Daniel,

 The issue is that type systems are designed for local and not
 distributed computations. Let's look at an example.

 Imagine an actor that has three states, A, B and C

 In state A it accepts messages of type X, and when received one, it
 transitions to B
 In state B it accepts messages of type X and Y. When X is received,
 transitions to C, if Y, then stays in B
 In state C it accepts messages of type Z

 Now you send to an actor starting from state A a message X. Two things
 can happen:
  - X is delivered, so the possible accepted types are {X, Y}
  - X is lost, so the accepted type is {X}
 The intersection of those is {X}.

 Now imagine that you send another message X. Three things can happen:
  - both X's were delivered, so the accepted type is {Z}
  - only one of the X's were delivered, the other is lost, so the
 accepted types are {X, Y}
  - both X's were lost, the accepted type is {X}
 The intersection of the above cases is the empty set.

 So what should be the local type representation of an actor that you
 have sent two messages of type X?

 Let's modify the example, and assume that there was no message loss,
 but let's take the viewpoint of another sender. This sender knows that two
 X's were sent to our example actor by the other sender. What messages can
 we send? There are three scenarios:
  - both X's sent by the other sender has arrived already, so the
 accepted type is {Z}
  - only the first X sent by the other sender has arrived yet, so the
 accepted types are {X, Y}
  - no X's has arrived yet, accepted type is {X}
 The intersection of the above cases is the empty set.

 As you see, without receiving a reply from an actor, the provable type
 of an actor is usually Nothing, or something useless. Only replies can
 convey the *possible* type of an actor, and even that cannot be guaranteed
 if there are concurrent senders.

 -Endre


 On Sat, Mar 8, 2014 at 8:08 PM, Daniel Armak danar...@gmail.comwrote:

 My intent was definitely to throw away type safety. In my example you
 can wrap any ActorRef using any trait, and you can extract and use the raw
 ActorRef from a typed wrapper. The only thing I was trying to salvage was
 for the sender to declare what kind of actor / behavior they thought they
 were dealing with.

 But I'm taking your advice to heart. I'll try to use pure actors until
 I have more of a sense of how problematic various issues are.

 Thanks!

 Daniel Armak


 On Sat, Mar 8, 2014 at 8:59 PM, Derek Wyatt 

Re: [akka-user] Re: How can I reconcile untyped actors with typeful programming?

2014-03-08 Thread Derek Wyatt
On 8 March 2014 13:31, Daniel Armak danar...@gmail.com wrote:

 Hi Derek.

 Yes, I'm aware of the tradeoffs and the reasons for them. It just seems to
 me there ought to be a middle road.

 Here's an idea off the top of my head. If remoting is going to be
 transparent, there won't be compile time type assurance. So let's give up
 on local type assurance too, and just use types for documentation and
 refactoring; that still seems a lot better than nothing.

 Suppose for each actor I wanted to implement, I declare a trait with a
 method for each message it might receive. Each method must receive exactly
 one parameter, which is the message, and return Unit:

 trait Printer {
   def print(msg: String): Unit
 }

 The method name 'print' is just for documentation; only the parameter is
 sent as the message. This preserves transparency with the actor model; you
 don't rely on the trait implementation to build the actual message.

 The user of an ActorRef would use a wrapper (value type around the
 ActorRef) generated by a macro to implement this trait. The macro would
 also validate the trait: each method has one argument, returns Unit, and
 all argument types are distinct. Each method call would be implemented as a
 send().

 val actor : ActorRef = ???
 val typedActor: Printer = mymacro.wrap[Printer](actor) // Or is there a
 way to declare types with macros? I forget.
 typedActor.print(my message)

 The macro would add an (implicit sender: ActorRef) argument to each method.

 The actor itself would extend the Printer trait and implement its methods.
 Another macro would concatenate them to implement receive:

 class PrinterActor extends Actor with Printer with
 TypedActorMacro[Printer] {
   def print(msg: String):
 }

 To use become/unbecome, we could introduce something more complicated. Or,
 even, use the Printer trait only on the sender side - it would still be
 useful. This is just a rough outline. Do you think it might be useful, or
 do you think I shouldn't go down this road and trying to marry akka actors
 and (actor) types is a futile endeavour?


Not futile, but highly suspect.  You've barely scratched the surface with
the above and much research is way ahead of you here.

The ??? you have above isn't exactly trivial to implement, for example.
What's more is that you've probably thrown away a ton more features in the
process.  e.g.:

class MyActor(printActor: PrinterActor) { ... }

// later...

val myActor =
  MyActor.props(loadBalancer(printerActor.props()))
// oops. Does the loadBalancer now have to
// implement Printer?  What if it's a load
// balancer in front of scatter gather routers
// that talk to forwarders that talk to various
// different versions of Printers?  Does everyone
// have to implement the same API?  If not, how
// are you not throwing away type safety?  And, if so
// how am I doing anything but writing annoying code
// that keeps me a slave to the API?  And how do I
// easily manage API changes, and so on, and so forth?

Maybe not theoretically futile, but practically?  Probably :)

To be perfectly honest, it seems as though you're trying to fix a problem
without having travelled a mile in its shoes yet.  There are subsets of the
problem that are much more important and more possible to cage, and you
will see them as you progress.  When you do, focusing on those (should you
still believe them to be worth it) might be the far better option.



 Thanks!

 On Sat, Mar 8, 2014 at 7:51 PM, Derek Wyatt de...@derekwyatt.org wrote:

 What you're experiencing is a trade-off.  Actors provide a trade-off that
 you don't seem to be taking into account; endpoints (Actors) are untyped
 and the messages that they handle are strongly typed.

 You can't have an Actor be able to process anything with a
 type-specific receive method.  With Actor programming, I should be able to
 add as many intermediaries in the message flow as I like and not disturb
 the two endpoints. The intermediaries should equally be ignorant of what's
 happening (load balancers, routers, loggers, cachers, mediators,
 scatter-gather, and so forth).  You should also be able to move them around
 a cluster without disturbing the endpoints.  You can also set up dynamic
 delegation in an Actor without it having to really understand what's going
 on - for example, an Actor that speaks the main dialect but delegates to
 something else when it doesn't understand what's being said.

 If you want to eliminate all of those features, then you will be able to
 get the type-safe determinism you're looking for (so long as you stay in
 the same JVM - crossing JVMs will incur a what the hell am I *really* 
 talking
 to? question that eliminates a compile time assurance). Roland also tried
 bringing the best of both worlds together using Typed Channels but I think
 it was lacking a high enough success level to survive, but it might be a
 way to get closer to your ideal.

 In short, you're giving up type safety in order to open the door to a
 

Re: [akka-user] Re: How can I reconcile untyped actors with typeful programming?

2014-03-08 Thread Daniel Armak
My intent was definitely to throw away type safety. In my example you can
wrap any ActorRef using any trait, and you can extract and use the raw
ActorRef from a typed wrapper. The only thing I was trying to salvage was
for the sender to declare what kind of actor / behavior they thought they
were dealing with.

But I'm taking your advice to heart. I'll try to use pure actors until I
have more of a sense of how problematic various issues are.

Thanks!

Daniel Armak


On Sat, Mar 8, 2014 at 8:59 PM, Derek Wyatt de...@derekwyatt.org wrote:

 On 8 March 2014 13:31, Daniel Armak danar...@gmail.com wrote:

 Hi Derek.

 Yes, I'm aware of the tradeoffs and the reasons for them. It just seems
 to me there ought to be a middle road.

 Here's an idea off the top of my head. If remoting is going to be
 transparent, there won't be compile time type assurance. So let's give up
 on local type assurance too, and just use types for documentation and
 refactoring; that still seems a lot better than nothing.

 Suppose for each actor I wanted to implement, I declare a trait with a
 method for each message it might receive. Each method must receive exactly
 one parameter, which is the message, and return Unit:

 trait Printer {
   def print(msg: String): Unit
 }

 The method name 'print' is just for documentation; only the parameter is
 sent as the message. This preserves transparency with the actor model; you
 don't rely on the trait implementation to build the actual message.

 The user of an ActorRef would use a wrapper (value type around the
 ActorRef) generated by a macro to implement this trait. The macro would
 also validate the trait: each method has one argument, returns Unit, and
 all argument types are distinct. Each method call would be implemented as a
 send().

 val actor : ActorRef = ???
 val typedActor: Printer = mymacro.wrap[Printer](actor) // Or is there a
 way to declare types with macros? I forget.
 typedActor.print(my message)

 The macro would add an (implicit sender: ActorRef) argument to each
 method.

 The actor itself would extend the Printer trait and implement its
 methods. Another macro would concatenate them to implement receive:

 class PrinterActor extends Actor with Printer with
 TypedActorMacro[Printer] {
   def print(msg: String):
 }

 To use become/unbecome, we could introduce something more complicated.
 Or, even, use the Printer trait only on the sender side - it would still be
 useful. This is just a rough outline. Do you think it might be useful, or
 do you think I shouldn't go down this road and trying to marry akka actors
 and (actor) types is a futile endeavour?


 Not futile, but highly suspect.  You've barely scratched the surface with
 the above and much research is way ahead of you here.

 The ??? you have above isn't exactly trivial to implement, for example.
 What's more is that you've probably thrown away a ton more features in the
 process.  e.g.:

 class MyActor(printActor: PrinterActor) { ... }

 // later...

 val myActor =
   MyActor.props(loadBalancer(printerActor.props()))
 // oops. Does the loadBalancer now have to
 // implement Printer?  What if it's a load
 // balancer in front of scatter gather routers
 // that talk to forwarders that talk to various
 // different versions of Printers?  Does everyone
 // have to implement the same API?  If not, how
 // are you not throwing away type safety?  And, if so
 // how am I doing anything but writing annoying code
 // that keeps me a slave to the API?  And how do I
 // easily manage API changes, and so on, and so forth?

 Maybe not theoretically futile, but practically?  Probably :)

 To be perfectly honest, it seems as though you're trying to fix a
 problem without having travelled a mile in its shoes yet.  There are
 subsets of the problem that are much more important and more possible to
 cage, and you will see them as you progress.  When you do, focusing on
 those (should you still believe them to be worth it) might be the far
 better option.



 Thanks!

 On Sat, Mar 8, 2014 at 7:51 PM, Derek Wyatt de...@derekwyatt.org wrote:

 What you're experiencing is a trade-off.  Actors provide a trade-off
 that you don't seem to be taking into account; endpoints (Actors) are
 untyped and the messages that they handle are strongly typed.

 You can't have an Actor be able to process anything with a
 type-specific receive method.  With Actor programming, I should be able to
 add as many intermediaries in the message flow as I like and not disturb
 the two endpoints. The intermediaries should equally be ignorant of what's
 happening (load balancers, routers, loggers, cachers, mediators,
 scatter-gather, and so forth).  You should also be able to move them around
 a cluster without disturbing the endpoints.  You can also set up dynamic
 delegation in an Actor without it having to really understand what's going
 on - for example, an Actor that speaks the main dialect but delegates to
 something else when it doesn't understand what's