简体   繁体   中英

Is it possible to change the variance of a base class/trait in Scala?

I would like to derive from Scala's immutable Map. It is defined as such:

trait Map[A, +B]

Unfortunately, my implementation needs to be invariant in B. I tried the following, but without success:

def +(kv : (A, B)) : MyMap[A, B] = { ... }

override def +[B1 >: B](kv : (A, B1)) : MyMap[A, B1] =
    throw new IllegalArgumentException()

Maybe there is a trick with @uncheckedVariance ?

The trouble is that if you derive an invariant version from an immutable map, you'll break type safety. For example:

val dm = DiotMap(1 -> "abc")
val m: Map[Int, Any] = dm

This declaration is valid, because Map is covariant. If your collection cannot handle covariance, what will happen when I use m ?

Getting rid of covariance altogether would of course be unsound, and is not allowed. Given m: Map[A, String] , and v: Any , you can do val mm: Map[A, Any] = m + v . This is what Map definition says, and all implementors must follow. Your class may be invariant, but it must implement the full covariant interface of Map.

Now redefining + to throw an error is a different story (not very sound yet). The problem with your new + method is that after generics erasure, it has the same signature than the other + method. There is a trick: add in implicit parameter, so that you have two parameters in the signature, which makes it different from the first one.

def +(kv : (A,B))(implicit useless: A <:< A) : MyMap[A,B]

(it doesn't really matter what implicit parameter you're looking for, as long as one is found. implicit useless: Ordering[String] works just as well)

Doing that, you have the usual problem with overloading. If you add a B without the compiler knowing it to be so, the failing method will be called. It might be better to perform a type check there so that B instances are accepted whatever. That would require getting a Manifest[B] in your map.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM