In scala source I can see this code:
@implicitNotFound(msg = \"Cannot prove that ${From} <:< ${To}.\")
sealed abstract class <:<[-From, +To] extends
Most of the time when you want to ensure that A <:< B
(or more correctly, you want to ensure that A <: B
using an evidence of type A <:< B
), it is because you actually have a value of type A
and want to be able to treat it as an instance of type B
.
When you have a value x: A
, proving via the presence of an implicit value that A
is a sub-type of B
won't magically change the type of x
to B
.
But for all intents and purpose <:<
actually allows this because it is also a function that just returns its argument (it is basically the identity, with just an added - and slightly hidden - cast).
This way when your method get passed an implicit value of type A <:< B
, what you get is actually also a suitable implicit conversion from A
to B
(implicitly converting x:A
to a value of type B
).
In the case when you don't actually need to convert anything, well that does not really matter whether <:<
extends Function1
or not.
The same rationale applies to =:=
.
UPDATE: In response to "In the case of =:=, Why would I want to convert values of type A to value of type A ?":
You should first note that even in the case of <:<
there is the same apparent contradiction: surely if A <: B
I can treat any value of type A
as a value of type B
(this is pretty much the definition of sub-typing).
Say we have the following generic method:
class Foo {
def hello() { println("hello!") }
}
def f[T]( value: T )(implicit e: T <:< Foo){
value.hello()
}
class Bar extends Foo
f( new Bar )
When compiling f
the compiler only knows that value
has some type T
.
Nothing tells the compiler that T
will always be a sub-type of Foo
.
So if it were not for the fact that e: T <:< Foo
also provides an implicit conversion from T
to Foo
,
then the call value.hello()
would fail because T
is just some type that the compiler does not know
anything about.
It is only by careful design that having an implicit value e: T <:< Foo
in scope happens if and only if T <: Foo
.
But the compiler has no idea of this, so from his point of view T
and Foo
are unrelated.
Thus we have to provide him a way to convert values of type T
to Foo
, which is done by the T <:< Foo
evidence itself.
As I said, the same rationale applies to =:=
: having an instance of T =:= Foo
gives no clue to the compiler about the fact
that T = Foo
, so the conversion must be provided to him.