score:2

Accepted answer

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:

  1. Revert to the state where Disconnect was a singleton object, without an associated case class.
  2. Remove the Disconnect definition altogether. Add case class NewDisconnect instead. Now every occurrence of Peer.Disconnect will become a proper error.
  3. Replace all Peer.Disconnect by Peer.NewDisconnect(foo)
  4. Rename NewDisconnect to Disconnect.

score:1

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.

score:1

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.


Related Query

More Query from same tag