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