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?
Getting rid of covariance altogether would of course be unsound, and is not allowed.
Given
m: Map[A, String], andv : Any, you can doval mm : Map[A, Any] = m + v. This is whatMapdefinition 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.(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.