Hi Philipp,
Apologies for misspelling your name.
By the by, not to 'hit and run' with this thread, I bought Programming
in Erlang by Joe Armstrong recently, not least to make sure that I
understand how actors are supposed to work. I plan to revisit this
thread/topic when I know what I'm talking about.
When I mentioned the simplicity of my library, I didn't intend to
accuse scala.actors of complexity - I'm quite aware that my library is
very limited (in fact I have a few versions each with different
subsets implemented). I'm looking at scala.actors for inspiration,
and trying to understand the decisions embodied in it, rather than
trying to outright criticise it.
Cheers,
Ricky.
2008/8/18 Philipp Haller <
philipp.haller@...>:
> Hi, Jesper,
>
> Of course, one can choose a type that somehow subsumes all the types
> that an actor receives. (As a minor point, note that when using `Either`
> or other types, one has to re-organize the code accordingly.)
>
> However, after giving it more thought I realized that the problem comes
> from the dynamic scoping of `self` which refers to the currently
> executing actor:
>
> actor {
> actor {
> ... self ...
> }
> ... self ...
> }
>
> In the above example the two occurrences of `self` refer to two
> different actors. Note that `self` has dynamic scope, therefore we can
> use `self` inside a function, e.g.
>
> def f(x: Int): Unit = {
> ... self ...
> }
>
> and it will continue to refer to the currently executing actor even if
> the concrete actor instance is not known at compile time:
>
> actor {
> actor {
> if (b1) f(0)
> }
> if (b2) f(1)
> }
>
> Assuming that using `actor` one could create typed actors `Actor[+Msg]`,
> and types `S` and `T` are unrelated, then in
>
> actor[S] {
> actor[T] {
> ... self ...
> }
> ... self ...
> }
>
> the type of `self` would have to be `Actor[Nothing]` and therefore
> useless for typed message sends.
>
> Currently, I see two approaches to allow typed actors:
>
> 1. Remove the dynamically-scoped `self` altogether. Replace the untyped
> `actor` function with
>
> def actor[T](Actor[T] => Unit): Actor[T]
>
> Example use:
>
> actor[Int] { self => ... }
>
> The downside to this is that there is no common way to refer to
> the currently executing actor (regardless of how it is created). As a
> consequence, some patterns used in, e.g., Erlang, are ruled out.
>
> 2. Allow some dynamic scoping w.r.t. `self`:
> Keep the untyped `actor` function as a way to create `Actor[Any]`s.
> These actors can use `self` with dynamic scope.
>
> Typed actors are created by sub-classing `Actor[+Msg]`. Inside typed
> actors, use of the dynamically-scoped `self` results in a runtime
> error.
>
>
> Cheers,
> Philipp
>
>
> Jesper Nordenberg wrote:
>> Philipp Haller wrote:
>>> 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.
>>
>> So, in this case you create an Actor[Any] (or a more advanced type with
>> Either or the message sequence encoded in the type). I can't think of
>> any reason why the Actor class shouldn't have a type parameter.
>>
>>> 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)]
>>> }
>>
>> The usefulness of message type check is not primarily on the receiver
>> side, it's on the caller side. You don't want to send a message of
>> incorrect type to an actor and get a runtime error.
>>
>> In essence, you can view an actor as a function of type "A =>
>> Future[B]". Types A and B are clearly related, if you send an actor a
>> certain message type you would expect a reply of a certain type. How can
>> we encode this in Scala? The straightforward way would be to encode the
>> return type in the message type, for example:
>>
>> trait Message { type ReturnType }
>>
>> case class MyMess(x : Int, y : Int) extends Message {
>> type ReturnType = Int
>> }
>>
>> trait Actor[Msg] {
>> def ! : Future[T#ReturnType]
>> }
>>
>> (alternatively "trait Actor[Msg <: Message]")
>>
>> However, implementing the receive method in a type safe way is AFAIK not
>> possible to do in Scala, you would have to resort to casting.
>>
>> /Jesper Nordenberg
>>
>
>