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?

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
> whole new set of facilities.  Don't want to lose the type-safety?  Close
> the door :)
>
> I had the exact same reservations as you have right now.  I tried to
> reconcile them myself, using typed actors and my world turned into a pile
> of crap... I got no real flexibility out of that system.  There was a
> cognitive overhead to switching to actors and no benefit.
>
> In the end, I learned to embrace the patterns and philosophy and grew to
> love it so much that I wrote a book about it (the first one, I think) and
> now code in Scala and Akka every single day.  Your mileage may vary :)
>
>
> On Friday, March 7, 2014 5:10:23 PM UTC-5, Daniel Armak wrote:
>>
>> Hello,
>>
>> I hope someone will take the time to read this message (sorry about its
>> length) and help me.
>>
>> I'm writing a fairly large system from scratch in Scala. I love the rich
>> typing and functional programming style, and I have experience with
>> future-based programming, but not actors.
>>
>> When I try to use actors, I feel like I'm giving up static typing, even
>> the basic feature of a type declaring its methods (=received messages). Using
>> partial functions feels like casting, because I really want to assert that
>> the 'partial' function will always match.
>>
>> This can't be right. How do you reconcile the two worlds?
>>
>> Specific issues I'm struggling with:
>>
>> 1. Typed code is discoverable via methods and fields. An actor relies on
>> documentation.
>>
>> One option is to define all messages an actor can receive in its
>> companion object, and document each message; but many libraries (e.g.
>> spray) define many different actors that all send and receive the same
>> types (eg HttpRequest), which is convenient for forwarding messages between
>> actors. But then the *only* way to figure out which messages are legal and
>> the semantics of what they do is to read the docs.
>>
>> When an actor manages complex state and might receive ten or twenty
>> different message types, this is hard to manage.
>>
>> Even if I document the actor, this documentation is still not
>> discoverable because the client has an ActorRef, not an
>> ActorRef[MyActorTrait]. So I have to figure out manually what behavior this
>> actor is expected to implement and read the docs for that.
>>
>> 2. Refactoring actors is hard. To make a non-backward-compatible API
>> change to an actor, I have to go over all references to the message types
>> involved. No more 'find all usages of method' or 'rename method'.
>>
>> 3. Typed Actors lack important Actor features (become/unbecome, etc),
>> have to declare exceptions, suffer a proxy performance penalty, and aren't
>> recommended as a replacement for actors in general.
>>
>>
>> I understand that features like become() and remoting make it difficult
>> to type actors, and maybe this is just an unsolved difficult problem. So
>> how do mature actor-based projects handle these issues? How can I have the
>> benefits of both actors and static typing?
>>
>> TIA for any insight.
>>
>> Daniel Armak
>>
>  --
> >>>>>>>>>> Read the docs: http://akka.io/docs/
> >>>>>>>>>> Check the FAQ:
> http://doc.akka.io/docs/akka/current/additional/faq.html
> >>>>>>>>>> Search the archives: https://groups.google.com/group/akka-user
> ---
> You received this message because you are subscribed to the Google Groups
> "Akka User List" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to akka-user+unsubscr...@googlegroups.com.
> To post to this group, send email to akka-user@googlegroups.com.
> Visit this group at http://groups.google.com/group/akka-user.
> For more options, visit https://groups.google.com/d/optout.
>

-- 
>>>>>>>>>>      Read the docs: http://akka.io/docs/
>>>>>>>>>>      Check the FAQ: 
>>>>>>>>>> http://doc.akka.io/docs/akka/current/additional/faq.html
>>>>>>>>>>      Search the archives: https://groups.google.com/group/akka-user
--- 
You received this message because you are subscribed to the Google Groups "Akka 
User List" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to akka-user+unsubscr...@googlegroups.com.
To post to this group, send email to akka-user@googlegroups.com.
Visit this group at http://groups.google.com/group/akka-user.
For more options, visit https://groups.google.com/d/optout.

Reply via email to