That's only "all you have to do" in the sense that you can make anything
compile by casting it. Making it compile is not the goal, making it
work is.
> Is it just being strict type in this case?
It's telling you that this is unsound.
> Also I am assuming that
>
> val boxOfString = fruitBasket.asInstanceOf[MyContainer[String]]
> boxOfString.set("Bob")
>
> works because String is an AnyRef and since I am contravariant that
> means I can essentially put anything in there.
No, it "works" because you cast it. Those two lines would work equally
well if MyContainer were invariant or covariant. The actual storage
cell in MyContainer can hold anything, and once you abandon type safety
with the casts it won't stop you from putting anything there. You'll
discover why this is a bad idea as soon as you try to get an orange out
of the basket and find bob lounging in there instead.
val fruitbasket = new MyContainer(new Orange)
public void set( a: java.lang.Object ) { ... }
thus there is no ClassCastException when setting the banana. It would occur once you try to call a method on the item that would require it to be an Orange.
best, -sciss-
The way counter-variance works is that MyContainer[Fruit] is a subtype of MyContainer[Orange] AND also a subtype of MyContainer[Banana]…. So there is no common type of the container between MyContainer[Orange] and MyContainer[Banana]… you can’t stuff Bananas in an Orange container… but you can still stuff a Banana in a MyContainer[Fruit]... cause’ it’s a Fruit… but you still end up with a MyContainer[Fruit].
Your example doesn’t really have any bearing on contra or co-variance. It wouldn’t work if you did [+A] either… because the container type was inferred to be [Orange], when instantiated and won’t change.
Why the compiler won’t let you do M[+A] is because of the set method
scala> class M[+A] { def set (a:A) {} }
<console>:6: error: covariant type A occurs in contravariant position in type A of value a
class M[+A] { def set (a:A) {} }
BUT – you can’t stuff Bananas in a container of Oranges, not matter what you do…
…short of hacking it that is, which is what you did J with the casting.
-Stefan
2011/4/11 Razvan Cojocaru <p...@razie.com>:
Under C-H Isomorphism, this corresponds to:
forall A B. A -> B
Let's write the truth table:
A B A->B
0 0 1
0 1 1
1 0 0 <-- logical inconsistency!
1 1 1
The rules are off (QED). It is a "lie", or "logically inconsistent."
As for contravariance and covariance, these correspond to contramap and
map respectively (for some functor F):
def contramap[A, B](f: A => B, b: F[B]): F[A]
def map[A, B](f: A => B, a: F[A]): F[B]
In the case of scala's variance annotations these correspond to using
the inheritance relationship for the first argument of the two
aforementioned methods.
That is to say, for contravariance, if you have a way to go from A => B
(by inheritance), then you have a way to go from F[B] to F[A] (by
inheritance). Similarly for map.
--
Tony Morris
http://tmorris.net/