Tuesday, March 30, 2010

Variant Positions 1

An additional topic on variance to finish up the major points on the topic. The previous two posts: contain required information for following this post.

In-, co- and contra- variance are the three types of variance expressible in Scala. I showed how this affects assignments and arguments being pass to methods in the last two topics. This looks at how the different types of variance influences how classes can be defined. In the last post we saw how the compiler complained about a method definition in a covariant class because the compiler recognized that such a definition was inherently dangerous and must be prohibited. The example was:
  1. scala> class Output[+A] {def write(a : A) = () /*do write*/ }
  2. < console>:5: error: covariant type A occurs in contravariant position in type A of value a
  3.        class Output[+A] {def write(a : A) = () /*do write*/ }
  4.                                    ^

For an class like Output it does not make sense to have A be covariant so we changed A to be contravariant. However suppose we have a collection type class.
  1. class Verified[+A] (assertion : (A) => Boolean, value : A){
  2.     assert(assertion(value))
  4.     def a = value
  5.     def a_=(a : A) = new Verified(assertion, a)
  6. }

The previous definition is not legal because value and a in the parameter of a_= "occur in a contravariant position." What to do? Making A contravariant isn't an option:
  1. class Verified[+A <: V,V](assertion : (V) => Booleanval value : A){
  2.     assert(assertion(value))
  3. /*
  4. this is the key.  Restrict possible types of
  5. A Since B is a super (or equal) type of A
  6. */
  7.     def update[ B >: A <: V](a : B) = new Verified(assertion, a)
  8. }
  9. // example useage
  10. scala> def notNull(obj : AnyRef) = obj != null
  11. notNull: (obj: AnyRef)Boolean
  12. scala> val v = new Verified(notNull, "hi")
  13. v: Verified[java.lang.String,AnyRef] = Verified@307b37df
  14. scala> val newV = v update (new Object())
  15. newV: Verified[java.lang.Object,AnyRef] = Verified@36f72f09
  16. // 3 is not legal because the type parameter 'V' is AnyRef.  Int is a subclass of Any NOT AnyRef
  17. scala> val newV = v update (3)           
  18. < console>:8: error: inferred type arguments [Any] do not conform to method update's type parameter bounds [B >: java.lang.String <: AnyRef]
  19.        val newV = v update (3)
  20.                   ^

No comments:

Post a Comment