This is an odd little fellow in akka.testkit.TestFSMRef:
class TestFSMRef[S, D, T <: Actor](
system: ActorSystem,
props: Props,
supervisor: ActorRef,
name: String)(implicit ev: T <:< FSM[S, D])
What is that <:< symbol? It turns out that it comes from Predef, thus:
sealed abstract class <:<[-From, +To] extends (From => To) with Serializable
private[this] final val singleton_<:< = new <:<[Any,Any] { def apply(x: Any): Any = x }
implicit def $conforms[A]: A <:< A = singleton_<:<.asInstanceOf[A <:< A]
The documentation says:
Requiring an implicit argument of the type `A <:< B` encodes the generalized constraint `A <: B`.
So, A is a subclass of B. Got it. But how is that enforced for each and every child/parent relationship?
Well, there is a single, implicit $conforms[A] lingering in the ether that insists that A is a superclass or same as A. That's what A <:< A is saying. This is using a type infix operator for syntactic sugar and is equivalent to <:<[A, A].
"A is a superclass or same as A"? This in itself is not terribly useful. However, <:<[B, A] also must be possible if and only if B is a superclass of A because <:< is contravariant in its first type (-From) and covariant it its second (+To). That is, <:<[B, A] is a subtype of <:<[A, A] so everything compiles.
So, going back to our original Akka code, the type T <:< FSM[S, D] is enforcing T being a subclass of FSM[S, D] by virtue of there implicitly existing T <:< T and the only way this is satisfied without compilation errors is T <: FSM[S, D].
No comments:
Post a Comment