Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How exactly does the Scala implementation of <:<, <%<, =:= work in the compiler?

I see now that there's a related question asking what these operators (<:<, <%<, =:=) do here:

What do <:<, <%<, and =:= mean in Scala 2.8, and where are they documented?

But I'm still confused about their implementation. In particular, I assume that once you've placed an implicit parameter that asserts a particular relationship, then you can use variables as if they've automatically been cast properly, e.g. this will compile:

class Foo[T](a: T) {
  def splitit(implicit ev: T <:< String) = a split " "
}

But how does this actually work in the compiler? Is there some magic compiler support for these operators, and if not, what's the underlying mechanism that allows it to infer this sort of relationship from the definition? (Was this mechanism added specifically to allow these operators to work, and how specific is it to these particular operators?) It seems a little magical that you can place an extra implicit parameter like this which somehow changes the compiler's interpretation of a type.

like image 521
Urban Vagabond Avatar asked Jul 15 '12 00:07

Urban Vagabond


1 Answers

The implementation is a bit tricky, but nothing magical.

There is an implicit method in Predef which can provide a value of type A <:< A for any A

implicit def conforms[A]: A <:< A

When you try to invoke your method, it looks for an implicit value of type T <:< String. The compiler will check to see if conforms[T] is a valid value. Let's say T is Nothing then there will be an implicit value Nothing <:< Nothing in scope which will allow your method call to compile. Due to the way <:< is defined

sealed abstract class <:<[-From, +To]

From is allowed to vary up and To is allowed to vary down. So a Nothing <:< Nothing is still a valid Nothing <:< String since Nothing is a subtype of String. A String <:< String would also be a valid Nothing <:< String since String is a supertype of Nothing (but the compiler seems to always pick just the first type).

You can call methods of String on it because <:< also extends => aka Function1 and serves as an implicit conversion from T to String, which basically ends up doing a safe cast.

=:= is the same thing except it is defined without any variance annotations, so the types must match exactly.

<%< is defined like <:< but the implicit method is a bit different, it adds another parameter to specify a view bound

implicit def conformsOrViewsAs[A <% B, B]: A <%< B

It is also deprecated.

like image 111
Kaito Avatar answered Oct 23 '22 11:10

Kaito