« Return to Thread: [scala] Why are Scala's actors untyped?
Hi, Ricky,
First, why are actors currently untyped?
Originally, the actors library emerged from an experiment to implement
Erlang in Scala. In that model, it is common to have nested receives, i.e.
receive {
case first =>
...
receive {
case second => ...
}
}
Now, if the types of `first` and `second` are unrelated, then certainly
the actor must be able to accept messages of type `Any`. Otherwise, at
least one of the receives would block indefinitely which is undesirable.
If the outer receive could enforce that inner receives operate on a
related message type, then we could give the actor a more precise
(input) type.
Why does this "untyped" scheme work surprisingly well in Scala? Pattern
matching helps you recover types, e.g.:
case class DoThis(x: List[(Int, String)])
receive {
case DoThis(args) => // know that args: List[(Int, String)]
}
Since you alluded to the simplicity of your library:
Much of the complexity of the actors library stems from the fact that an
actor can suspend in a nested event-based receive (called `react`). This
is explained in the first actors paper [1]. There is a set of
combinators, such as `loop`, that makes actors written in that style
composable. To some extent this is explained in the second actors paper [2].
There are more reasons why `scala.actors` doesn't fit on a screenful of
code. An important one is that it is guaranteed that only a single
thread is executing "inside" an actor at a time (which your
implementation does not guarantee since it submits `Callable`s right
away). For this you need an additional message queue. Other reason are
interoperability with Java threads (see [2]), monitoring through links etc.
Now, if you would disallow nested receives, then you could certainly
give those restricted actors a more precise type.
Basically, given a function `fun: M => R` the typed actors would fit the
pattern
loop {
react { case any => reply(fun(any)) }
}
where `fun` would not contain any calls to potentially suspending
methods, such as `react`.
In fact, this is how you can do input-typed actors using the existing
library:
def typedActor[A](fun: A => Unit): OutputChannel[A] = {
val sink = new SyncVar[Channel[A]]
actor {
val in = new Channel[A](self)
sink set in
loop {
in react { case any => reply(fun(any)) }
}
}
sink.get
}
Output types are also useful, e.g., to type synchronous and future-type
message sends, such as `!?` and `!!`. However, this probably requires a
little more effort.
But, I agree with you and others that it would good to have more support
for this in the library.
Cheers,
Philipp
[1] Haller, Odersky: Event-based Programming without Inversion of
Control, Proc. JMLC 2006
[2] Haller, Odersky: Actors that Unify Threads and Events, Proc.
COORDINATION 2007
Ricky Clarkson wrote:
> Hi all,
>
> I came across a use case for actors in my Java-only job, so I started
> thinking about how to go about implementing them for Java (or possibly
> using Scala's actors as a library, though $bang isn't a great method
> name). I learned enough of Erlang to be dangerous, then looked at
> Scala's implementation, to see how it would typically be implemented on
> the JVM. I was quite surprised to see that Scala's actors' messages are
> dispatched on through pattern matching - not the usual pattern matching
> that you can use to take a List, Option or Either to bits, but the kind
> equivalent to instanceof and casts from Javaland - i.e.,
> BreaksWhenYouChangeStuff(tm).
>
> So I had a quick go and had typed actors working well in Java in a
> couple of hours, enough to get my job done. Of course, programming for
> a Javaland project means that certain features seem too leftfield, e.g.,
> using Either, tuples or Option, so in my own time I decided to port my
> typed actors to less than a screenful of Scala.
>
> Then I had a look at Phillip Haller's tutorial on Scala Actors (
> http://lamp.epfl.ch/~phaller/doc/ActorsTutorial.html ), and ported his
> PingPong example to my library. (Library sounds grandiose for less than
> a screenful of code, but nevermind). I link here to my version of that
> example - http://cime.net/~ricky/tmp/PingPong.scala . I tried to keep
> close to the original, but I found it hard to keep track of using Ping
> and Pong twice (as a class extending Actor and as a case object
> representing a message), so I renamed the case objects to PingMessage
> and PongMessage (and changed them to case classes).
>
> But for the second example, I really have no idea why you would ever use
> actors to implement synchronous iteration over a tree, so I deleted my
> half-written port of that until I have fresher eyes. If anyone can
> explain why that example is useful, please do!
>
> So far though, I'm really unsure why the original library is untyped -
> if it turns out when I do more interesting things with my version that
> typing is impossible or too awkward sometimes, it would make sense to
> route around it, but to have untyping as the default in Scala seems.. odd.
>
> So, please enlighten me - why is it better to have untyped actors than
> typed actors? If you quote the test case above in your explanation,
> please don't count Either against it - that can easily be removed.
>
> Here's my working version of the 'library' for typed actors - names
> copied from scala.actors, laughably small -
> http://cime.net/~ricky/tmp/Actor.scala . I'm not really sure right now
> whether Actor should have a result type too (it does in that version) or
> just a message type.
>
> Cheers,
> Ricky.
« Return to Thread: [scala] Why are Scala's actors untyped?
| Free embeddable forum powered by Nabble | Forum Help |