type constraints - How does the <:< operator work in Scala? -
in scala there's class <:< witnesses type constraint. predef.scala:
sealed abstract class <:<[-from, +to] extends (from => to) serializable private[this] final val singleton_<:< = new <:<[any,any] { def apply(x: any): = x } implicit def $conforms[a]: <:< = singleton_<:<.asinstanceof[a <:< a] an example of how it's used in tomap method of traversableonce:
def tomap[t, u](implicit ev: <:< (t, u)): immutable.map[t, u] = what don't understand how works. understand a <:< b syntactically equivalent type <:<[a, b]. don't how compiler can find implicit of type if , if a <: b. assume asinstanceof call in definition of $conforms making possible somehow, how? also, significant singleton instance of abstract class used, instead of using object?
suppose we've got following simple type hierarchy:
trait foo trait bar extends foo we can ask proof bar extends foo:
val ev = implicitly[bar <:< foo] if run in console -xprint:typer, we'll see following:
private[this] val ev: <:<[bar,foo] = scala.this.predef.implicitly[<:<[bar,foo]](scala.this.predef.$conforms[bar]); so compiler has picked $conforms[bar] implicit value we've asked for. of course value has type bar <:< bar, because <:< covariant in second type parameter, subtype of bar <:< foo, fits bill.
(there's magic involved here in fact scala compiler knows how find subtypes of type it's looking for, it's generic mechanism , isn't surprising in behavior.)
now suppose ask proof bar extends string:
val ev = implicitly[bar <:< string] if turn on -xlog-implicits, you'll see this:
<console>:9: $conforms not valid implicit value <:<[bar,string] because: hasmatchingsymbol reported error: type mismatch; found : <:<[bar,bar] required: <:<[bar,string] val ev = implicitly[bar <:< string] ^ <console>:9: error: cannot prove bar <:< string. val ev = implicitly[bar <:< string] ^ the compiler tries bar <:< bar again, since bar isn't string, isn't subtype of bar <:< string, it's not need. $conforms place compiler can <:< instances (unless we've defined our own, dangerous), quite refuses compile nonsense.
to address second question: <:<[-from, +to] class necessary because need type parameters type class useful. singleton any <:< any value defined object—the decision use val , anonymous class arguably little simpler, it's implementation detail shouldn't ever need worry about.
Comments
Post a Comment