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:
  1. class Verified[+A <: V,V](assertion : (V) => Booleanprivate var value : A){
  2.     assert(assertion(value))
  3.     
  4.     def a = value
  5. // update is illegal.  See the example below
  6.     def update[ B >: A <: V](a : B) = value = a
  7. }
  8. def notNull(obj : AnyRef) = obj != null
  9. val v = new Verified(notNull, "hi")
  10. /*
  11. Up to this point everything looks ok but the next line
  12. will assign an object to value which is a reference to a String
  13. */
  14. 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:
  1. scala> class X[+A](val x :A)
  2. defined class X
  3. scala> class Y[A](var a: A) extends X[A](a)
  4. defined class Y
  5. scala> val x: X[Any] = new Y[String]("hi")
  6. x: X[Any] = Y@1732a4df
  7. scala> 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
  1. scala> def printList(l : List[Any]) = print(l mkString " :: ")
  2. printList: (l: List[Any])Unit
  3. scala> val buffer = Buffer(1,2,3)
  4. buffer: scala.collection.mutable.Buffer[Int] = ArrayBuffer(1, 2, 3)
  5. scala> printList(buffer)
  6. 1 :: 2 :: 3
  7. /*
  8. ++ is part of Iterable.  Since Iterable is covariant ++ 
  9. returns a new buffer it does not modify the existing buffer
  10. All mutators are only defined on invariant traits
  11. */
  12. scala> buffer ++ List(4)
  13. res16: scala.collection.mutable.Buffer[Int] = ArrayBuffer(1, 2, 3, 4)
  14. scala> res16 eq buffer
  15. res17: Boolean = false
  16. /*
  17. buffer defines += to add an element to the buffer
  18. so res27 is the same buffer with an extra element
  19. */
  20. scala> buffer += 10
  21. res27: buffer.type = ArrayBuffer(1, 2, 3, 10)
  22. scala> res27 eq buffer
  23. res28: Boolean = true

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))
  3.     
  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.                   ^

Saturday, March 27, 2010

Contravariance

Continuing on with variance and type parameters, this topic will discuss contravariance. See the post In- and Co- variance of type parameters for the intro material required for this topic.

Covariant parameters allow for an additional dimension of type compatibility:
  1. val l : List[Object] = List("this is legal")

Contravariance provides the opposite:
  1. // If the type parameter of list was contravariant this would be legal:
  2. val l : List[String] = List(new Object())

As covariance is indicated by a '+' before the type contravariance is indicated by a '-'
  1. scala> class X[-A]
  2. defined class X
  3. scala> val l : X[String] = new X[Object]
  4. l: X[String] = X@66201d6d

I can almost hear the "cool... but why?". Following the lead in the Programming In Scala book. Consider OutputStream first and a method in a Collection second. (The following code is illegal but consider it)
  1. class Output[+A] {def write(a : A) = () /*do write*/ }
  2. def writeObject(out : Output[Object]) = out.write("hello")
  3. /*
  4. Uh oh you this only is for outputting lists not Objects 
  5. (certainly not the String that is actually written)
  6. Runtime error for sure!
  7. */
  8. writeObject(new Output[List[String]])

The previous example (if it would compile) would explode because an Output that can only write lists is passed to the method. In the example a String is written to the Output object. The Output[List[String]] cannot handle that.

Fortunately the compiler sees the definition of the class and recognizes this is an error waiting to happen and makes it illegal:
  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.                                    ^

Consider the implications of making A contravariant?
  1. // The definition of object is now legal
  2. class Output[-A] {def write(a : A) = () /*do write*/ }
  3. // this is now a safe method definition since the parameter of Output must be a Object or a super class
  4. def writeObject(out : Output[Object]) = out.write("hello")
  5. // Now this is illegal as it should be
  6. scala> writeObject(new Output[List[String]])
  7. < console>:8: error: type mismatch;
  8.  found   : Output[List[String]]
  9.  required: Output[java.lang.Object]
  10.        writeObject(new Output[List[String]])
  11.        
  12. // this is legal... 
  13. scala> writeObject(new Output[Any])

In this example Output[Any] can be passed to the method. This makes sense. If the Output object knows how to write Any oject then it knows how to write an Object; its all good.

Wednesday, March 24, 2010

In- and Co- variance of type parameters

In Java most parameterized types are considered to be "invariant". What does that mean? Here is an example to explain:
  1. /*
  2. This is an example of a parameterized class that with an invariant parameter B
  3. In both Scala and Java parameters are invariant by default.
  4. */
  5. scala> class Invariant[B]
  6. defined class Invariant
  7. scala> var x : Invariant[Object] = new Invariant[Object]
  8. x: Invariant[java.lang.Object] = Invariant@2e0c5575
  9. /*
  10. Note: Invariant[String] cannot be assigned to Invariant[Object]
  11.       even though logically it seems like it should be.
  12.       This is the effect of invariance.  Covariant parameters do not have
  13.       this restriction.
  14. */
  15. scala> var x : Invariant[Object] = new Invariant[String]
  16. < console>:6: error: type mismatch;
  17.  found   : Invariant[String]
  18.  required: Invariant[java.lang.Object]
  19.  var x : Invariant[Object] = new Invariant[String]
  20.                              ^
  21. scala> class Sub[A] extends Invariant[A]   
  22. defined class Sub
  23. /*
  24. Since Sub is a subclass of Invariant it can be assigned
  25. (but not Sub[String])
  26. */
  27. scala> val x : Invariant[Object] = new Sub[Object]
  28. x: Invariant[java.lang.Object] = Sub@26ced1a8

Assignment compatibility has multiple dimensions: the object type and the types of the parameters. Unlike object type the compatibility of the type-parameters can be covariant, contravariant and invariant. Java has invariant parameters and that is demonstrated by the previous example. Covariant parameters allow subclassing. Contravariant parameters need their own topic.
  1. // The '+' indicates the parameter is covariant
  2. scala> class Covariant[+B]
  3. defined class Covariant
  4. scala> var x : Covariant[Object] = new Covariant[Object]
  5. x: Covariant[java.lang.Object] = Covariant@315cb235
  6. // Now this is legal
  7. scala> var x : Covariant[Object] = new Covariant[String]
  8. x: Covariant[java.lang.Object] = Covariant@26e2e276
  9. /*
  10. Warning: The following is not legal because 
  11.          you cannot supply an invariant parameter 
  12.          with a covariant value.
  13. */
  14. scala> class Sub[+A] extends Invariant[A]
  15. < console>:7: error: covariant type A occurs in invariant position in type [+A]Invariant[A] with ScalaObject{def this(): Sub[A]} of class Sub
  16.        class Sub[+A] extends Invariant[A]
  17.              ^
  18. scala> class Sub[+A] extends Covariant[A]
  19. defined class Sub
  20. scala> class Sub[A] extends Covariant[A] 
  21. defined class Sub

Monday, March 22, 2010

Implicit '=' operator

Continuing on with operators, There is a special type of operator in Scala. It is an operator that ends with =. If a class has operation (methods with an operator identifer) the = can be appended to the effectively creating a new method. In truth a new method is not created instead the compiler rewrites the line.

For example. If a method (like Int) defines + then a method call += can be used. It can be used to mutate a variable:
  1. scala> var i = 1
  2. i: Int = 1
  3. scala> i += 1
  4. scala> i
  5. res3: Int = 2

To illustrate this is not a special case for Int the next example defines several operations and demonstrates in place variable mutation.
  1. scala> case class MyClass(i:Int) {      
  2.      | def +(j:Int) = new MyClass(j + i)
  3.      | def -(j:Int) = new MyClass(i - j)
  4.      | def ^(j:Int) = MyClass(j)
  5.      | def +|(j:Int) = new MyClass(j + i / 3)
  6.      | }
  7. defined class MyClass
  8. scala> var c = MyClass(1)
  9. c: MyClass = MyClass(1)
  10. scala> c+=6
  11. scala> c
  12. res5: MyClass = MyClass(7)
  13. scala> c -= 2
  14. scala> c
  15. res7: MyClass = MyClass(5)
  16. scala> c ^= 10
  17. scala> c
  18. res23: MyClass = MyClass(10)
  19. scala> c +|= 5
  20. scala> c
  21. res25: MyClass = MyClass(8)

Here are several more examples using existing classes in Scala. They are all immutable examples.
  1. scala> var l = Set(1,2,3) 
  2. l: scala.collection.immutable.Set[Int] = Set(1, 2, 3)
  3. scala> l += 10
  4. scala> l
  5. res7: scala.collection.immutable.Set[Int] = Set(1, 2, 3, 10)
  6. scala> var seq = Seq(5,6,3)
  7. seq: Seq[Int] = List(5, 6, 3)
  8. scala> seq :+= 10
  9. scala> seq                 
  10. res9: Seq[Int] = List(5, 6, 3, 10)
  11. scala> seq +:= 10   
  12. scala> seq       
  13. res11: Seq[Int] = List(10, 5, 6, 3, 10)
  14. scala> var list = List(32)
  15. list: List[Int] = List(32)
  16. scala> list ::= 12
  17. scala> list
  18. res13: List[Int] = List(12, 32)

Note: assignment operators can also be defined as methods to mutate an object
  1. scala> case class MyClass(var i:Int) {
  2.      | def += (j:Int) = { i+=j ; this }
  3.      | }
  4. defined class MyClass
  5. scala> val m = MyClass(6)
  6. m: MyClass = MyClass(6)
  7. scala> m += 7
  8. res0: MyClass = MyClass(13)
  9. scala> m += 9
  10. res1: MyClass = MyClass(22)
  11. scala> res1 eq m
  12. res2: Boolean = true

Friday, March 19, 2010

Operators

Since Scala allows one to define the behavior of operators there are some rules involving operators and assignment like +=. One of the standard method calls in most languages is i += 1.

Since i+=1(no spaces) is also valid, Scala has some rules regarding how statements like i+=1 should be broken up. Obviously we know it should be 'i' '+=' and '1'. So there is a special class of characters called operators. I don't know all of them but a few are: + - ^ * / % ! | & =( ':' is sort of part of this group but has some special properties as well).

These characters can be method names but they cannot be combined with other identifier characters.

Update: These characters can be combined with other identifier characters if there is an under score so:
  1. def x+ = 3   // not valid
  2. def x_+ = 3  // valid
  3. def +x = 3   // not valid

However these characters are special because they can be combined in a special way with '=' for a special assignment construct as shown in the next post.

(end update)

  1. scala> case class MyClass(i:Int) {
  2.      | def +(j:Int) = new MyClass(j + i)
  3.      | def -(j:Int) = new MyClass(i - j)
  4.      | def ^(j:Int) = MyClass(j)
  5.      | def +|(j:Int) = new MyClass(j + i / 3)
  6.      | }
  7.  
  8.  scala> val c = MyClass(3)
  9.  c: MyClass = MyClass(3)
  10.  scala> c + 4
  11.  res26: MyClass = MyClass(7)
  12.  scala> c-2 
  13.  res27: MyClass = MyClass(1)
  14.  scala> c -6
  15.  res28: MyClass = MyClass(-3)
  16.  scala> c ^ 3
  17.  res29: MyClass = MyClass(3)
  18.  scala> c+|5
  19.  res31: MyClass = MyClass(6)

Wednesday, March 17, 2010

Geoscript.scala

This is a bit of a departure from the standard daily-scala format, but it is one of the elements I had always invisioned. This topic takes a look at Geoscript.scala. (Github repo is at: http://github.com/dwins/geoscript.scala)

Geoscript has been given a Scala implementation. It is based on the Geotools Java library and thus far provides a script interface to access some of the basic spatial functions.

For setting up the console with the required libraries follow the instructions at: http://geoscript.org/scala/quickstart.html#quickstart

Here is an example of Geoscript in action:

  1. scala> import org.geoscript.GeoScript._
  2. import org.geoscript.GeoScript._
  3. scala> import org.geoscript.geometry._
  4. import org.geoscript.geometry._
  5. scala> val line = LineString((10, 10), (20, 20), (30, 40))
  6. line: org.geoscript.geometry.LineString = LINESTRING (10 10, 20 20, 30 40)
  7. /*
  8. create a polygon by buffering the line (essentially expanding the line by 10 units that is degrees if not otherwise specified)
  9. */
  10. scala> val poly = line buffer 10
  11. poly: org.geoscript.geometry.Geometry = POLYGON ((11.781455848733053 25.923591472464004, 21.05572809000084 44.47213595499958, 22.100060210309515 46.13114600374718, 23.447982586398712 47.55453954995706, 25.04769531727891 48.68761637789669, 26.837722339831622 49.48683298050514, 28.74927391943886 49.921475911950004, 30.708890200906794 49.97484208812642, 32.64126422950409 49.6448806768120...
  12. // query the area of the polygon
  13. scala> poly.area
  14. res0: Double = 1041.9912814842407
  15. // get the centroids of the polygon and line
  16. scala> line.centroid
  17. res1: org.geoscript.geometry.Point = POINT (21.12574113277207 24.188611699158105)
  18. scala> poly.centroid
  19. res2: org.geoscript.geometry.Point = POINT (20.79088988611118 24.43096430943361)
  20. /*
  21. Obviously the polygon and line intersect since the polygon is a buffer of the line
  22. */
  23. scala> poly.intersects(line)
  24. res3: Boolean = true
  25. scala> val poly2 = Geometry.fromWKT("POLYGON ((10 10, 10 20, 20 20, 20 15, 10 10))")
  26. poly2: org.geoscript.geometry.Geometry = POLYGON ((10 10, 10 20, 20 20, 20 15, 10 10))
  27. // less trivial intersects operation
  28. scala> poly intersects poly2
  29. res3: Boolean = true
  30. // not make a new geometry from the intersection of the two geometries
  31. scala> val intersecting = poly intersection poly2
  32. intersecting: org.geoscript.geometry.Geometry = POLYGON ((10 10, 10 20, 20 20, 20 15, 10 10))
  33. scala> intersecting.area 
  34. res6: Double = 75.0
  35. scala> import org.geoscript.projection._
  36. import org.geoscript.projection._
  37. /*
  38. None of the previous geometries has a projection associated.  
  39. A new geometry can have one created with a projection by using the in(Projection) method
  40. */ 
  41. scala> val latLongPoly = poly2 in Projection("epsg:4326")
  42. latLongPoly: org.geoscript.geometry.Geometry = POLYGON ((10 10, 10 20, 20 20, 20 15, 10 10))
  43. // now reproject the latlong projection to a french projection 
  44. scala> latLongPoly in Projection("epsg:21781")
  45. res12: org.geoscript.geometry.Geometry = POLYGON ((950650.7690658928 -4203986.192880551, 900363.7533498043 -2900002.601715782, 2061411.5566836582 -2774908.8442438124, 2174910.791185147 -3393231.5380846346, 950650.7690658928 -4203986.192880551))

Tuesday, March 16, 2010

Assert, Require, Assume

Very simple but useful are the methods assert, require and assume which are built into the Predef object. As you might expect they are methods for performing certain checks during runtime to verify certain conditions. They do not use the Java assert framework and therefore are always evaluated regardless of whether or not assertions are enabled.

Update: Scala 2.8 has an annotation called elidable that will (when 2.8 is complete) allow one to remove method calls at compile time by setting a compiler flag. The assert, etc... methods are all marked with this flag and as a result can be removed at compile time for production environments.

Scala2.8
  1. scala> var called = 0
  2. called: Int = 0
  3. scala> called
  4. res0: Int = 0
  5. /*
  6. assert, require and assume have call by name parameters so the message is only 
  7. calculated when the assertion fails.
  8. */
  9. scala> assert (called == 0, {called += 1; println("called is not 0")})
  10. scala> require (called == 0, {called += 1; println("called is not 0")})
  11. scala> assume (called == 0, {called += 1; println("called is not 0")}) 
  12. scala> called = 1
  13. called: Int = 1
  14. // demonstrating that the method is in fact called when the assertion fails
  15. scala> assert (called == 0, {called += 1; println("called is not 0")}) 
  16. called is not 0
  17. java.lang.AssertionError: assertion failed: ()
  18. at scala.Predef$.assert(Predef.scala:95)
  19. ...
  20. scala> called
  21. res4: Int = 2
  22. /*
  23. Require is intended to be used as a precondition of a method so 
  24. it throws an IllegalArgumentException, not an AssertionError
  25. */
  26. scala> require (called == 0, {called += 1; println("called is not 0")})
  27. called is not 0
  28. java.lang.IllegalArgumentException: requirement failed: ()
  29. at scala.Predef$.require(Predef.scala:117)
  30. ...
  31. scala> called                                                          
  32. res6: Int = 3
  33. scala> assume (called == 0, {called += 1; println("called is not 0")}) 
  34. called is not 0
  35. java.lang.AssertionError: assumption failed: ()
  36. at scala.Predef$.assume(Predef.scala:107)
  37. ...
  38. scala> called                                                         
  39. res8: Int = 4


scala 2.7.7
  1. /*
  2. In Scala 2.7 the parameter is evaluated before the 
  3. method is called so the side effect of the message causes
  4. the assertion to fail
  5. */
  6. scala> assert (called == 0, {called += 1; println("called is not 0")})
  7. called is not 0
  8. scala> called
  9. res2: Int = 1

Monday, March 15, 2010

Unzip

_ Scala 2.8 only tip _

Unzip is a handy companion to partition.
- Partition divides a traversable into two traversables by a boolean predicate.
- Unzip divides a traversable into two by dividing each element into two parts (each becomes an element in one traversable). If an element is a Tuple2 then each tuple is divided into two otherwise a function is required to divide an element into two.

  1. // basic usage
  2. scala> List((1,2),(2,3)).unzip
  3. res2: (List[Int], List[Int]) = (List(1, 2),List(2, 3))
  4. /* 
  5. tuples can be of different types 
  6. and the resulting traversables reflect the differing types
  7. */
  8. scala> List((2,"a"),(3,"b")).unzip
  9. res3: (List[Int], List[java.lang.String]) = (List(2, 3),List(a, b))
  10. // Maps are Traversable[Collection] so unzip works with them
  11. scala> Map(1 -> 2, 3 -> 4).unzip
  12. res1: (scala.collection.immutable.Iterable[Int], scala.collection.immutable.Iterable[Int]) = (List(1, 3),List(2, 4))
  13. // Of course sets result in sets and duplicates are collected to a single element
  14. scala> Set((1,2),(2,2)).unzip
  15. res7: (scala.collection.immutable.Set[Int], scala.collection.immutable.Set[Int]) = (Set(1, 2),Set(2))
  16. /*
  17. Arbitrary elements can be unziped if a method is provided to decompose each element
  18. */
  19. scala> List("one word""another word").unzip {e => (e takeWhile {_ != ' '}, e dropWhile {_ != ' '})} 
  20. res6: (List[String], List[String]) = (List(one, another),List( word,  word))
  21. /*
  22. The following shows the same function 
  23. applied with map.  It results in a single
  24.  list of Tuples rather than two lists of single elements
  25.  */
  26. scala> List("one word""another word").map {e => (e takeWhile {_ != ' '}, e dropWhile {_ != ' '})}  
  27. res8: List[(String, String)] = List((one, word), (another, word))

Friday, March 12, 2010

Multiple Argument Implicit Conversions

Suppose you are creating a DSL and you want to implicitly convert 2 values to a particular object:
  1. val v : SomeObject = (2, 3)

This is easily attained. In this example we will support the previous example as well as the standard 1 object to another implicit conversion.
  1. val v : SomeObject = 2

Example:
  1. // first lets define a class
  2. scala> case class Randomly(x : Int, y : Double)
  3. defined class Randomly
  4. // the normal conversion
  5. scala> implicit def intToRandomly(i : Int) = new Randomly(i,0.0)
  6. intToRandomly: (i: Int)Randomly
  7. /*
  8. now a tuple for the other conversion.
  9. Important:  The two conversions must have different names. At least that is the case in Scala 2.8
  10. */
  11. scala> implicit def tupleToRandomly(i : (IntDouble)) = new Randomly(i._1, i._2)
  12. tupleToRandomly: (i: (IntDouble))Randomly
  13.  
  14. scala> val r1 : Randomly = 4                                                     
  15. r1: Randomly = Randomly(4,0.0)
  16. scala> val r2 : Randomly = (4, 6.0)
  17. r2: Randomly = Randomly(4,6.0)
  18. /*
  19. Suppose you want to do
  20. val r : Randomly = (4,4)
  21. you might think to implicitly convert from in to double
  22. */
  23. scala> implicit def intToDouble(i : Int) = i.toDouble
  24. intToDouble: (i: Int)Double
  25. // implicit chaining is not permitted
  26. scala> val r3 : Randomly = (4, 6)                    
  27. < console>:10: error: type mismatch;
  28.  found   : (IntInt)
  29.  required: Randomly
  30.        val r3 : Randomly = (4, 6)
  31. // Here is the legal option
  32. scala> implicit def intTupleToRandomly(t: (Int,Int)) = new Randomly(t._1,t._2.toDouble) 
  33. intTupleToRandomly: (t: (IntInt))Randomly
  34. scala> val r3 : Randomly = (4, 6)                                                      
  35. r3: Randomly = Randomly(4,6.0)

Wednesday, March 10, 2010

How to reverse a map

Suppose you wish to take a map and swap the keys with values. The stackoverflow question Elegant way to revers a map in scala offers some good suggestions

  1. scala> val nodupes = Map(1 -> "a", 2-> "b", 3 -> "c")
  2. nodupes: scala.collection.immutable.Map[Int,java.lang.String] = Map((1,a), (2,b), (3,c))
  3. // Scala 2.8+
  4. scala> nodupes map {_.swap}                          
  5. res4: scala.collection.immutable.Map[java.lang.String,Int] = Map((a,1), (b,2), (c,3))
  6. // Scala 2.7
  7. scala> Map() ++ (nodupes map {case (k,v) => (v,k)})  
  8. res5: scala.collection.immutable.Map[java.lang.String,Int] = Map((a,1), (b,2), (c,3))
  9. // watch out if the values have duplicates you will loose information:
  10. scala> val dupes = Map(1 -> "a", 2-> "b", 3 -> "b")  
  11. dupes: scala.collection.immutable.Map[Int,java.lang.String] = Map((1,a), (2,b), (3,b))
  12. scala> dupes map {_.swap}                          
  13. res6: scala.collection.immutable.Map[java.lang.String,Int] = Map((a,1), (b,3))
  14. // a way to not loose any data
  15. scala> dupes groupBy {_._2} map {case (key,value) => (key, value.unzip._1)}     
  16. res12: scala.collection.Map[java.lang.String,scala.collection.immutable.Iterable[Int]] = Map((a,List(1)), (b,List(2, 3)))
  17. // I wanted to do the following for performance:
  18. scala> dupes.view groupBy {_._2} map {case (key,value) => (key, value.unzip._1)}
  19. java.lang.UnsupportedOperationException: IterableView((1,a), (2,b), (3,b)).newBuilder
  20. at scala.collection.TraversableViewLike$class.newBuilder(TraversableViewLike.scala:40)
  21. at scala.collection.IterableLike$$anon$1.newBuilder(IterableLike.scala:363)
  22. at scala.collection.TraversableLike$$anonfun$groupBy$1.apply(TraversableLike.scala:370)
  23. // but as you can see a view cannot yet be grouped.  Perhaps in the future.

Monday, March 8, 2010

Lazy man's random test data

A quick tip for generating some random testdata.

Note: This is a poor man's solution to using ScalaCheck. If you can handle the dependency I would really recommend using that library.

  1. scala> object Options extends Enumeration {                       
  2.      | val ONE, TWO, THREE, FOUR = Value                          
  3.      | }
  4. defined module Options
  5. /*
  6. Randomly select zero or more elements from the options enumeration
  7. */
  8. scala> Options.values.filter {_ => util.Random.nextBoolean} mkString ", "
  9. res2: String = TWO, FOUR
  10. /*
  11. Select a random string.  
  12. Warning:  there is no restriction on the characters so control characters are likely
  13. */
  14. scala> util.Random.nextString(10)
  15. res5: String = ??????????
  16. /*
  17. ASCII string is oftern more useful for test data.  This selects a random string up to 13 characters long
  18. */
  19. scala> util.Random.nextASCIIString(13)
  20. res6: java.lang.String = RVPD\#_HqJ8:o
  21. /*
  22. This creates a sequence of 10 random strings
  23. */
  24. scala> 1 to 10 map {_ => util.Random.nextASCIIString(13)}
  25. res7: scala.collection.immutable.IndexedSeq[java.lang.String] = IndexedSeq(;E8|Q8H8RI;Q=, vM-X;"ksBr\:c, SKyz{uXNQ5E]X, =Jd8_ll08)s%e, gRCs)6wj%C-YF, `x;2Zru?l*c%@, XE*/Rx9:qPfpm, s|u,e.un+-Xm(, M,TpX9Dq-6$+^, w;exER&#0|}Ya)

Saturday, March 6, 2010

Blocks within if statements

his is another topic that examines the consistency of Scala. This topic examines blocks in if statements. It is related to Blocks within for comprehensions and Temporary Variables during object creation.
  1. // standard if
  2. if(1 > 2) -1 else 0
  3. // since blocks return a value you can use a block within the if statement 
  4. // (not sure when you would want to but...)
  5. if ({ val x = 1
  6.       val y = 2
  7.       x == y }) 1 else 2

Thursday, March 4, 2010

Zip with a constant value

A simple tip for zipping a List (or other collection) with a single value.

  1. scala> Stream.continually("h") zip List(1,2,3,4)
  2. res2: scala.collection.immutable.Stream[(java.lang.String, Int)] = Stream((h,1), ?)
  3. scala> res2 mkString ","
  4. res3: String = (h,1),(h,2),(h,3),(h,4)
  5. scala> List(1,2,3,4) zip Stream.continually("h")
  6. res4: List[(Int, java.lang.String)] = List((1,h), (2,h), (3,h), (4,h))

Wednesday, March 3, 2010

Functions using case statements

A further tip regarding using case statements to construct functions. If a case statement is assigned to a Function it will construct a Function object not a PartialFunction.

I suppose the question is why do you care about this since PartialFunction is a Function. The fact is that a PartialFunction is a Function1. But using a case statement you can construct a Function4 very easily.
  1. scala> def run(f : Function1[Any,Unit]) = println(f.isInstanceOf[PartialFunction[_,_]])
  2. run: (f: (Any) => Unit)Unit
  3. /*
  4. since run expects a Function calling run as shown here will make a 
  5. Function object not a PartialFunction Object
  6. */
  7. scala> run({case f => ()}) 
  8. false
  9. scala> def pf(f : PartialFunction[Any,Unit]) = println(f.isInstanceOf[PartialFunction[_,_]]) 
  10. pf: (f: PartialFunction[Any,Unit])Unit
  11. // Now a PartialFunction will be created
  12. scala> pf({case f => ()})                                                                         
  13. true
  14. scala> def run(f : Function2[Int,String,Unit]) = f(1,"2")                                     
  15. run: (f: (IntString) => Unit)Unit
  16. /*
  17. This demonstrates why it is important that a case creates a Function
  18. when assigned to a Function. PartialFunctions are Function1 objects
  19. but the following statement is creating a Function2 object.
  20. */
  21. scala> run({                 
  22.      | case (1,b) => println(b)
  23.      | case (a,b) => println(a,b)
  24.      | })
  25. 2

Tuesday, March 2, 2010

Methods on PartialFunction

This topic inspects the methods defined in the PartialFunction Object.
  1. scala> type PF = PartialFunction[Int,Int]
  2. defined type alias PF
  3. // the two partial functions that we will use for the examples
  4. scala> val pf1 : PF = {case 1 => 2}                      
  5. pf1: PF = < function1>
  6. scala> val pf2 : PF = {case 2 => 3}                      
  7. pf2: PF = < function1>
  8. /*
  9. As is well known, when a PartialFunction is called with a value
  10. it must be defined at that value or bad things will happen
  11. */
  12. scala> pf1 isDefinedAt 1  
  13. res14: Boolean = true
  14. scala> pf1 isDefinedAt 2
  15. res15: Boolean = false
  16. scala> pf1(2)
  17. scala.MatchError: 2
  18. at $anonfun$1.apply(< console>:5)
  19. at $anonfun$1.apply(< console>:5)
  20. at .< init>(< console>:7)
  21.     ...
  22. scala> pf1(1)
  23. res5: Int = 2
  24. /*
  25. It is possible to compose two partial functions so first one partialFunction is called and then the next
  26. */
  27. scala> (pf1 andThen pf2) isDefinedAt 2 
  28. res16: Boolean = false
  29. scala> (pf1 andThen pf2) isDefinedAt 1
  30. res17: Boolean = true
  31. scala> (pf1 andThen pf2)(2)
  32. scala.MatchError: 2
  33. at $anonfun$1.apply(< console>:5)
  34. at $anonfun$1.apply(< console>:5)
  35. at scala.PartialFunction$$anon$2.apply(PartialFunction.scala:59)
  36. at .< init>(< console>:8)
  37.     ...
  38. scala> (pf1 andThen pf2)(1)
  39. res8: Int = 3
  40. /*
  41. An alternative way of combining PartialFunctions is to 'or' them
  42. */
  43. scala> (pf1 orElse pf2) isDefinedAt 1
  44. res18: Boolean = true
  45. scala> (pf1 orElse pf2) isDefinedAt 2
  46. res19: Boolean = true
  47. scala> (pf1 orElse pf2) isDefinedAt 3
  48. res20: Boolean = false
  49. scala> (pf1 orElse pf2)(1) 
  50. res9: Int = 2
  51. scala> (pf1 orElse pf2)(2)
  52. res10: Int = 3
  53. /*
  54. Finally a PartialFunction can be easily converted to a function that returns 
  55. an Option
  56. */
  57. scala> pf1.lift
  58. res21: (Int) => Option[Int] = < function1>
  59. scala> pf1.lift(1)
  60. res11: Option[Int] = Some(2)
  61. scala> pf1.lift(2)
  62. res12: Option[Int] = None

Monday, March 1, 2010

NullPointer when mixed traits (Warning)

This tip is mainly to document a 'GOTCHA' that I got caught by recently. It basically goes like this:

Trait Y extends(or has self-type) X. Trait X defines some abstract method 'm'. The initialization code in Y accesses 'm'. Creation of an object new X with Y results in: *Boom* NullPointerException (on object creation).

The example in code:
  1. scala> trait X { val x : java.io.File }
  2. defined trait X
  3. scala> trait Y {self : X => ; val y = x.getName} 
  4. defined trait Y
  5. scala> new X with Y { val x = new java.io.File("hi")}
  6. java.lang.NullPointerException
  7. at Y$class.$init$(< console>:5)
  8. at $anon$1.< init>(< console>:7)
  9. ...

At a glance it seems that x should override the abstract value x in trait X. However the order in which traits are declared is important. In this case first Y is configured then X. Since X is not yet configured Y throws an exception. There are several ways to work around this.
Option 1:
  1. trait X {val x : java.io.File}
  2. trait Y {self : X => ; val y = x.getName}
  3. /*
  4. Declaring Y with X will work because Y is initialized after X
  5. but remember that there may
  6. be other reasons that X with Y is required.  
  7. Method resolution is one such reason
  8. */
  9. new Y with X { val x = new java.io.File("hi")}

Option 2:
  1. trait X { val x : java.io.File }
  2. trait Y {self : X => ; def y = x.getName}
  3. /*
  4. Since method y is a 'def' x.getName will not be executed during initialization.
  5. */
  6. scala> new X with Y { val x = new java.io.File("hi")}
  7. res10: java.lang.Object with X with Y = $anon$1@7cb9e9a3

Option 3:
  1. trait X { val x : java.io.File }
  2. trait Y {self : X => ; lazy val y = x.getName}
  3. /*
  4. 'lazy val' works for the same reason 'def' works: x.getName is not invoked during initialization
  5. */
  6. scala> new X with Y { val x = new java.io.File("hi")}
  7. res10: java.lang.Object with X with Y = $anon$1@7cb9e9a3

Option 4:
  1. trait X {val x : java.io.File }
  2. trait Y extends X {def y = x.getName}
  3. /*
  4. if Y extends X then a new Y can be instantiated
  5. */
  6. new Y {val x = new java.io.File("hi")}

Two more warnings. First, the same error will occur whether 'x' is a def or a val or a var.
  1. trait X { def x : java.io.File }   
  2. trait Y {self : X => ; val y = x.getName}     
  3. new X with Y { val x = new java.io.File("hi")}

Second warning: In complex domain models it is easy to have a case where Y extends X but the final object is created as: new X with Y{...}.

You will get the same error here because (I think) the compiler recognized that Y is being mixed in with X and therefore the X will be initialized as after Y instead of before Y.

First the code:
  1. trait X { def x : java.io.File }   
  2. trait Y extends X { val y = x.getName}        
  3. new X with Y { val x = new java.io.File("hi")}

If the code instantiated new Y{...} the initialization would be X then Y. Because X can only be initialized once, the explicit declaration of new X with Y forces Y to be initialized before X. (X can only be initialized once even when it appears twice in the hierarchy).

This is a topic called linearization and will be addressed in the future.