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:
Options are implicitly converted to Iterables, so Options can be appended to collections.
This topic just demonstrates a cute little trick that can occasionally be quite useful:
- scala> List(1,2,3) ++ Some(4)
- res0: List[Int] = List(1, 2, 3, 4)
- scala> List(1,2,3) ++ None
- res1: List[Int] = List(1, 2, 3)
Options are implicitly converted to Iterables, so Options can be appended to collections.
- scala> val x : Iterable[Int] = None
- x: Iterable[Int] = List()
- scala> val x : Iterable[Int] = Some(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
Since
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:
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)
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:
- def x+ = 3 // not valid
- def x_+ = 3 // valid
- 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)
- scala> case class MyClass(i:Int) {
- | def +(j:Int) = new MyClass(j + i)
- | def -(j:Int) = new MyClass(i - j)
- | def ^(j:Int) = MyClass(j)
- | def +|(j:Int) = new MyClass(j + i / 3)
- | }
-
- scala> val c = MyClass(3)
- c: MyClass = MyClass(3)
- scala> c + 4
- res26: MyClass = MyClass(7)
- scala> c-2
- res27: MyClass = MyClass(1)
- scala> c -6
- res28: MyClass = MyClass(-3)
- scala> c ^ 3
- res29: MyClass = MyClass(3)
- scala> c+|5
- res31: MyClass = MyClass(6)
Labels:
assignment,
beginner,
operator,
Scala
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
scala 2.7.7
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
- scala> var called = 0
- called: Int = 0
- scala> called
- res0: Int = 0
- /*
- assert, require and assume have call by name parameters so the message is only
- calculated when the assertion fails.
- */
- scala> assert (called == 0, {called += 1; println("called is not 0")})
- scala> require (called == 0, {called += 1; println("called is not 0")})
- scala> assume (called == 0, {called += 1; println("called is not 0")})
- scala> called = 1
- called: Int = 1
- // demonstrating that the method is in fact called when the assertion fails
- scala> assert (called == 0, {called += 1; println("called is not 0")})
- called is not 0
- java.lang.AssertionError: assertion failed: ()
- at scala.Predef$.assert(Predef.scala:95)
- ...
- scala> called
- res4: Int = 2
- /*
- Require is intended to be used as a precondition of a method so
- it throws an IllegalArgumentException, not an AssertionError
- */
- scala> require (called == 0, {called += 1; println("called is not 0")})
- called is not 0
- java.lang.IllegalArgumentException: requirement failed: ()
- at scala.Predef$.require(Predef.scala:117)
- ...
- scala> called
- res6: Int = 3
- scala> assume (called == 0, {called += 1; println("called is not 0")})
- called is not 0
- java.lang.AssertionError: assumption failed: ()
- at scala.Predef$.assume(Predef.scala:107)
- ...
- scala> called
- res8: Int = 4
scala 2.7.7
- /*
- In Scala 2.7 the parameter is evaluated before the
- method is called so the side effect of the message causes
- the assertion to fail
- */
- scala> assert (called == 0, {called += 1; println("called is not 0")})
- called is not 0
- scala> called
- 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.
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.
- // basic usage
- scala> List((1,2),(2,3)).unzip
- res2: (List[Int], List[Int]) = (List(1, 2),List(2, 3))
- /*
- tuples can be of different types
- and the resulting traversables reflect the differing types
- */
- scala> List((2,"a"),(3,"b")).unzip
- res3: (List[Int], List[java.lang.String]) = (List(2, 3),List(a, b))
- // Maps are Traversable[Collection] so unzip works with them
- scala> Map(1 -> 2, 3 -> 4).unzip
- res1: (scala.collection.immutable.Iterable[Int], scala.collection.immutable.Iterable[Int]) = (List(1, 3),List(2, 4))
- // Of course sets result in sets and duplicates are collected to a single element
- scala> Set((1,2),(2,2)).unzip
- res7: (scala.collection.immutable.Set[Int], scala.collection.immutable.Set[Int]) = (Set(1, 2),Set(2))
- /*
- Arbitrary elements can be unziped if a method is provided to decompose each element
- */
- scala> List("one word", "another word").unzip {e => (e takeWhile {_ != ' '}, e dropWhile {_ != ' '})}
- res6: (List[String], List[String]) = (List(one, another),List( word, word))
- /*
- The following shows the same function
- applied with map. It results in a single
- list of Tuples rather than two lists of single elements
- */
- scala> List("one word", "another word").map {e => (e takeWhile {_ != ' '}, e dropWhile {_ != ' '})}
- res8: List[(String, String)] = List((one, word), (another, word))
Labels:
2.8,
beginner,
Scala,
traversable,
unzip
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.
- scala> val propsTemplates = Option(System getProperty "MVN_CREATOR_TEMPLATES")
- propsTemplates: Option[java.lang.String] = None
- scala> val envTemplates = Option(System getenv "MVN_CREATOR_TEMPLATES")
- envTemplates: Option[java.lang.String] = None
- scala> val defaultHome = Some(System getProperty "user.home")
- defaultHome: Some[java.lang.String] = Some(/Users/jeichar)
- /*
- chain the different options together in order of priority and get the value
- I am taking a small liberty here because I am assuming that user.home is always available
- */
- scala> propsTemplates.orElse(envTemplates).orElse(defaultHome).get
- res0: java.lang.String = /Users/jeichar
- // alternative form:
- scala> propsTemplates orElse envTemplates orElse defaultHome get
- 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:
However you have the option to apply a little sugar to the statements cleaning them up a little:
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.
- scala> for (i <- 1 to 10; if (i % 2 == 1)) yield i
- res0: scala.collection.immutable.IndexedSeq[Int] = IndexedSeq(1, 3, 5, 7, 9)
- scala> util.Random.nextInt(10) match {
- | case i if(i>5) => println("hi")
- | case _ => println("low")
- | }
- low
However you have the option to apply a little sugar to the statements cleaning them up a little:
- scala> for (i <- 1 to 10; if i % 2 == 1) yield i
- res2: scala.collection.immutable.IndexedSeq[Int] = IndexedSeq(1, 3, 5, 7, 9)
- scala> util.Random.nextInt(10) match {
- | case i if i>5 => println("hi")
- | case _ => println("low")
- | }
- 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.
- scala> 10 match { case i if i == 1 || i == 10 => "obviously this is a match"}
- res4: java.lang.String = obviously this is a match
- /*
- 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
- */
- scala> 10 match { case i if i == 1 ||
- | i == 10 => "obviously this is a match"}
- res5: java.lang.String = obviously this is a match
- scala> 10 match {
- | case i
- | if
- | i == 1
- | ||
- | i == 10
- | => "matched"
- | }
- res6: java.lang.String = matched
- /*
- 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.
- */
- scala> for {
- | x <- 1 to 10
- | if
- | x > 10
- | || x == 2 } yield x
- < console>:5: error: '<-' expected but integer literal found.
- || x == 2 } yield x
- ^
- < console>:5: error: illegal start of simple expression
- || x == 2 } yield x
- ^
- scala> for {
- | x <- 1 to 10
- | if x == 1 || x == 10 } yield x
- res7: scala.collection.immutable.IndexedSeq[Int] = IndexedSeq(1, 10)
Labels:
beginner,
filter,
for,
for-comprehension,
guard,
match,
matching,
Scala,
syntactic sugar
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.
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.
- # scala -classpath ~/.m2/repository/org/scala-tools/testing/specs/1.6.1/specs-1.6.1.jar
- scala> import org.specs._
- import org.specs._
- scala> object XmlSpec extends Specification {
- | val sample = <library>
- | <videos>
- | <video type="dvd">Seven</video>
- | <video type="blue-ray">The fifth element</video>
- | <video type="hardcover">Gardens of the moon</video>
- | </videos>
- | <books>
- | <book type="softcover">Memories of Ice</book>
- | </books>
- | </library>
- | "Scala XML" should {
- | "allow xpath-like selection" in {
- | (sample \\ "video").size must be (3)
- | }
- | "select child nodes" in {
- | // This test fails because child is a sequence not a string
- | // See the results of the tests
- | sample.child must contain (<videos/>)
- | }
- | }
- | }
- defined module XmlSpec
- scala> XmlSpec.main(Array[String]())
- Specification "XmlSpec"
- Scala XML should
- + allow xpath-like selection
- x select child nodes <-- x indicates failure.
- 'ArrayBuffer(
- , <videos>
- <video type="dvd">Seven</video>
- <video type="blue-ray">The fifth element</video>
- <video type="hardcover">Gardens of the moon</video>
- </videos>,
- , <books>
- <book type="softcover">Memories of Ice</book>
- </books>,
- )' doesn't contain '<videos></videos>' (< console>:24)
- Total for specification "XmlSpec":
- Finished in 0 second, 52 ms
- 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
From the caller's point of view; varargs can be called as follows:
In Java (if I remember right) only arrays can be passed in place of varargs:
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.
Examples:
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:
- class C {
- public static void main(String... args) {
- System.out.println(args.length)
- }
- }
- String[] args = new String[]{"arg1", "arg2"}
- 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.
- def method (args:Int*) = println(args)
- val list = List(1,2,3)
- method (list:_*) // note the use of _*
Examples:
- scala> def method(varargs:Int*)(more:String*) = println(varargs,more)
- method: (Int*)(String*)Unit
- scala> method(1,2,3,4)("one")
- (Array(1, 2, 3, 4),Array(one))
- scala> method(1,2,3,4)
- < console>:6: error: missing arguments for method method in object $iw;
- follow this method with '_' if you want to treat it as a partially applied function
- method(1,2,3,4)
- ^
- scala> method(1,2,3,4)()
- (Array(1, 2, 3, 4),Array())
- scala> method()("one")
- (Array(),Array(one))
- scala> method("one")
- < console>:6: error: type mismatch;
- found : java.lang.String("one")
- required: Int
- method("one")
- ^
- scala> method()()
- (Array(),Array())
- scala> val method2 = method(1,2,3)_
- method2: (String*) => Unit = < function>
- scala> val paramList = List("hi","ho")
- paramList: List[java.lang.String] = List(hi, ho)
- scala> method2(paramList)
- < console>:8: error: type mismatch;
- found : List[java.lang.String]
- required: String
- method2(paramList)
- ^
- scala> method2(paramList:_*)
- (Array(1, 2, 3),List(hi, ho))
- scala> val range = (1 to 5) map {_.toString}
- range: RandomAccessSeq.Projection[java.lang.String] = RangeM(1, 2, 3, 4, 5)
- scala> method2(range:_*)
- (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:
Scala:
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:
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:
- /**
- * Returns the annotation with the given name or null if there is no annotation
- * on the objects class with the given name.
- */
- public static < A extends java.lang.annotation.Annotation> Annotation annotation(Object obj, Class< A> annotationCls) {
- return obj.getClass().getAnnotation(annotationCls)
- }
Scala:
- import java.lang.annotation.Annotation
- /**
- * Returns the annotation with the given name.
- */
- def annotation[A <: Annotation](obj:Object, annotationCls:Class[A]) : Option[Annotation] = {
- Option (obj.getClass.getAnnotation (annotationCls))
- }
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:
- scala> import java.lang.annotation.Annotation
- import java.lang.annotation.Annotation
- kscala> def annotation[A <: Annotation](obj:Object, annotationCls:Class[A]) : Option[Annotation] = {
- | Option (obj.getClass.getAnnotation (annotationCls))
- | }
- annotation: [A <: java.lang.annotation.Annotation](obj: java.lang.Object,annotationCls: Class[A])Option[java.lang.annotation.Annotation]
- // strings do not have the Documented annotation so None is returned
- scala> annotation("x", classOf[java.lang.annotation.Documented])
- res0: Option[java.lang.annotation.Annotation] = None
- // None is not defined
- scala> res0.isDefined
- res1: Boolean = false
- // None IS empty
- scala> res0.isEmpty
- res26: Boolean = true
- // We need a some example so LineNumberInputStream has Deprecated annotation
- // we will use that in order to
- scala> val in = new LineNumberInputStream(new ByteArrayInputStream("hello".getBytes))
- in: java.io.LineNumberInputStream = java.io.LineNumberInputStream@8ca9a2d
- scala> annotation(in, classOf[Deprecated])
- res2: Option[java.lang.annotation.Annotation] = Some(@java.lang.Deprecated())
- // Some(...) is always defined even if it contains null
- scala> res2.isDefined
- res3: Boolean = true
- scala> val nullSome = Some(null)
- nullSome: Some[Null] = Some(null)
- scala> nullSome.isDefined
- res28: Boolean = true
- // Some is never empty
- scala> res2.isEmpty
- res4: Boolean = false
- // You can also test particular values as follows
- scala> if(res0 == None) println("its ok to use")
- its ok to use
- scala> if (res2.map {a => "found"} == Some("found")) println ("it is deprecated dont use!")
- it is deprecated dont use!
- scala> res0 match {
- | case None => println("its ok to use")
- | case Some(x:Deprecated) => println ("it is deprecated dont use!")
- | }
- its ok to use
- scala> res2 match {
- | case None => println("its ok to use")
- | case Some(x:Deprecated) => println ("it is deprecated dont use!")
- | }
- it is deprecated dont use!
- scala> if(Some("hi") == Some("hi")) println("a match")
- a match
- scala> if(Some("hi") == Some("ho")) println("a match")
- // After you have tested you can use get to obtain the value
- // but becareful, you will get an exception if you forget to test.
- scala> res0.get
- java.util.NoSuchElementException: None.get
- at scala.None$.get(Option.scala:169)
- at scala.None$.get(Option.scala:167)
- at .< init>(< console>:12)
- at .< clinit>(< console>)
- [snip]
- scala> res2.get
- res10: java.lang.annotation.Annotation = @java.lang.Deprecated()
- // a potentially better way of optaining the value is to provide a default if
- // the value does not exists
- scala> res2.getOrElse(classOf[java.lang.annotation.Documented])
- res13: java.lang.Object = @java.lang.Deprecated()
- scala> res0.getOrElse(classOf[java.lang.annotation.Documented])
- res14: java.lang.Object = interface java.lang.annotation.Documented
- // A Option is a "monad" (dont worry too much about the term if
- // you dont know it) a very (VERY) simplified meaning of that is that
- // option behaves a bit like a collection of size 1 or 0
- // you can use similar methods on an Option as a collection.
- // So exists tests each element in the Option to see if it matches
- // the function passed in as the parameter
- // res2 has an object that is an instanceOf Annotation
- scala> res2.exists {_.isInstanceOf[Annotation]}
- res7: Boolean = true
- // None always returns false to exists
- scala> res0.exists {_.isInstanceOf[Annotation]}
- res8: Boolean = false
- scala> res2.exists {_.toString == "hi"}
- res29: Boolean = false
- // Similarly you can use the filter method that is present in all collections
- scala> res2.filter {_.toString == "hi"}
- res30: Option[java.lang.annotation.Annotation] = None
- scala> res2.filter {_.isInstanceOf[Annotation]}
- res32: Option[java.lang.annotation.Annotation] = Some(@java.lang.Deprecated())
- // apart from just filtering you can convert the type contained
- // in the Option by using map to map from one type of Option to
- // another type of Option in this examples we map from
- // Option[Annotation] to Option[String]
- scala> res0.map {_.toString}.getOrElse("does not exist")
- res15: java.lang.String = does not exist
- scala> res2.map {_.toString}.getOrElse("does not exist")
- res16: java.lang.String = @java.lang.Deprecated()
- // Another very handy and safe way to access the value is to use foreach
- // this will call the function with the parameter from the Option if
- // the Option is Some but a noop will occur if the Option is None.
- scala> res2.foreach { println _ }
- @java.lang.Deprecated()
- scala> res0.foreach { println _ }
- // orElse is simply a method to ensure that the Option is a Some
- scala> res0.orElse(Some(classOf[java.lang.annotation.Documented]))
- res22: Option[java.lang.Object] = Some(interface java.lang.annotation.Documented)
- scala> res2.orElse(Some(classOf[java.lang.annotation.Documented]))
- 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).
- // BigInt objects can be created from ints
- scala> val x = BigInt(1500)
- x: BigInt = 1500
- // or longs
- scala> val y = BigInt(8839200231L)
- y: BigInt = 8839200231
- // or strings
- scala> val z = BigInt("1234566789008723457802308972345723470589237507")
- z: BigInt = 1234566789008723457802308972345723470589237507
- // then thanks to scala you can multiply/divide/add/subtract etc...
- // as if it was a Scala literal
- scala> x * y * z
- res0: BigInt = 16368874569886254973831932331037537269641764816982396175500
- // by importing implicits you can also directly multiply big ints with integers and longs
- // however remember to put the big in first so that the int is converted to big int
- // because you cannot do Int * BigInt. It must be BigInt * Int
- scala> import BigInt._
- import BigInt._
- scala> x * y * z * 124
- 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:
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.
If the protected is parameterized then only classes that fall into the parameter category can access the parameter:
The following example shows how package access works in Scala 2.8. They have to be compiled as 2 files.
Root.scala:
Subpackage.scala
IE:
- object PublicObject {
- val publicVal
- var publicVar
- def publicMethod = 1
- }
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.
- scala> class Class1 {
- | protected def pMethod = "protected"
- | }
- defined class Class1
- scala> class Class2 {
- // pMethod is not accessible because Class2 is not a subclass of Class1
- | new Class1().pMethod
- | }
- <console>:6: error: method pMethod cannot be accessed in Class1
- new Class1().pMethod
- ^
- scala> class Class3 extends Class1 {
- // also unlike Java, protected restricts to the same object
- | new Class1().pMethod
- | }
- <console>:6: error: method pMethod cannot be accessed in Class1
- new Class1().pMethod
- ^
- scala> class Class3 extends Class1 {
- | pMethod
- | }
- defined class Class3
If the protected is parameterized then only classes that fall into the parameter category can access the parameter:
- scala> class Class1 {
- // protected[Class1] is equivalent to private
- | protected[Class1] def method() = println("hi")
- | method()
- | }
- defined class Class1
- scala> new Class1()
- hi
- res0: Class1 = Class1@dc44a6d
- // this does not work because method is only accessible in Class1
- scala> class Class2 extends Class1 { method() }
- <console>:5: error: not found: value method
- class Class2 extends Class1 { method() }
- ^
- scala> object Module {
- | object Inner1 {
- | protected[Inner1] def innerMethod = println("hi")
- | protected[Module] def moduleMethod = println("moduleMethod")
- |
- | object InnerInner {
- | // InnerInner is within Inner1 so the access works
- | def callInner = innerMethod
- | }
- | }
- | // module method is protected[Module] so anything in Module can access it
- | def callModuleMethod = Inner1.moduleMethod
- |
- | object Inner2 {
- | // Inner1.module method is protected[Module] and
- | // Inner2 is within module so therefore has access
- | def callModuleMethod = Inner1.moduleMethod
- | }
- | }
- defined module Module
- scala> Module.callModuleMethod
- moduleMethod
- scala> Module.Inner1.InnerInner.callInner
- hi
- scala> Module.Inner1.innerMethod
- <console>:6: error: method innerMethod cannot be accessed in object Module.Inner1
- Module.Inner1.innerMethod
- ^
- scala> Module.Inner1.moduleMethod
- <console>:6: error: method moduleMethod cannot be accessed in object Module.Inner1
- 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:
- package root
- class Class1 {
- protected[root] def rootMethod = println("rootMethod")
- }
- class Class2 {
- // same package so this is legal
- new Class1().rootMethod
- }
Subpackage.scala
- package root.sub
- class Class3 {
- // Class3 is in a subpackage of root so
- // it can access all objects protected by
- // protected[root] as well as objects
- // protected by protected[root.sub]
- new root.Class1().rootMethod
- }
Monday, November 2, 2009
Multiple Constructors
In Scala there is a primary constructor:
First multiple constructors:
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.
Factory companion objects can be used to work around these restrictions:
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:
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:
- scala> class HelloConstructor(param1:Int, param2:Int) {
- | def this(onlyParam:Int) = this(onlyParam,onlyParam)
- | def this(p1:String, p2:String, p3:String) = this(p1.length, p2.length + p3.length)
- | def this(onlyParam:String) = this(onlyParam.length)
- | }
- 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.
- scala> class HelloConstructor(param1:Int, param2:Int) {
- | def x = 1
- | def this() = this(x,3)
- | }
- <console>:6: error: not found: value x
- def this() = this(x,3)
- scala> class HelloConstructor(param1:Int, param2:Int) {
- | def this() = {
- | println("constructing") // the REPL won't even let me finish method definition
- <console>:3: error: 'this' expected but identifier found.
- println("constructing")
- ^
Factory companion objects can be used to work around these restrictions:
- scala> class HelloConstructor(param1:Int, param2:Int)
- defined class HelloConstructor
- scala> object HelloConstructor {
- | def apply() = {
- | println("constructing object")
- | new HelloConstructor(1,2)
- | }
- | }
- defined module HelloConstructor
- scala> HelloConstructor()
- constructing object
- 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:
- scala> class HelloConstructor(param1: Int = 1, param2: Int = 2)
- defined class HelloConstructor
- scala> new HelloConstructor()
- res0: HelloConstructor = HelloConstructor@7cd47880
- scala> new HelloConstructor(1)
- res1: HelloConstructor = HelloConstructor@3834a1c8
- scala> new HelloConstructor(param1 = 1)
- res2: HelloConstructor = HelloConstructor@3b3e3940
- scala> new HelloConstructor(param2 = 1)
- res3: HelloConstructor = HelloConstructor@6dee2ea8
- scala> new HelloConstructor(3,4)
- res4: HelloConstructor = HelloConstructor@397b6074
- scala> new HelloConstructor(param1 = 3, param2=4)
- res5: HelloConstructor = HelloConstructor@20272fec
Labels:
beginner,
classes,
companion,
constructor,
factory-method,
Scala
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:
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:
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:
- 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:
- scala> val groups = (1 to 20).toList groupBy {
- | case i if(i<5) => "g1"
- | case i if(i<10) => "g2"
- | case i if(i<15) => "g3"
- | case _ => "g4"
- | }
- 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))
- scala> groups.keySet
- res6: scala.collection.Set[java.lang.String] = Set(g1, g2, g3, g4)
- scala> groups("g1")
- res7: List[Int] = List(1, 2, 3, 4)
- scala> val mods = (1 to 20).toList groupBy ( _ % 4 )
- 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,
- 11, 15, 19), 0 -> List(4, 8, 12, 16, 20))
- scala> mods.keySet
- res9: scala.collection.Set[Int] = Set(1, 2, 3, 0)
- scala> mods(1)
- res11: List[Int] = List(1, 5, 9, 13, 17)
Labels:
beginner,
collections,
groupby,
Scala
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.
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.
- /*
- Making use of raw strings to create a multi line string
- I add a | at the beginning of each line so that we can line up the quote nicely
- in source code then later strip it from the string using stripMargin
- */
- scala> val quote = """|I don-t consider myself a pessimist.
- | |I think of a pessimist as someone who is waiting for it to rain.
- | |And I feel soaked to the skin.
- |
- | |Leonard Cohen"""
- quote: java.lang.String =
- |I don-t consider myself a pessimist.
- |I think of a pessimist as someone who is waiting for it to rain.
- |And I feel soaked to the skin.
-
- |Leonard Cohen
- // capilize the first character of each line
- scala> val capitalized = quote.lines.
- | map( _.trim.capitalize).mkString("\n")
- capitalized: String =
- |I don-t consider myself a pessimist.
- |I think of a pessimist as someone who is waiting for it to rain.
- |And I feel soaked to the skin.
- |Leonard Cohen
- // remove the margin of each line
- scala> quote.stripMargin
- res1: String =
- I don-t consider myself a pessimist.
- I think of a pessimist as someone who is waiting for it to rain.
- And I feel soaked to the skin.
-
- Leonard Cohen
- // this is silly. I reverse the order of each word but keep the words in order
- scala> quote.stripMargin.
- | lines.
- | map( _.split(" ").
- | map(_.reverse).
- | mkString (" ")).
- | mkString("\n")
- res16: String =
- I t-nod redisnoc flesym a .tsimissep
- I kniht fo a tsimissep sa enoemos ohw si gnitiaw rof ti ot .niar
- dnA I leef dekaos ot eht .niks
- dranoeL nehoC
- scala> val myPatch = "-->This is my patch<--"
- myPatch: java.lang.String = -->This is my patch<--
- // I replace the characters from point 10 in the string to myPatch.length
- // (the full patch string)
- scala> quote.patch(10, myPatch, myPatch.length).mkString
- res21: String =
- |I don-t c-->This is my patch<--mist.
- |I think of a pessimist as someone who is waiting for it to rain.
- |And I feel soaked to the skin.
-
- |Leonard Cohen
- // drop the first 3 lines of the string.
- // there is also a take method
- scala> quote.lines.drop(3).mkString("\n").stripMargin
- res25: String =
-
- Leonard Cohen
- // a bunch of examples of converting strings
- scala> "1024".toInt
- res26: Int = 1024
- scala> "1024".toFloat
- res27: Float = 1024.0
- scala> "1024".toDouble
- res28: Double = 1024.0
- scala> "1024".toLong
- res29: Long = 1024
- scala> "102".toByte
- res31: Byte = 102
- scala> "true".toBoolean
- res32: Boolean = true
- // format uses the java.util.Formatter class to format a string
- scala> "Hello %s,\nThe date is %2$tm %2$te,%2$tY".format("Jesse", new java.util.Date())
- res35: String =
- Hello Jesse,
- The date is 09 30,2009
- /*
- More silliness
- I am replacing every other character with the character of the reversed string
-
- this is done by
- 1. convert string to a list and zip it together with its reverse
- We may still need to cover zipping. It basically matches up the
- corresponding elements of two lists into one list
- so 1,2,3 and one,two,three zipped would be (1,one),(2,two),(3,three)
- 2. Add an index to each element in the list with zipWithIndex
- 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
-
- Not useful but interesting use of functional idioms
- */
- scala> quote.toList.
- | zip(quote.reverse.toList).
- | zipWithIndex.
- | map {
- | case ((original,reversed),index) if(index % 2 == 0) => original
- | case ((original,reversed),index) => reversed
- | }.
- | mkString
- 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|
- // filter out all non-vowels
- scala> quote.filter( "aeiou" contains _ ).mkString
- res51: String = ooieeaeiiioaeiiaoeoeoiaiioioaieeoaeoeieoaoe
Labels:
beginner,
raw strings,
Scala,
String
Subscribe to:
Comments (Atom)