From da7d8783871a7dc654ad8c36b9fbea5028025f47 Mon Sep 17 00:00:00 2001 From: Roland Date: Wed, 15 Jun 2011 20:39:29 +0200 Subject: [PATCH 1/2] make Channel contravariant --- .../scala/akka/actor/actor/ChannelSpec.scala | 16 ++++++++++++++++ .../src/main/scala/akka/actor/Channel.scala | 7 ++----- 2 files changed, 18 insertions(+), 5 deletions(-) create mode 100644 akka-actor-tests/src/test/scala/akka/actor/actor/ChannelSpec.scala diff --git a/akka-actor-tests/src/test/scala/akka/actor/actor/ChannelSpec.scala b/akka-actor-tests/src/test/scala/akka/actor/actor/ChannelSpec.scala new file mode 100644 index 0000000000..7300f4a28e --- /dev/null +++ b/akka-actor-tests/src/test/scala/akka/actor/actor/ChannelSpec.scala @@ -0,0 +1,16 @@ +package akka.actor + +import org.scalatest.WordSpec +import org.scalatest.matchers.MustMatchers +import akka.dispatch._ + +class ChannelSpec extends WordSpec with MustMatchers { + "A Channel" must { + "be contravariant" in { + val ap = new ActorPromise(1000) + val p: Promise[Any] = ap + val c: Channel[Any] = ap + val cs: Channel[String] = c + } + } +} diff --git a/akka-actor/src/main/scala/akka/actor/Channel.scala b/akka-actor/src/main/scala/akka/actor/Channel.scala index 80134f2df8..2896883f2b 100644 --- a/akka-actor/src/main/scala/akka/actor/Channel.scala +++ b/akka-actor/src/main/scala/akka/actor/Channel.scala @@ -8,14 +8,11 @@ package akka.actor * Abstraction for unification of sender and senderFuture for later reply. * Can be stored away and used at a later point in time. * - * Channel cannot be contravariant because of Future providing its value in - * covariant position. - * * The possible reply channel which can be passed into ! and safe_! is always * untyped, as there is no way to utilize its real static type without * requiring runtime-costly manifests. */ -trait Channel[T] { +trait Channel[-T] { /** * Scala API.

@@ -105,7 +102,7 @@ trait Channel[T] { * i.e. ! is not guaranteed to fail (e.g. NullChannel would be a * counter-example). */ -trait AvailableChannel[T] { self: Channel[T] ⇒ +trait AvailableChannel[-T] { self: Channel[T] ⇒ def safe_!(msg: T)(implicit channel: UntypedChannel = NullChannel): Boolean = { if (isUsable) { try { From 6a3049e4c5c1e6af1f6752ff982c665e1031582b Mon Sep 17 00:00:00 2001 From: Roland Date: Wed, 15 Jun 2011 21:04:33 +0200 Subject: [PATCH 2/2] document Channel contravariance --- .../test/scala/akka/actor/actor/ChannelSpec.scala | 4 ++++ akka-docs/scala/actors.rst | 13 ++++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/akka-actor-tests/src/test/scala/akka/actor/actor/ChannelSpec.scala b/akka-actor-tests/src/test/scala/akka/actor/actor/ChannelSpec.scala index 7300f4a28e..61c898f8be 100644 --- a/akka-actor-tests/src/test/scala/akka/actor/actor/ChannelSpec.scala +++ b/akka-actor-tests/src/test/scala/akka/actor/actor/ChannelSpec.scala @@ -1,3 +1,7 @@ +/** + * Copyright (C) 2009-2011 Scalable Solutions AB + */ + package akka.actor import org.scalatest.WordSpec diff --git a/akka-docs/scala/actors.rst b/akka-docs/scala/actors.rst index 2d0f105e0e..3019272e7f 100644 --- a/akka-docs/scala/actors.rst +++ b/akka-docs/scala/actors.rst @@ -266,7 +266,7 @@ Reply using the channel ^^^^^^^^^^^^^^^^^^^^^^^ If you want to have a handle to an object to whom you can reply to the message, you can use the ``Channel`` abstraction. -Simply call ``self.channel`` and then you can forward that to others, store it away or otherwise until you want to reply, which you do by ``Channel ! response``: +Simply call ``self.channel`` and then you can forward that to others, store it away or otherwise until you want to reply, which you do by ``channel ! response``: .. code-block:: scala @@ -274,6 +274,17 @@ Simply call ``self.channel`` and then you can forward that to others, store it a val result = process(request) self.channel ! result +The :class:`Channel` trait is contravariant in the expected message type. Since +``self.channel`` is subtype of ``Channel[Any]``, you may specialise your return +channel to allow the compiler to check your replies:: + + class MyActor extends Actor { + def doIt(channel: Channel[String], x: Any) = { channel ! x.toString } + def receive = { + case x => doIt(self.channel, x) + } + } + .. code-block:: scala case request =>