make tryTell nice from Scala AND Java

Thanks, Derek Williams, for the good suggestion!
This commit is contained in:
Roland 2011-08-03 23:08:38 +02:00
parent a43418a4c3
commit 2aa86ed37a
5 changed files with 64 additions and 30 deletions

View file

@ -31,4 +31,10 @@ public class JavaAPI {
}); });
assertNotNull(ref); assertNotNull(ref);
} }
@Test void mustAcceptSingleArgTryTell() {
ActorRef ref = Actors.actorOf(JavaAPITestActor.class);
ref.tryTell("hallo");
ref.tryTell("hallo", ref);
}
} }

View file

@ -32,6 +32,16 @@ class ChannelSpec extends WordSpec with MustMatchers {
}).start() }).start()
a ! "hallo" a ! "hallo"
s must be(("hallo", a)) s must be(("hallo", a))
{
implicit val actor = a
ch tryTell "buh"
}
s must be(("buh", a))
ch.!("world")(a)
s must be(("world", a))
ch.tryTell("bippy")(a)
s must be(("bippy", a))
} }
} }

View file

@ -303,7 +303,7 @@ abstract class ActorRef extends ActorRefShared with ForwardableChannel with Repl
* *
* If you would rather have an exception, check the <code>reply(..)</code> version. * If you would rather have an exception, check the <code>reply(..)</code> version.
*/ */
def tryReply(message: Any): Boolean = channel.tryTell(message, this) def tryReply(message: Any): Boolean = channel.tryTell(message)(this)
/** /**
* Sets the dispatcher for this actor. Needs to be invoked before the actor is started. * Sets the dispatcher for this actor. Needs to be invoked before the actor is started.

View file

@ -4,6 +4,23 @@
package akka.actor package akka.actor
/*
* This package is just used to hide the tryTell method from the Scala parts:
* it will be public to javac's eyes by virtue of §5.2 of the SLS.
*/
package japi {
trait Channel[-T] { self: akka.actor.Channel[T]
private[japi] def tryTell(msg: T): Boolean = {
try {
self.!(msg)(NullChannel)
true
} catch {
case _: Exception false
}
}
}
}
/** /**
* Abstraction for unification of sender and senderFuture for later reply. * Abstraction for unification of sender and senderFuture for later reply.
* Can be stored away and used at a later point in time. * Can be stored away and used at a later point in time.
@ -12,13 +29,39 @@ package akka.actor
* untyped, as there is no way to utilize its real static type without * untyped, as there is no way to utilize its real static type without
* requiring runtime-costly manifests. * requiring runtime-costly manifests.
*/ */
trait Channel[-T] { trait Channel[-T] extends japi.Channel[T] {
/** /**
* Scala API. <p/> * Scala API. <p/>
* Sends the specified message to the channel. * Sends the specified message to the channel.
*/ */
def !(msg: T)(implicit channel: UntypedChannel): Unit def !(msg: T)(implicit sender: UntypedChannel): Unit
/**
* Scala and Java API. <p/>
* Try to send the specified message to the channel, i.e. fire-and-forget
* semantics, including the sender reference if possible (not supported on
* all channels).<p/>
* From Java:
* <pre>
* actor.tryTell(message);
* actor.tryTell(message, context);
* </pre>
* <p/>
* From Scala:
* <pre>
* actor tryTell message
* actor.tryTell(message)(sender)
* </pre>
*/
def tryTell(msg: T)(implicit sender: UntypedChannel): Boolean = {
try {
this.!(msg)(sender)
true
} catch {
case _: Exception false
}
}
/** /**
* Try to send an exception. Not all channel types support this, one notable * Try to send an exception. Not all channel types support this, one notable
@ -47,32 +90,6 @@ trait Channel[-T] {
*/ */
def tell(msg: T, sender: UntypedChannel): Unit = this.!(msg)(sender) def tell(msg: T, sender: UntypedChannel): Unit = this.!(msg)(sender)
/**
* Try to send the specified message to the channel, i.e. fire-and-forget semantics.<p/>
* <pre>
* channel.tell(message);
* </pre>
*/
def tryTell(msg: T): Boolean = this.tryTell(msg, NullChannel)
/**
* Java API. <p/>
* Try to send the specified message to the channel, i.e. fire-and-forget
* semantics, including the sender reference if possible (not supported on
* all channels).<p/>
* <pre>
* actor.tell(message, context);
* </pre>
*/
def tryTell(msg: T, sender: UntypedChannel): Boolean = {
try {
this.!(msg)(sender)
true
} catch {
case _: Exception false
}
}
} }
/** /**

View file

@ -349,7 +349,8 @@ Simply call ``self.channel`` and then you can forward that to others, store it a
case request => case request =>
val result = process(request) val result = process(request)
self.channel ! result self.channel ! result // will throw an exception if there is no sender information
self.channel tryTell result // will return Boolean whether reply succeeded
The :class:`Channel` trait is contravariant in the expected message type. Since The :class:`Channel` trait is contravariant in the expected message type. Since
``self.channel`` is subtype of ``Channel[Any]``, you may specialise your return ``self.channel`` is subtype of ``Channel[Any]``, you may specialise your return