Showing posts with label beginner. Show all posts
Showing posts with label beginner. Show all posts

Friday, April 16, 2010

A quick note. ScalaDays Rocks! Wish you were here :)

This topic just demonstrates a cute little trick that can occasionally be quite useful:
  1. scala> List(1,2,3) ++ Some(4)
  2. res0: List[Int] = List(1, 2, 3, 4)
  3. scala> List(1,2,3) ++ None   
  4. res1: List[Int] = List(1, 2, 3)

Options are implicitly converted to Iterables, so Options can be appended to collections.
  1. scala> val x : Iterable[Int] = None       
  2. x: Iterable[Int] = List()
  3. scala> val x : Iterable[Int] = Some(4)
  4. x: Iterable[Int] = List(4)

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)

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))

Wednesday, February 3, 2010

Chaining Options with orElse

A simple but handy use for Option is to select the first valid option from a selection of possible choices. Sound vague? Well it is because it can be used in many different situations. The one presented here is: the program needs a directory that can be set by the user either as a system variable, and environment variable or the default value. The java code is a nightmare of if (xxx == null) statements. The Scala code is beautiful.
  1. scala> val propsTemplates = Option(System getProperty "MVN_CREATOR_TEMPLATES")
  2. propsTemplates: Option[java.lang.String] = None
  3. scala> val envTemplates = Option(System getenv "MVN_CREATOR_TEMPLATES")
  4. envTemplates: Option[java.lang.String] = None
  5. scala> val defaultHome = Some(System getProperty "user.home")
  6. defaultHome: Some[java.lang.String] = Some(/Users/jeichar)
  7. /* 
  8. chain the different options together in order of priority and get the value
  9. I am taking a small liberty here because I am assuming that user.home is always available
  10. */
  11. scala> propsTemplates.orElse(envTemplates).orElse(defaultHome).get
  12. res0: java.lang.String = /Users/jeichar
  13. // alternative form:
  14. scala> propsTemplates orElse envTemplates orElse defaultHome get
  15. res1: java.lang.String = /Users/jeichar

Tuesday, January 26, 2010

Guard Sugar

This topic is a simple tip for a cleaner syntax for guards. Guards/filters are statements in for-comprehensions and case statements that guard or filter matches. Often you will see them as follows:
  1. scala> for (i <- 1 to 10; if (i % 2 == 1)) yield i
  2. res0: scala.collection.immutable.IndexedSeq[Int] = IndexedSeq(1, 3, 5, 7, 9)
  3. scala> util.Random.nextInt(10) match {
  4.      | case i if(i>5) => println("hi")
  5.      | case _ => println("low")
  6.      | }
  7. low

However you have the option to apply a little sugar to the statements cleaning them up a little:
  1. scala> for (i <- 1 to 10; if i % 2 == 1) yield i  
  2. res2: scala.collection.immutable.IndexedSeq[Int] = IndexedSeq(1, 3, 5, 7, 9)
  3. scala> util.Random.nextInt(10) match {          
  4.      | case i if i>5 => println("hi")           
  5.      | case _ => println("low")                 
  6.      | }
  7. hi

As you can see the brackets are optional. That is because in both cases the brackets are not required for the parser to determine the start and end of the guard statements. They are added so that the "normal" syntax used in the typical if statements will compile.
  1. scala> 10 match { case i if i == 1 || i == 10 => "obviously this is a match"
  2. res4: java.lang.String = obviously this is a match
  3. /*
  4. In case statements you can split the if almost any way you want because it is very clearly bound by the if and the => that is required for all case statements with a guard
  5. */
  6. scala> 10 match { case i if i == 1 ||                                        
  7.      | i == 10 => "obviously this is a match"}
  8. res5: java.lang.String = obviously this is a match
  9. scala> 10 match {        
  10.      | case i
  11.      | if
  12.      | i == 1
  13.      | ||
  14.      | i == 10 
  15.      | => "matched"
  16.      | }
  17. res6: java.lang.String = matched
  18. /*
  19. For-comprehensions are not as flexible since it is harder for the compiler to determine where the guard ends. So try to keep it on one line or otherwise make it a function.  That is probably good advice for case statements as well.
  20. */
  21. scala> for { 
  22.      | x <- 1 to 10
  23.      | if
  24.      | x > 10
  25.      | || x == 2 } yield x
  26. < console>:5: error: '<-' expected but integer literal found.
  27.        || x == 2 } yield x
  28.                ^
  29. < console>:5: error: illegal start of simple expression
  30.        || x == 2 } yield x
  31.                  ^
  32. scala> for {              
  33.      | x <- 1 to 10       
  34.      | if x == 1 || x == 10 } yield x
  35. res7: scala.collection.immutable.IndexedSeq[Int] = IndexedSeq(1, 10)

Wednesday, December 16, 2009

Specs BDD Testing framework

This is the second Scala test framework topic and focuses on the excellent Specs framework. The other topic was on ScalaTest, another excellent testing framework for Scala.

Specs is focussed on BDD testing (Behaviour Driven Design) and is the inspiration for ScalaTests WordSpec. From what I understand Specs was in-turn inspired by RSpec the Ruby BDD testing framework.

Specs has some truly unique features to it which we will encounter in future topics. But for now just the basics. The following example tests a couple of Scala's XML support in order to demonstract the general pattern followed when writing Specs' tests.

  1. # scala -classpath ~/.m2/repository/org/scala-tools/testing/specs/1.6.1/specs-1.6.1.jar
  2. scala> import org.specs._
  3. import org.specs._
  4. scala> object XmlSpec extends Specification {
  5.      |  val sample = <library>
  6.      |         <videos>
  7.      |         <video type="dvd">Seven</video>
  8.      |         <video type="blue-ray">The fifth element</video>
  9.      |         <video type="hardcover">Gardens of the moon</video>
  10.      |         </videos>
  11.      |         <books>
  12.      |         <book type="softcover">Memories of Ice</book>
  13.      |         </books>
  14.      |         </library>
  15.      |  "Scala XML" should {
  16.      |   "allow xpath-like selection" in {
  17.      |    (sample \\ "video").size must be (3)    
  18.      |   }
  19.      |   "select child nodes" in {
  20.      |    // This test fails because child is a sequence not a string
  21.      |    // See the results of the tests
  22.      |    sample.child must contain (<videos/>)
  23.      |   }
  24.      |  }
  25.      |  }
  26. defined module XmlSpec
  27. scala> XmlSpec.main(Array[String]())
  28. Specification "XmlSpec"
  29.   Scala XML should
  30.   + allow xpath-like selection
  31.   x select child nodes <-- x indicates failure.
  32.     'ArrayBuffer(
  33.                    , <videos>
  34.                    <video type="dvd">Seven</video>
  35.                    <video type="blue-ray">The fifth element</video>
  36.                    <video type="hardcover">Gardens of the moon</video>
  37.                    </videos>, 
  38.                    , <books>
  39.                    <book type="softcover">Memories of Ice</book>
  40.                    </books>, 
  41.                    )' doesn't contain '<videos></videos>' (< console>:24)
  42. Total for specification "XmlSpec":
  43. Finished in 0 second, 52 ms
  44. 2 examples, 2 expectations, 1 failure, 0 error

Wednesday, November 25, 2009

Varargs

Both Java and Scala have varargs. In Scala the syntax for a varargs argument is def method (param:String*). In the off-chance you are not aware of what varargs are; they allow an arbitrary number of values to be passed to the method. Some restrictions on when varargs can be used are:
  • The vararg parameter must be the last parameter in the list
  • There can not be default values for any parameters in the method containing the varargs (Scala 2.8+)

From the caller's point of view; varargs can be called as follows: method("p1""p2""p3") where the number of values is not limited. However, the () must be used.

In Java (if I remember right) only arrays can be passed in place of varargs:
  1. class C {
  2.   public static void main(String... args) {
  3.     System.out.println(args.length)
  4.   }
  5. }
  6. String[] args = new String[]{"arg1""arg2"}
  7. C.main (args)

However Scala is more general and allows any sequence to be passed to varargs, with a caveat. When a sequence is passed to varargs a hint must be provided to indicate that you are intending to have the sequence be expanded to be the varargs.
  1. def method (args:Int*) = println(args)
  2. val list = List(1,2,3)
  3. method (list:_*)  // note the use of _*

Examples:
  1. scala> def method(varargs:Int*)(more:String*) = println(varargs,more)
  2. method: (Int*)(String*)Unit
  3. scala> method(1,2,3,4)("one")
  4. (Array(1, 2, 3, 4),Array(one))
  5. scala> method(1,2,3,4)       
  6. < console>:6: error: missing arguments for method method in object $iw;
  7. follow this method with '_' if you want to treat it as a partially applied function
  8.        method(1,2,3,4)
  9.        ^
  10. scala> method(1,2,3,4)()
  11. (Array(1, 2, 3, 4),Array())
  12. scala> method()("one")  
  13. (Array(),Array(one))
  14. scala> method("one")  
  15. < console>:6: error: type mismatch;
  16.  found   : java.lang.String("one")
  17.  required: Int
  18.        method("one")
  19.               ^
  20. scala> method()()     
  21. (Array(),Array())
  22. scala> val method2 = method(1,2,3)_  
  23. method2: (String*) => Unit = < function>
  24. scala> val paramList = List("hi","ho")
  25. paramList: List[java.lang.String] = List(hi, ho)
  26. scala> method2(paramList)
  27. < console>:8: error: type mismatch;
  28.  found   : List[java.lang.String]
  29.  required: String
  30.        method2(paramList)
  31.                ^
  32. scala> method2(paramList:_*)
  33. (Array(1, 2, 3),List(hi, ho))
  34. scala> val range = (1 to 5) map {_.toString} 
  35. range: RandomAccessSeq.Projection[java.lang.String] = RangeM(1, 2, 3, 4, 5)
  36. scala> method2(range:_*)                     
  37. (Array(1, 2, 3),RangeM(1, 2, 3, 4, 5))

Thursday, November 19, 2009

Options

Scala is forced to have a "null" value because it interoperates with Java. However unlike Java APIs the recommended way to hand cases where there may or may not be a value (IE a return value) is to return an Option object. Compare the Scala and Java idioms for handling a possible null (or None) return value:

Note: The Option class have been updated in Scala 2.8 so I am going to use some of the scala 2.8 methods. Most of the examples will work with Scala 2.7 but not all; the principal is the same for 2.7 and 2.8.

Java:
  1. /**
  2.  * Returns the annotation with the given name or null if there is no annotation
  3.  * on the objects class with the given name.
  4.  */
  5. public static < A extends java.lang.annotation.Annotation> Annotation annotation(Object obj, Class< A> annotationCls) {
  6.   return obj.getClass().getAnnotation(annotationCls)
  7. }

Scala:
  1. import java.lang.annotation.Annotation
  2. /**
  3.  * Returns the annotation with the given name.
  4.  */
  5. def annotation[A <: Annotation](obj:Object, annotationCls:Class[A]) : Option[Annotation] = {
  6.    Option (obj.getClass.getAnnotation (annotationCls))
  7. }

In the Scala version it is obvious the use of the API (and the compiler) that there are two types of legal return types. Some or None and the compiler will force you to deal with this fact. Where in Java it is very easy to forget to check for null.

Also not that it is very easy to Wrap a null in an Option using the Option objects apply method. If the parameter is a null then None is return otherwise Some is returned.

The other important aspect is how to deal with the Option object and obtain the data from the object if it is present. This is both simple and non-simple. There are a large number of possible useage patterns that can be applied to it.

Examples:
  1. scala> import java.lang.annotation.Annotation
  2. import java.lang.annotation.Annotation
  3. kscala> def annotation[A <: Annotation](obj:Object, annotationCls:Class[A]) : Option[Annotation] = { 
  4.      |    Option (obj.getClass.getAnnotation (annotationCls))                                      
  5.      | }
  6. annotation: [A <: java.lang.annotation.Annotation](obj: java.lang.Object,annotationCls: Class[A])Option[java.lang.annotation.Annotation]
  7. // strings do not have the Documented annotation so None is returned
  8. scala> annotation("x", classOf[java.lang.annotation.Documented])                                   
  9. res0: Option[java.lang.annotation.Annotation] = None
  10. // None is not defined
  11. scala> res0.isDefined
  12. res1: Boolean = false
  13. // None IS empty 
  14. scala> res0.isEmpty
  15. res26: Boolean = true
  16. // We need a some example so LineNumberInputStream has Deprecated annotation
  17. // we will use that in order to 
  18. scala> val in = new LineNumberInputStream(new ByteArrayInputStream("hello".getBytes))
  19. in: java.io.LineNumberInputStream = java.io.LineNumberInputStream@8ca9a2d
  20. scala> annotation(in, classOf[Deprecated])                                           
  21. res2: Option[java.lang.annotation.Annotation] = Some(@java.lang.Deprecated())
  22. // Some(...) is always defined even if it contains null
  23. scala> res2.isDefined
  24. res3: Boolean = true
  25. scala> val nullSome = Some(null)
  26. nullSome: Some[Null] = Some(null)
  27. scala> nullSome.isDefined
  28. res28: Boolean = true
  29. // Some is never empty
  30. scala> res2.isEmpty
  31. res4: Boolean = false
  32. // You can also test particular values as follows
  33. scala> if(res0 == None) println("its ok to use")
  34. its ok to use
  35. scala> if (res2.map {a => "found"} == Some("found")) println ("it is deprecated dont use!")
  36. it is deprecated dont use!
  37. scala> res0 match {                                                       
  38.      | case None => println("its ok to use")                              
  39.      | case Some(x:Deprecated) => println ("it is deprecated dont use!"
  40.      | }
  41. its ok to use
  42. scala> res2 match {                                                      
  43.      | case None => println("its ok to use")                             
  44.      | case Some(x:Deprecated) => println ("it is deprecated dont use!")
  45.      | }
  46. it is deprecated dont use!
  47. scala> if(Some("hi") == Some("hi")) println("a match")    
  48. match
  49. scala> if(Some("hi") == Some("ho")) println("a match")
  50. // After you have tested you can use get to obtain the value
  51. // but becareful, you will get an exception if you forget to test.
  52. scala> res0.get
  53. java.util.NoSuchElementException: None.get
  54.                           at scala.None$.get(Option.scala:169)
  55.                           at scala.None$.get(Option.scala:167)
  56.                           at .< init>(< console>:12)
  57.                           at .< clinit>(< console>)
  58.                           [snip]
  59. scala> res2.get
  60. res10: java.lang.annotation.Annotation = @java.lang.Deprecated()
  61. // a potentially better way of optaining the value is to provide a default if 
  62. // the value does not exists
  63. scala> res2.getOrElse(classOf[java.lang.annotation.Documented])
  64. res13: java.lang.Object = @java.lang.Deprecated()
  65. scala> res0.getOrElse(classOf[java.lang.annotation.Documented])
  66. res14: java.lang.Object = interface java.lang.annotation.Documented
  67. // A Option is a "monad" (dont worry too much about the term if 
  68. // you dont know it) a very (VERY) simplified meaning of that is that 
  69. // option behaves a bit like a collection of size 1 or 0
  70. // you can use similar methods on an Option as a collection.  
  71. // So exists tests each element in the Option to see if it matches 
  72. // the function passed in as the parameter
  73. // res2 has an object that is an instanceOf Annotation 
  74. scala> res2.exists {_.isInstanceOf[Annotation]}  
  75. res7: Boolean = true
  76. // None always returns false to exists
  77. scala> res0.exists {_.isInstanceOf[Annotation]}
  78. res8: Boolean = false
  79. scala> res2.exists {_.toString == "hi"}
  80. res29: Boolean = false
  81. // Similarly you can use the filter method that is present in all collections
  82. scala> res2.filter {_.toString == "hi"}    
  83. res30: Option[java.lang.annotation.Annotation] = None
  84. scala> res2.filter {_.isInstanceOf[Annotation]}
  85. res32: Option[java.lang.annotation.Annotation] = Some(@java.lang.Deprecated())
  86. // apart from just filtering you can convert the type contained 
  87. // in the Option by using map to map from one type of Option to
  88. // another type of Option in this examples we map from 
  89. // Option[Annotation] to Option[String]
  90. scala> res0.map {_.toString}.getOrElse("does not exist")                        
  91. res15: java.lang.String = does not exist
  92. scala> res2.map {_.toString}.getOrElse("does not exist")
  93. res16: java.lang.String = @java.lang.Deprecated()
  94. // Another very handy and safe way to access the value is to use foreach
  95. // this will call the function with the parameter from the Option if
  96. // the Option is Some but a noop will occur if the Option is None.
  97. scala> res2.foreach { println _ }
  98. @java.lang.Deprecated()
  99. scala> res0.foreach { println _ }
  100. // orElse is simply a method to ensure that the Option is a Some
  101. scala> res0.orElse(Some(classOf[java.lang.annotation.Documented]))
  102. res22: Option[java.lang.Object] = Some(interface java.lang.annotation.Documented)
  103. scala> res2.orElse(Some(classOf[java.lang.annotation.Documented]))
  104. res23: Option[java.lang.Object] = Some(@java.lang.Deprecated())

Sunday, November 8, 2009

BigInt in Scala

One of the best examples of why it is so great to use Scala for API design is BigInt. Using BigInt in Java is a real headache because of the limitations of Java with regards to API design. Scala in comparison makes using BigInt no different than using Ints (with execution that there is not a BigInt literal).

  1. // BigInt objects can be created from ints
  2. scala> val x = BigInt(1500)
  3. x: BigInt = 1500
  4. // or longs
  5. scala> val y = BigInt(8839200231L)
  6. y: BigInt = 8839200231
  7. // or strings
  8. scala> val z = BigInt("1234566789008723457802308972345723470589237507")
  9. z: BigInt = 1234566789008723457802308972345723470589237507
  10. // then thanks to scala you can multiply/divide/add/subtract etc...
  11. // as if it was a Scala literal
  12. scala> x * y * z
  13. res0: BigInt = 16368874569886254973831932331037537269641764816982396175500
  14. // by importing implicits you can also directly multiply big ints with integers and longs
  15. // however remember to put the big in first so that the int is converted to big int
  16. // because you cannot do Int * BigInt.  It must be BigInt * Int
  17. scala> import BigInt._
  18. import BigInt._
  19. scala> x * y * z * 124
  20. res1: BigInt = 2029740446665895616755159609048654621435578837305817125762000

Thursday, November 5, 2009

Access modifiers (public, private, protected)

By default classes, objects and class members (fields, methods) are all public.
IE:
  1. object PublicObject {
  2.   val publicVal
  3.   var publicVar
  4.   def publicMethod = 1
  5. }

In this example everything is public. Similar to Java there is private and protected (there is no public because that is default). Private works as it does in Java but protected is dramatically different.
  • The first difference is that protected can have two forms: protected and protected[foo]. Where foo can be a class, package or object.

  • The second difference is that the non-parameterized protected for is only visible from subclasses not from the same package.
  1. scala> class Class1 {
  2.      | protected def pMethod = "protected"
  3.      | }
  4. defined class Class1
  5. scala> class Class2 { 
  6. // pMethod is not accessible because Class2 is not a subclass of Class1
  7.      | new Class1().pMethod 
  8.      | }
  9. <console>:6: error: method pMethod cannot be accessed in Class1
  10.        new Class1().pMethod
  11.                     ^
  12. scala> class Class3 extends Class1 {
  13. // also unlike Java, protected restricts to the same object
  14.      | new Class1().pMethod
  15.      | }
  16. <console>:6: error: method pMethod cannot be accessed in Class1
  17.        new Class1().pMethod
  18.                     ^
  19. scala> class Class3 extends Class1 {
  20.      | pMethod
  21.      | }
  22. defined class Class3

If the protected is parameterized then only classes that fall into the parameter category can access the parameter:
  1. scala> class Class1 {                                
  2. // protected[Class1] is equivalent to private
  3.      | protected[Class1] def method() = println("hi")
  4.      | method()
  5.      | }
  6. defined class Class1
  7. scala> new Class1()
  8. hi
  9. res0: Class1 = Class1@dc44a6d
  10. // this does not work because method is only accessible in Class1
  11. scala> class Class2 extends Class1 { method() }      
  12. <console>:5: error: not found: value method
  13.        class Class2 extends Class1 { method() }
  14.                                      ^
  15. scala> object Module {                                         
  16.      |   object Inner1 {                                         
  17.      |     protected[Inner1] def innerMethod = println("hi")       
  18.      |     protected[Module] def moduleMethod = println("moduleMethod")
  19.      |
  20.      |     object InnerInner { 
  21.      |       // InnerInner is within Inner1 so the access works
  22.      |       def callInner = innerMethod
  23.      |     }
  24.      |   }
  25.      |   // module method is protected[Module] so anything in Module can access it
  26.      |   def callModuleMethod = Inner1.moduleMethod
  27.      |
  28.      |   object Inner2 {
  29.      |     // Inner1.module method is protected[Module] and 
  30.      |     // Inner2 is within module so therefore has access
  31.      |     def callModuleMethod = Inner1.moduleMethod
  32.      |   }
  33.      | }
  34. defined module Module
  35. scala> Module.callModuleMethod
  36. moduleMethod
  37. scala> Module.Inner1.InnerInner.callInner
  38. hi
  39. scala> Module.Inner1.innerMethod         
  40. <console>:6: error: method innerMethod cannot be accessed in object Module.Inner1
  41.        Module.Inner1.innerMethod
  42.                      ^
  43. scala> Module.Inner1.moduleMethod
  44. <console>:6: error: method moduleMethod cannot be accessed in object Module.Inner1
  45.        Module.Inner1.moduleMethod

The following example shows how package access works in Scala 2.8. They have to be compiled as 2 files.

Root.scala:
  1. package root
  2. class Class1 {
  3.   protected[root] def rootMethod = println("rootMethod")
  4. }
  5. class Class2 {
  6.   // same package so this is legal
  7.   new Class1().rootMethod
  8. }


Subpackage.scala
  1. package root.sub
  2. class Class3 {
  3.   // Class3 is in a subpackage of root so 
  4.   // it can access all objects protected by
  5.   // protected[root] as well as objects
  6.   // protected by protected[root.sub]
  7.   new root.Class1().rootMethod
  8. }

Monday, November 2, 2009

Multiple Constructors

In Scala there is a primary constructor: class MyClass(constructorParam:Any). Unlike Java, that constructor must be called. The question that often arises is, "How can one define multiple constructors?" There is a simple way to do this, however often a factory companion object can be used to remove the need for multiple constructors. Factory Companion Objects are covered in a previous post but I will review the pattern here quickly.

First multiple constructors:
  1. scala> class HelloConstructor(param1:Int, param2:Int) {
  2.      | def this(onlyParam:Int) = this(onlyParam,onlyParam)
  3.      | def this(p1:String, p2:String, p3:String) = this(p1.length, p2.length + p3.length)
  4.      | def this(onlyParam:String) = this(onlyParam.length)
  5.      | }
  6. defined class HelloConstructor

In Java if a constructor calls another constructor that call must be the first statement in the constructor. Scala is the same except that in Scala the primary constructor must be called. Notice that all constructors call this(param1,param2) at some point. In addition any method defined in the class HelloConstructor is not available until after the primary constructor is invoked. The following examples are not valid.
  1. scala> class HelloConstructor(param1:Int, param2:Int) {                                  
  2.      | def x = 1
  3.      | def this() = this(x,3)
  4.      | }
  5. <console>:6: error: not found: value x
  6.        def this() = this(x,3)
  7. scala> class HelloConstructor(param1:Int, param2:Int) {
  8.      | def this() = {
  9.      | println("constructing")  // the REPL won't even let me finish method definition
  10. <console>:3: error: 'this' expected but identifier found.
  11.        println("constructing")
  12.        ^

Factory companion objects can be used to work around these restrictions:
  1. scala> class HelloConstructor(param1:Int, param2:Int)  
  2. defined class HelloConstructor
  3. scala> object HelloConstructor {                             
  4.      | def apply() = {
  5.      | println("constructing object")
  6.      | new HelloConstructor(1,2)
  7.      | }
  8.      | }
  9. defined module HelloConstructor
  10. scala> HelloConstructor()
  11. constructing object
  12. res1: HelloConstructor = HelloConstructor@5b0010ec

Since companion objects can access private members of the class the factory methods can be as powerful as a constructor without the restrictions.

One last idea that is useful when designing classes is Scala 2.8 default arguments:
  1. scala> class HelloConstructor(param1: Int = 1, param2: Int = 2)
  2. defined class HelloConstructor
  3. scala> new HelloConstructor()
  4. res0: HelloConstructor = HelloConstructor@7cd47880
  5. scala> new HelloConstructor(1)
  6. res1: HelloConstructor = HelloConstructor@3834a1c8
  7. scala> new HelloConstructor(param1 = 1)
  8. res2: HelloConstructor = HelloConstructor@3b3e3940
  9. scala> new HelloConstructor(param2 = 1)
  10. res3: HelloConstructor = HelloConstructor@6dee2ea8
  11. scala> new HelloConstructor(3,4)       
  12. res4: HelloConstructor = HelloConstructor@397b6074
  13. scala> new HelloConstructor(param1 = 3, param2=4)
  14. res5: HelloConstructor = HelloConstructor@20272fec

Friday, October 30, 2009

Groupby - collection processing

Iterator and Iterable have most of the most useful methods when dealing with collections. Fold, Map, Filter are probably the most common. But other very useful methods include grouped/groupBy, sliding, find, forall, foreach, and many more. I want to cover Iterable's groupBy method in this topic.

This is a Scala 2.8 and later method. It is similar to partition in that it allows the collection to be divided (or partitioned). Partition takes a method with returns a boolean and partitions the collection into two depending on a result. GroupBy takes a function that returns an object and returns a Map with the key being the return value. This allows an arbitrary number of partitions to be made from the collection.

Here is the method signature:
  1. def groupBy[K](f : (A) => K) : Map[K, This]

A bit of context is require to understand the three Type parameters A, K and This. This method is defined in a super class of collections called TraversableLike (I will briefly discuss this in the next topic.) TraversableLike takes two type parameters: the type of the collection and the type contained in the collection. Therefore in this method definition, 'This' refers to the collection type (List for example) and A refers to contained type (perhaps Int). Finally K refers to the type returned by the function and are the keys of the groups formed by the method.

Examples:
  1. scala> val groups = (1 to 20).toList groupBy {
  2.      | case i if(i<5) => "g1"
  3.      | case i if(i<10) => "g2"
  4.      | case i if(i<15) => "g3"
  5.      | case _ => "g4"
  6.      | }
  7. res4: scala.collection.Map[java.lang.String,List[Int]] = Map(g1 -> List(1, 2, 3, 4), g2 -> List(5, 6, 7, 8, 9), g3 -> List(10, 11, 12, 13, 14), g4 -> List(15, 16, 17, 18, 19, 20))
  8. scala> groups.keySet
  9. res6: scala.collection.Set[java.lang.String] = Set(g1, g2, g3, g4)
  10. scala> groups("g1")
  11. res7: List[Int] = List(1, 2, 3, 4)
  12. scala> val mods = (1 to 20).toList groupBy ( _ % 4 )
  13. mods: scala.collection.Map[Int,List[Int]] = Map(1 -> List(1, 5, 9, 13, 17), 2 -> List(2, 6, 10, 14, 18), 3 -> List(3, 7,
  14.  11, 15, 19), 0 -> List(4, 8, 12, 16, 20))
  15. scala> mods.keySet
  16. res9: scala.collection.Set[Int] = Set(1, 2, 3, 0)
  17. scala> mods(1)
  18. res11: List[Int] = List(1, 5, 9, 13, 17)

Thursday, October 1, 2009

Strings

This topic simply shows several things that can be done with strings. It is not exhaustive and focusses of things that cannot as easily be done with java strings.

Note: Because I am using Scala 2.7 we often need to use mkString to convert the processed string from a sequence of characters to a string. In scala 2.8 this is not required.

  1. /*
  2.    Making use of raw strings to create a multi line string
  3.    I add a | at the beginning of each line so that we can line up the quote nicely 
  4.    in source code then later strip it from the string using stripMargin
  5. */
  6. scala>val quote = """|I don-t consider myself a pessimist.                                                                                                
  7.      |                |I think of a pessimist as someone who is waiting for it to rain.
  8.      |                |And I feel soaked to the skin.
  9.      | 
  10.      |                |Leonard Cohen"""
  11. quote: java.lang.String = 
  12. |I don-t consider myself a pessimist. 
  13.                       |I think of a pessimist as someone who is waiting for it to rain.
  14.                       |And I feel soaked to the skin.
  15.        
  16.                       |Leonard Cohen
  17. // capilize the first character of each line
  18. scala>val capitalized = quote.lines.
  19.      |                         map( _.trim.capitalize).mkString("\n")
  20. capitalized: String = 
  21. |I don-t consider myself a pessimist.
  22. |I think of a pessimist as someone who is waiting for it to rain.
  23. |And I feel soaked to the skin.
  24. |Leonard Cohen
  25. // remove the margin of each line
  26. scala> quote.stripMargin        
  27. res1: String = 
  28. I don-t consider myself a pessimist. 
  29. I think of a pessimist as someone who is waiting for it to rain.
  30. And I feel soaked to the skin.
  31.        
  32. Leonard Cohen
  33. // this is silly.  I reverse the order of each word but keep the words in order
  34. scala> quote.stripMargin.         
  35.      |       lines.               
  36.      |       map( _.split(" ").   
  37.      |              map(_.reverse).
  38.      |              mkString (" ")).
  39.      |      mkString("\n")
  40. res16: String = 
  41. I t-nod redisnoc flesym a .tsimissep
  42. I kniht fo a tsimissep sa enoemos ohw si gnitiaw rof ti ot .niar
  43. dnA I leef dekaos ot eht .niks
  44. dranoeL nehoC
  45. scala>val myPatch = "-->This is my patch<--"                
  46. myPatch: java.lang.String = -->This is my patch<--
  47. // I replace the characters from point 10 in the string to myPatch.length 
  48. // (the full patch string)
  49. scala> quote.patch(10, myPatch, myPatch.length).mkString     
  50. res21: String = 
  51. |I don-t c-->This is my patch<--mist.
  52.                       |I think of a pessimist as someone who is waiting for it to rain.
  53.                       |And I feel soaked to the skin.
  54.        
  55.                       |Leonard Cohen
  56. // drop the first 3 lines of the string.  
  57. // there is also a take method
  58. scala> quote.lines.drop(3).mkString("\n").stripMargin 
  59. res25: String = 
  60.        
  61. Leonard Cohen
  62. // a bunch of examples of converting strings
  63. scala>"1024".toInt
  64. res26: Int = 1024
  65. scala>"1024".toFloat
  66. res27: Float = 1024.0
  67. scala>"1024".toDouble
  68. res28: Double = 1024.0
  69. scala>"1024".toLong  
  70. res29: Long = 1024
  71. scala>"102".toByte 
  72. res31: Byte = 102
  73. scala>"true".toBoolean
  74. res32: Boolean = true
  75. // format uses the java.util.Formatter class to format a string
  76. scala>"Hello %s,\nThe date is %2$tm %2$te,%2$tY".format("Jesse", new java.util.Date()) 
  77. res35: String = 
  78. Hello Jesse,
  79. The date is 09 30,2009
  80. /*
  81.    More silliness
  82.    I am replacing every other character with the character of the reversed string
  83.   
  84.    this is done by 
  85.    1. convert string to a list and zip it together with its reverse
  86.       We may still need to cover zipping.  It basically matches up the 
  87.       corresponding elements of two lists into one list
  88.       so 1,2,3 and one,two,three zipped would be (1,one),(2,two),(3,three)
  89.    2. Add an index to each element in the list with zipWithIndex
  90.    3. Use map to check if the element is an odd element using the index and return either the original element or the reversed element
  91.   
  92.    Not useful but interesting use of functional idioms
  93. */
  94. scala> quote.toList.                                          
  95.      |       zip(quote.reverse.toList).                       
  96.      |       zipWithIndex.                                    
  97.      |       map {                                            
  98.      |            case ((original,reversed),index) if(index % 2 == 0) => original
  99.      |            case ((original,reversed),index) => reversed                   
  100.      |           }.                                                              
  101.      |       mkString                                                            
  102. res42: String = |e oo -r noes|d r m s l     e s m s .        . i s e t o   e|a shlne  f anp|s i i t a   o e n   h  .siwrioi gifrrfig ioirwis.  h   n e o   a t i i s|pna f  enlhs a|e   o t e s i .        . s m s e     l s m r d|seon r- oo e|
  103. // filter out all non-vowels
  104. scala> quote.filter( "aeiou" contains _ ).mkString
  105. res51: String = ooieeaeiiioaeiiaoeoeoiaiioioaieeoaeoeieoaoe