Channels | Contents | Index |
Channels can be used to simplify the handling of messages that have
different types but that are sent to the same actor. The hierarchy of
channels is divided into OutputChannel
s and
InputChannel
s.
OutputChannel
s can be sent messages. An OutputChannel
out
supports the following operations.
out ! msg
. Asynchronously sends msg
to
out
. A reference to the sending actor is transferred as in
the case where msg
is sent directly to an actor.
out forward msg
. Asynchronously forwards msg
to
out
. The sending actor is determined as in the case where
msg
is forwarded directly to an actor.
out.receiver
. Returns the unique actor that is receiving
messages sent to the out
channel.
out.send(msg, from)
. Asynchronously sends msg
to
out
supplying from
as the sender of the message.
Note that the OutputChannel
trait has a type parameter that
specifies the type of messages that can be sent to the channel (using
!
, forward
, and send
). The type parameter is
contravariant: trait OutputChannel[-Msg]
.
Actors can receive messages from InputChannel
s. Like
OutputChannel
, the InputChannel
trait has a type
parameter that specifies the type of messages that can be received
from the channel. The type parameter is covariant:
trait InputChannel[+Msg]
. An InputChannel[Msg]
in
supports the following operations.
in.receive { case Pat1 => ... ; case Patn => ... }
(and
similarly, in.receiveWithin
). Receives a message from
in
. Invoking receive
on an input channel has the same
semantics as the standard receive
operation for actors. The
only difference is that the partial function passed as an argument
has type PartialFunction[Msg, R]
where R
is the return
type of receive
.
in.react { case Pat1 => ... ; case Patn => ... }
(and
similarly, in.reactWithin
). Receives a message from in
using the event-based react
operation. Like react
for
actors, the return type is Nothing
, indicating that
invocations of this method never return. Like the receive
operation above, the partial function passed as an argument has a
refined type: PartialFunction[Msg, Unit]
.
Channels are created using the concrete Channel
class. It
extends both InputChannel
and OutputChannel
. A channel
can be shared either by making the channel visible in the scopes of
multiple actors, or by sending it in a message.
The following example demonstrates scope-based sharing.
actor { var out: OutputChannel[String] = null val child = actor { react { case "go" => out ! "hello" } } val channel = new Channel[String] out = channel child ! "go" channel.receive { case msg => println(msg.length) } }
Running this example prints the string "5"
to the console. Note
that the child
actor has only access to out
which is an
OutputChannel[String]
. The channel
reference, which can
also be used to receive messages, is hidden. However, care must be
taken to ensure the output channel is initialized to a concrete
channel before the child
sends messages to it. This is done
using the "go"
message. When receiving from channel
using channel.receive
we can make use of the fact that
msg
is of type String
; therefore, it provides a
length
member.
An alternative way to share channels is by sending them in messages. The following example demonstrates this.
case class ReplyTo(out: OutputChannel[String]) val child = actor { react { case ReplyTo(out) => out ! "hello" } } actor { val channel = new Channel[String] child ! ReplyTo(channel) channel.receive { case msg => println(msg.length) } }
The ReplyTo
case class is a message type that we use to
distribute a reference to an OutputChannel[String]
. When the
child
actor receives a ReplyTo
message it sends a string
to its output channel. The second actor receives a message on that
channel as before.
Channels | Contents | Index |