Wednesday, March 31, 2010

Variant Positions 2

This is a continuation of post: Variant Positions 1

...

My first attempt at the Verified was to make it a mutable object (my Java tourettes kicking in). But it cannot be covariant and mutable. Look at the code to see why:
`class Verified[+A <: V,V](assertion : (V) => Boolean, private var value : A){    assert(assertion(value))        def a = value// update is illegal.  See the example below    def update[ B >: A <: V](a : B) = value = a}def notNull(obj : AnyRef) = obj != nullval v = new Verified(notNull, "hi")/*Up to this point everything looks ok but the next linewill assign an object to value which is a reference to a String*/v update (new Object())`
For Verified to be mutable A must be invariant. If you look at the Mutable collections in Scala they are all invariant.

Here is an interesting example of both invariant and covariant type parameters in a class hierarchy:
`scala> class X[+A](val x :A)defined class Xscala> class Y[A](var a: A) extends X[A](a)defined class Yscala> val x: X[Any] = new Y[String]("hi")x: X[Any] = Y@1732a4dfscala> x.asInstanceOf[Y[String]].a="ho"`
This example is perfectly legal because no matter how X[Any] is used no illegal assignment in Y can occur. The interesting thing is that the object can be used in covariant usecases when only X is required. This is now the collections in Scala can work.

Here is a little example of collections invariance and covariance in action. In List the parameter is covariant but in Buffer it is invariant
`scala> def printList(l : List[Any]) = print(l mkString " :: ")printList: (l: List[Any])Unitscala> val buffer = Buffer(1,2,3)buffer: scala.collection.mutable.Buffer[Int] = ArrayBuffer(1, 2, 3)scala> printList(buffer)1 :: 2 :: 3/*++ is part of Iterable.  Since Iterable is covariant ++ returns a new buffer it does not modify the existing bufferAll mutators are only defined on invariant traits*/scala> buffer ++ List(4)res16: scala.collection.mutable.Buffer[Int] = ArrayBuffer(1, 2, 3, 4)scala> res16 eq bufferres17: Boolean = false/*buffer defines += to add an element to the bufferso res27 is the same buffer with an extra element*/scala> buffer += 10res27: buffer.type = ArrayBuffer(1, 2, 3, 10)scala> res27 eq bufferres28: Boolean = true`

1 comment:

1. seriously, this series has been blowing my mind a little bit.

thanks.