How does the <: <operator work in Scala?

Scala has a class <:<that witnesses type restrictions. From Predef.scala:

  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]

An example of how it is used is in the toMapmethod TraversableOnce:

def toMap[T, U](implicit ev: A <:< (T, U)): immutable.Map[T, U] =

What I do not understand is how it works . I understand that it is A <:< Bsyntactically equivalent to type <:<[A, B]. But I don’t understand how the compiler can find an implicit such type if and only if A <: B. I suppose the call asInstanceOfin the definition $conformsmakes this possible somehow, but how? Also, is it important to use a single instance of an abstract class, and not just use it object?

+4
1

, :

trait Foo
trait Bar extends Foo

, Bar Foo:

val ev = implicitly[Bar <:< Foo]

-Xprint:typer, :

private[this] val ev: <:<[Bar,Foo] =
  scala.this.Predef.implicitly[<:<[Bar,Foo]](scala.this.Predef.$conforms[Bar]);

, $conforms[Bar] , . , Bar <:< Bar, <:< , Bar <:< Foo, .

( - , Scala , , , .)

, , Bar String:

val ev = implicitly[Bar <:< String]

-Xlog-implicits, :

<console>:9: $conforms is not a valid implicit value for <:<[Bar,String] because:
hasMatchingSymbol reported error: type mismatch;
 found   : <:<[Bar,Bar]
 required: <:<[Bar,String]
       val ev = implicitly[Bar <:< String]
                          ^
<console>:9: error: Cannot prove that Bar <:< String.
       val ev = implicitly[Bar <:< String]
                          ^

Bar <:< Bar, Bar String, Bar <:< String, , . $conforms - , <:< ( , ), .


: <:<[-From, +To] , . singleton Any <:< Any - val , , , , .

+11

All Articles