The Akka docs call Actor's receive as a method. But as per the API it is a abstract type member rather than an abstract method. Any reason why receive is termed as a method?
Yeah, docs could be improved a bit.
If you take a look into the Actor trait, you will notice that receive is indeed a method. The Actor.Receive in its signature is the type member you are referring to, defined in the Actor object.
So, receive is an abstract method that every Actor needs to implement. Its type is partial function; you can easily tell because it takes a bunch of case statements, e.g.
def receive = {
case "test" => log.info("received test")
case _ => log.info("received unknown message")
}
Each case statement takes Any and returns Unit, so the actual type of the partial function is PartialFunction[Any, Unit]. For clarity and simplicity, Akka guys decided to create a placeholder for that particular type, they called it Receive and they put it in the Actor companion object.
Small digression: a lot of folks are not really happy with messages being of type Any and Akka guys have promised to introduce typed messages; not sure if they delivered it yet in the latest release though.
Related
I have a case class Disconnect(nodeId: PublicKey) that has 1 parameter in it, however in some other part of the code it happened to be used without the parameter i.e: Disconnect and the compiler did not catch the error, note that I've also tried to run the compiler with -Xlint option and it still can't catch the error.
scala version: 2.11.12
target jvm version: 1.8
code compiled with options:
-deprecation
-feature
-language:postfixOps
-language:implicitConversions
-Xfatal-warnings
-unchecked
-Xmax-classfile-name 140
-nobootcp
[history] It used to be case object Disconnect but at some point it has been changed to case class and a parameter was added, in the code it was still instantiated parameterless and the compiler couldn't notice it. I tried adding -Xlint option to the compiler but it didn't help.
In Peer.scala
object Peer {
// other code
case class Disconnect(nodeId: PublicKey)
// more code
}
In Channel.scala
// inside a function
revocationTimeout.peer ! Peer.Disconnect
//
I expected the compiler to catch the misuse of the case class and fail to compile.
Edit: thanks all for the replies, indeed the compiler is doing his job just fine and Disconnect is being used as a type instead of case class instance, this is possible because it's used in a function that accepts Any as parameter.
Since you declare Disconnect to be a case class, the compiler automatically generates a companion object Disconnect, which holds all the neat apply and unapply methods. Therefore, Peer.Disconnect is a perfectly valid expression of the singleton type Peer.Disconnect.type. One might argue that it wouldn't have happened if you used Akka Typed right from the beginning, but in your code, the ! method accepts anything, so in order to force the compiler to emit some meaningful error messages, you need something else. Here is one simple approach:
Revert to the state where Disconnect was a singleton object, without an associated case class.
Remove the Disconnect definition altogether. Add case class NewDisconnect instead. Now every occurrence of Peer.Disconnect will become a proper error.
Replace all Peer.Disconnect by Peer.NewDisconnect(foo)
Rename NewDisconnect to Disconnect.
I assume that ! is the tell operator from akka actors.
It's signature is
def !(message: Any)(implicit sender: ActorRef = Actor.noSender): Unit
So you can send to it literally anything, in this case you are sending the type Disconnect.
This is one of the greatest disadvantages from using akka actors, that's why there is a new module akka typed where you define a type-safe behavior for your actors.
You may wonder why this doesn't blow up in runtime if you are sending an object that you don't expect. The reason is that actor's receive is a PartialFunction[Any, Unit] that "discards" the messages that are not defined for the PF.
The problem is not in the compiler but in the method ! which accepts Any as argument:
def !(message: Any)(implicit sender: ActorRef = Actor.noSender): Unit
so we could change the argument to anything and it would still compile, for example,
revocationTimeout.peer ! "woohoo" // compiles OK!
On the other hand if we look at the corresponding Akka Typed ! method
implicit final class ActorRefOps[-T](val ref: ActorRef[T]) extends AnyVal {
def !(msg: T): Unit = ref.tell(msg)
}
then we see it is parameterised with type parameter T and the compiler would catch it.
I'm rather new to Scala so this may be a trivial question. I'm trying to put together a simple project in Akka and I'm not sure how to handle a situation where I need to store a reference to an actor of a constrained type.
Let's assume I have an actor trait
trait MyActorTrait extends Actor
Then somewhere else I would like to define another trait with a member
def reference: ActorRef[MyActorTrait]
That obviously doesn't work since ActorRef doesn't care about the target actor's type (or does it?). Is there any way to constrain the reference to only accept references to actors that extend MyActorTrait?
By design, there is no way you can access the underlying Actor through ActorRef (or, pretty much, any other way). So, constraining the type like you describe is pointless, there would be absolutely no difference in what you can do with ActorRef[Foo] vs. ActorRef[Bar].
Not saying, this is a good thing (few things in Akka can be characterized that way IMO), but that's just the way it is.
The way you try to reference an actor in another actor is not right. Actors form a hierarchy. So it gives you a path to refer an actor. There are mainly three ways you could reference another actor using
Absolute Paths
context.actorSelection("/user/serviceA")
Relative Paths
context.actorSelection("../brother") ! msg
Querying the Logical Actor Hierarchy
context.actorSelection("../*") ! msg
You may have a look at the doc - https://doc.akka.io/docs/akka/2.5/general/addressing.html.
After some digging around I believe I've found a way.
First I create a trait which will preserve the actor type
trait TypedActorRef[T <: Actor] {
def reference: ActorRef
type t = T
}
Then implement a generic apply which instantiates a private case class extending the trait
object TypedActorRef {
private case class Ref[T <: Actor] (reference: ActorRef) extends TypedActorRef[T]
def apply[T <: Actor](actor: T) = {
Ref[T](actor.self)
}
}
With that I can keep a reference which is restricted an actor of the type I want.
trait OtherActor extends Actor
trait MyActor extends Actor
{
def otherActorsReference: TypedActorRef[OtherActor]
}
This seems OK to me, at least this seems not to upset the compiler, but I'm not sure if this solution prevents from creating other extensions of the TypedActorRef which may not respect the same constraints.
I spent two days trying to debug an issue where a message wasn't being handled by an actor, ultimately to find out the message being sent to it didn't have the parentheses following its name. If parameter-less case classes without parentheses are deprecated in Scala, why does Akka still allow them to be sent without warning?
I guess that the problem here isn't that the companion object is not Serializable. You would get warning anyway - and an exception if you use akka remoting. The problem probably was that the receive function in the receieving actor doesn't have a case for the companion object.
Akka simply doesn't care which messages are you sending as you can send any object as a message. Doesn't make sense to me to have a check that you shouldn't be sending a deprecated class.
I'm guessing here but sounds like what you were sending was the companion object of the case class and not the case class itself. The case class would have been serializable by default (all case classes are serializable if constructed from serializable components) but the companion is not guaranteed to be serializable.
In the code I'm working on I have a class called SuccessMessage with fields actorType (an enum) and payload. I am not sure what type to make payload.
If I make payload of type Any, I have to do a lot of gross looking instanceOf type casting to handle it later on in my code in more specific implementations.
If I use generics, and make payload of type T, my other classes have to also include the type T. For example, in a high level trait of mine called Commander, I have a method called handleSuccess that takes in a SuccessMessage, and it will have to be able to take in a success message of generic type T, forcing my commander to be of generic type T too.
I am not sure if I have to pick between these two lesser evils, or if there is a better way of doing it. I have to include some way of generifying payload, because Success Message requires a payload of different types.
EDIT:
There is an additional problem with generics. Commander has to be able to handle many different kinds of SuccessMessages, so if it takes a SuccessMessage[T] in handleSuccess, forcing Commander to be Commander[T], then Commander won't be able to handle success messages with different types (I think, not 100% sure).
EDIT 2:
Here is a short bit of commander:
trait Commander {
def handleSuccess(message: SuccessMessage){
//based on SuccessMessage.ActorType, do different stuff
}
class SuccessMessage(val actorType: ActorType, val payload: Option[Any])
class SuccessMessage(val actorType: ActorType, val payload: Option[T])
EDIT 3: Here is a description of the workflow to better explain the problem.
Commander send msg to Poller
Poller sends SuccessMessage(self, List[String]) to Commander
Commander sends List[String] to Processor
Processor sends SuccessMessage(self, File) to Commander
Commander sends File to Uploader
Uploader sends SuccessMessage(self, Boolean) to Commander
and so on.
Therefore, we need SuccessMessage to take different types.
Unless T has some type bounds that allow the compiler to assume certain things about its behavior, you will have to cast instances of T to some concrete type to use them for any explicit purpose. (Basically same issue as Any)
You might want to look at type-classes. Then you can define some kind of handler for each type, and match the incoming payload to the handler using an implicit type-class instance. (see https://github.com/mpilquist/simulacrum library)
EDIT: Example here -> https://gist.github.com/phaistos/51f0405a2f25812a5780
Basically you end up with a typeclass like:
#typeclass trait CommanderHandler[A] {
def handle(payload: A): Unit
}
And then you make an instance for each type you want to use as a payload:
implicit val handlerInt: CommanderHandler[Int] = new CommanderHandler[Int] {
def handle(payload: Int) { /* use the payload here */ }
}
And then you can make a function like this to handle them:
def consumePayload[T](t: T)(implicit h: CommanderHandler[T]) {
h.handle(t)
}
The implicit you create for the given type must be available at the call site for consumePayload. Basically you're just wrapping the handler for each type in a nice little bundle.
This is the neatest pattern ive found for such things so far. Hope it helps. Make sure you read the docs for simulacrum if you use it, you will need to do some imports after creating the typeclass to make it work.
EDIT: As an alternative you could also look at polymorphic methods via shapeless: https://github.com/milessabin/shapeless/wiki/Feature-overview:-shapeless-2.0.0#polymorphic-function-values
I'm willing how to implement an extensible dispatch mechanism in Scala.
For example:
I have a trait called Sender (with a method 'send') and a bunch of classes that implement that trait (MailSender, IPhoneSender, AndroidSender). On top of them there is a class which implements the same trait but dispatches the message to the above senders depending the type of the message.
I know I can use pattern matching, but my problem with that approach is about extensibility: If someone wants to add another sender (i.e. WindowsPhoneSender), he must add a new case to the pattern matching method (thus breaking the open-closed principle). I don't want developers to modify the library's code, so I need this to be as extensible as possible.
I thought about a chain of responsibility approach (in Java I would do that), but is there a better way in Scala? (My knowledge in Scala is limited, but I know the Scala compiler does a lot of magical things)
Thanks!
It would be clearer if you gave a more concrete use case, but you might be looking for the typeclass pattern:
case class AndoidMessage()
case class WindowsMessage()
trait Sender[M]{
def send(message: M)
}
implicit object AndroidSender extends Sender[AndroidMessage]{...}
implicit object WindowsSender extends Sender[AndroidMessage]{...}
def mySendMethod[M: Sender](message: M) = {
// use the implicit Sender[M] to send the message
}
//AndroidSender is resolved implicitly
mySendMethod(new AndroidMessage())
//third party can define their own message and their own
//implicit sender for it (perhaps in a companion object
//so it's resolved automatically)
case class BeosMessage()
object BeosMessage{
implicit object BMSender extends Sender[BeosMessage]{...}
}