![]() | ![]() | ![]() | 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 OutputChannels and
InputChannels.
OutputChannels 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 InputChannels. 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 |