Scala type evidences

后端 未结 1 687
鱼传尺愫
鱼传尺愫 2021-01-21 23:38

In scala source I can see this code:

@implicitNotFound(msg = \"Cannot prove that ${From} <:< ${To}.\")
sealed abstract class <:<[-From, +To] extends          


        
相关标签:
1条回答
  • 2021-01-22 00:05

    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.

    0 讨论(0)
提交回复
热议问题