Scala type system 可以有type constraints, 比如[ T <: Int ] 要 type T 是 Int後代, 不過有些更進階的符號, 看起來會以為是operator, 事實上是一個type的 syntax sugar進階應用, <:< 就是一個最好例子
<:< type
先簡單看一段code
scala> def peek[C, A](col: C)(implicit ev: C <:< Traversable[A]) =
| (col.head, col)
foo: [C,A](col: C)(implicit ev: <:<[C,Traversable[A]])(A, C)
比較要注意的地方是 implicit ev: C <:< Traversable[A]
看起來是需要一個 implicit value ev他的type是C
然後C 又接著 <:< Traversable[A]
結果上來說
限制C是 subtype of Traversable[A]
這樣看起來<:< 就跟 <: subtype constraints一樣嘛
但實際上<:< 是一個type, 並非compiler層級的syntax
<:< type定義如下
/**
* An instance of `A <:< B` witnesses that `A` is a subtype of `B`.
* Requiring an implicit argument of the type `A <:< B` encodes
* the generalized constraint `A <: B`.
*
* @note we need a new type constructor `<:<` and evidence `conforms`,
* as reusing `Function1` and `identity` leads to ambiguities in
* case of type errors (`any2stringadd` is inferred)
*
* To constrain any abstract type T that's in scope in a method's
* argument list (not just the method's own type parameters) simply
* add an implicit argument of type `T <:< U`, where `U` is the required
* upper bound; or for lower-bounds, use: `L <:< T`, where `L` is the
* required lower bound.
*
* In part contributed by Jason Zaugg.
*/
@implicitNotFound(msg = "Cannot prove that ${From} <:< ${To}.")
sealed abstract class <:<[-From, +To] extends (From => To) with Serializable
private[this] final val singleton_<:< = new <:<[Any,Any] { def apply(x: Any): Any = x }
// The dollar prefix is to dodge accidental shadowing of this method
// by a user-defined method of the same name (SI-7788).
// The collections rely on this method.
implicit def $conforms[A]: A <:< A = singleton_<:<.asInstanceOf[A <:< A]
@deprecated("Use `implicitly[T <:< U]` or `identity` instead.", "2.11.0")
def conforms[A]: A <:< A = $conforms[A]
/** An instance of `A =:= B` witnesses that the types `A` and `B` are equal.
*
* @see `<:<` for expressing subtyping constraints
*/
是定義在scala.Predef裡面, 可參考source code
source code有點複雜, 可以參考簡化版本
sealed abstract class <:<[-From, +To] extends
(From => To) with Serializable
implicit def conforms[A]: A <:< A = new (A <:< A) {
def apply(x: A) = x
}
直白上來說C <:< Traversable[A]算是syntax sugar
原本應該是 <:<[C , Traversable[A] ]
那麼<:<定義裡面透過variance 來實現subtype constraints
type <:<[-From, +To]定義上是透過variance trick 來驗證subtype relationship
再去注意到
implicit def conforms[A]: A <:< A = new (A <:< A) {
def apply(x: A) = x
}
Trick point:
因為conform接受 A <:< A (也就是 <:<[A, A])那麼在<:<[-From, +To] 定義中明確表示 -From是 Contravariant
可接受super type variance
所以只要 B <: A, 就 <:<[B, A] 可以轉換成conform的 <:<[A, A]
以上的推論都是compiler 在type system 的推導
因此要構成 <:<[B, A]這個type, 就是要確保 B 是A的 subtype
所以<:< 不是 operator
是一個type, 透過type variance, 來實作subtype的語意
然後再加上syntax sugar
<:<[B, A] => B <:< A
才達到這樣的目的
沒有留言:
張貼留言