i am looking into scala's type level programming and have got some knowledge about it.But i have no idea why class <:< needs to extend from (From => To),i wrote the following code in REPL .
trait <:<[-T, +U] // just 'plain' generic trait
// an implicit object will looked up by compiler
implicit def implicitAgent[A]: <:<[A, A] = new <:<[A,A] {}
def myFunc[T,U](one:T, two:U)(implicit ev: T <:< U): Unit = {
println(one, two)
class Base {
override def toString: String = "base"
}
class Derived extends Base {
override def toString: String = "Derived"
}
myFunc(new Derived, new Base)
and it works and prints:
(Derived,base)
So my question is what's the class <:<'s design decision?why it needs to extends From => To ?
Because that way implicit ev: T <:< U
also acts as an implicit conversion from T
to U
that can automatically upcast any value of type T
to type U
.
With <:<
defined in Predef
:
scala> trait Foo
defined trait Foo
scala> def myFunc[T](t: T)(implicit ev: T <:< Foo): Foo = t
myFunc: [T](t: T)(implicit ev: T <:< Foo)Foo
With your <:<
:
scala> trait <:<[-T, +U]
defined trait $less$colon$less
scala> implicit def implicitAgent[A]: <:<[A, A] = new <:<[A,A] {}
implicitAgent: [A]=> A <:< A
scala> def myFunc[T](t: T)(implicit ev: T <:< Foo): Foo = t
<console>:14: error: type mismatch;
found : T
required: Foo
def myFunc[T](t: T)(implicit ev: T <:< Foo): Foo = t
^
Once you have a proof that a value is an instance of U
(i.e. its type T
is a subtype of type U
) it's very likely that you will want to use that value as an instance of U
, otherwise why did you need the proof in the first place? If <:<
is a function you can do that automatically.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With