- scala> List(1,2) map (Map(1->"one",2->"two"))
- res0: List[java.lang.String] = List(one, two)
- scala> List(3,3,2) map (List('a', 'b', 'c','d'))
- res2: List[Char] = List(d, d, c)
Monday, November 9, 2009
Using objects as functions
A fun but easily overlooked fact is that many classes inherit from a Function class and therefore can be used where "normal" functions can be used.
Labels:
function,
intermediate,
list,
Map,
Scala
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
Function._
If you have not looked at the Function object I would recommend you do. It contains several useful methods for combining and converting functions.
Examples:
Examples:
- cala> def twoParamFunc( i:Int, j:String) = println(i,j)
- twoParamFunc: (i: Int,j: String)Unit
- // the tupled method converts the function with n parameters into
- // a function that takes one tupleN
- scala> val tupled = Function tupled twoParamFunc _
- tupled: ((Int, String)) => Unit = < function1>
- scala> tupled (1 -> "one")
- (1,one)
- // A practical use-case is to convert an existing method
- // for use with a Map
- // Example with out using the tupled method
- scala> Map( 1 -> "one", 2 -> "two") map (entry => twoParamFunc(entry._1, entry._2))
- (1,one)
- (2,two)
- res5: scala.collection.immutable.Iterable[Unit] = List((), ())
- // example using tupled
- scala> Map( 1 -> "one", 2 -> "two") map (tupled)
- (1,one)
- (2,two)
- res7: scala.collection.immutable.Iterable[Unit] = List((), ())
- // and for balance the opposite
- scala> val untupled = Function untupled tupleParamFunc _
- untupled: (Int, String) => Unit = < function2>
- scala> untupled(1, "one")
- tuple = (1,one)
- // Chain is for chaining together an arbitrary number of functions
- scala> def inc(i:Int) = i + 1
- inc: (i: Int)Int
- scala> def double(i:Int) = i*i
- double: (i: Int)Int
- scala> def decr(i:Int) = i - 1
- decr: (i: Int)Int
- scala> (Function chain List(inc _, double _, decr _, double _, inc _, inc _))(3)
- res10: Int = 227
- // Now examples curries two methods then chains them together
- // define basic methods
- scala> def inc(step:Int,i:Int) = i + step
- inc: (step: Int,i: Int)Int
- scala> def multiply(i:Int, j:Int) = i * j
- multiply: (i: Int,j: Int)Int
- // Convert them to methods where the first argument is 3
- scala> val inc3 = (Function curried inc _)(3)
- inc3: (Int) => Int = < function1>
- scala> val multiplyBy3 = (Function curried multiply _)(3)
- multiplyBy3: (Int) => Int = < function1>
- // chain the resulting Function1 objects together and execute chain with parameter 3
- // (3 + 3)*3 = 18
- scala> chain(List(inc3, multiplyBy3))(3)
- res12: Int = 18
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
- }
Tuesday, November 3, 2009
Non-strict (lazy) Collections
This topic discusses non-strict collections. There is a fair bit of confusion with regards to non-strict collections: what to call them and what are they. First lets clear up some definitions.
Pre Scala 2.8 collections have a projection method. This returns a non-strict collections. So often non-strict collections are called projections in Pre Scala 2.8
Scala 2.8+ the method was changed to view, so in Scala 2.8+ view sometimes refers to non-strict collections (and sometime to a implicit conversion of a class)
Another name for non-strict collections I have seen is "lazy collections."
All those labels are for the same thing "non-strict collections" which is the functional programming term and which I will use for the rest of this topic.
As an excellent addition to this topic please take a look at Strict Ranges? by Daniel Sobral.
One way to think of non-strict collections are pull collections. A programmer can essentially form a sequence of functions and the evaluation is only performed on request.
Note: I am intentionally adding side effects to the processes in order to demonstrate where processing takes place. In practice the collectionsshould be immutable (ideally) and the processing the collections really should be side-effect free. Otherwise almost guaranteed you will find yourself with a bug that is almost impossible to find.
Example of processing a strict collection:
Notice how each time the expression is called x is incremented 3 times. Once for each element in the list. This demonstrates that map is being called for every element of the list even though only head is being calculated. This is strict behaviour.
Example of processing a non-strict collection with Scala 2.7.5
For Scala 2.8 change project => view.
Here you can see that only one element in the list is being calculated for the head request. That is the idea behind non-strict collections and can be useful when dealing with large collections and very expensive operations. This also demonstrates why side-effects are so crazy dangerous!.
More examples (Scala 2.8):
Pre Scala 2.8 collections have a projection method. This returns a non-strict collections. So often non-strict collections are called projections in Pre Scala 2.8
Scala 2.8+ the method was changed to view, so in Scala 2.8+ view sometimes refers to non-strict collections (and sometime to a implicit conversion of a class)
Another name for non-strict collections I have seen is "lazy collections."
All those labels are for the same thing "non-strict collections" which is the functional programming term and which I will use for the rest of this topic.
As an excellent addition to this topic please take a look at Strict Ranges? by Daniel Sobral.
One way to think of non-strict collections are pull collections. A programmer can essentially form a sequence of functions and the evaluation is only performed on request.
Note: I am intentionally adding side effects to the processes in order to demonstrate where processing takes place. In practice the collectionsshould be immutable (ideally) and the processing the collections really should be side-effect free. Otherwise almost guaranteed you will find yourself with a bug that is almost impossible to find.
Example of processing a strict collection:
- scala> var x=0
- x: Int = 0
- scala> def inc = {
- | x += 1
- | x
- | }
- inc: Int
- scala> var list = List(inc _, inc _, inc _)
- list: List[() => Int] = List(<function0>, <function0>, <function0>)
- scala> list.map (_()).head
- res0: Int = 1
- scala> list.map (_()).head
- res1: Int = 4
- scala> list.map (_()).head
- res2: Int = 7
Notice how each time the expression is called x is incremented 3 times. Once for each element in the list. This demonstrates that map is being called for every element of the list even though only head is being calculated. This is strict behaviour.
Example of processing a non-strict collection with Scala 2.7.5
For Scala 2.8 change project => view.
- scala> var x=0
- x: Int = 0
- scala> def inc = {
- | x += 1
- | x
- | }
- inc: Int
- scala> var list = List(inc _, inc _, inc _)
- list: List[() => Int] = List(<function0>, <function0>, <function0>)
- scala> list.projection.map (_()).head
- res0: Int = 1
- scala> list.projection.map (_()).head
- res1: Int = 2
- scala> list.projection.map (_()).head
- res2: Int = 3
- scala> list.projection.map (_()).head
- res3: Int = 4
Here you can see that only one element in the list is being calculated for the head request. That is the idea behind non-strict collections and can be useful when dealing with large collections and very expensive operations. This also demonstrates why side-effects are so crazy dangerous!.
More examples (Scala 2.8):
- scala> var x=0
- x: Int = 0
- scala> def inc = { x +=1; x }
- inc: Int
- // strict processing of a range and obtain the 6th element
- // this will run inc for every element in the range
- scala> (1 to 10).map( _ + inc).apply(5)
- res2: Int = 12
- scala> x
- res3: Int = 10
- // reset for comparison
- scala> x = 0
- x: Int = 0
- // now non-strict processing but the same process
- // you get a different answer because only one
- // element is calculated
- scala> (1 to 10).view.map( _ + inc).apply(5)
- res6: Int = 7
- // verify that x was incremented only once
- scala> x
- res7: Int = 1
- // reset for comparison
- scala> x = 0
- x: Int = 0
- // force forces strict processing
- // now we have the same answer as if we did not use view
- scala> (1 to 10).view.map( _ + inc).force.apply(5)
- res9: Int = 12
- scala> x
- res10: Int = 10
- // reset for comparison
- scala> x = 0
- x: Int = 0
- // first 5 elements are computed only
- scala> (1 to 10).view.map( _ + inc).take(5).mkString(",")
- res9: String = 2,4,6,8,10
- scala> x
- res10: Int = 5
- // reset for comparison
- scala> x = 0
- x: Int = 0
- // only first two elements are computed
- scala> (1 to 10).view.map( _ + inc).takeWhile( _ < 5).mkString(",")
- res11: String = 5,7
- scala> x
- res12: Int = 5
- // reset for comparison
- scala> x = 0
- x: Int = 0
- // inc is called 2 for each element but only the last 5 elements are computed so
- // x only == 10 not 20
- scala> (1 to 10).view.map( _ + inc).map( i => inc ).drop(5).mkString(",")
- res16: String = 2,4,6,8,10
- scala> x
- res17: Int = 10
- scala> x = 0
- x: Int = 0
- // define this for-comprehension in a method so that
- // the repl doesn't call toString on the result value and
- // as a result force the full list to be processed
- scala> def add = for( i <- (1 to 10).view ) yield i + inc
- add: scala.collection.IndexedSeqView[Int,IndexedSeq[_]]
- scala> add.head
- res5: Int = 2
- // for-comprehensions will also be non-strict if the generator is non-strict
- scala> x
- res6: Int = 1
Labels:
2.8,
collections,
intermediate,
lazy-val,
non-strict,
projection,
Scala,
view
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
Scala 2.8 Collections Overview
This topic introduces the basics of the collections API introduced in Scala 2.8. It is NOT intended to teach everything one needs to know about the collections API. It is intended only to provide context for future discussions about the new features of 2.8 collections. For example I am planning on how to introduce custom collection builders.
Disclaimer: I am not an expert on the changes to 2.8. But I think it is important to have a basic awareness of the changes. So I am going to try to provide a simplified explanation. Corrections are most certainly welcome. I will incorporate them into the post as soon as I get them.
If you want more information you can view the improvement document: Collections SID.
Pre Scala 2.8 there were several criticisms about the inconsistencies on the collections API.
Here is a Scala 2.7 example:
Notice how after the map function the return value is a ArrayBuffer, not a String. The mkString function is required to convert the collection back to a String.
Here is the code in Scala28:
In Scala28 it recognizes that the original collection is a String and therefore a String should be returned. This sort of issue was endemic in Scala 2.7 and several classes had hacks to work around the issue. For example List overrode the implementations for many of its methods so a List would be returned. But other classes, like Map, did not. So depending on what class you were using you would have to convert back to the original collection type. Maps are another good example:
But if you use filter in map then you got a Map back.
I don't want to go into detail how this works, but basically each collection is associated with a Builder which is used to construct new instances of the collection. So the superclasses can perform the logic and simply delegate the construction of the classes to the Builder. This has the effect of both reducing the amount of code duplication in the Scala code base (not so important to the API) but most importantly making the return values of the various methods consistent.
It does make the API slightly more complex.
So where in pre Scala 2.8 there was a hierarchy (simplified):
Disclaimer: I am not an expert on the changes to 2.8. But I think it is important to have a basic awareness of the changes. So I am going to try to provide a simplified explanation. Corrections are most certainly welcome. I will incorporate them into the post as soon as I get them.
If you want more information you can view the improvement document: Collections SID.
Pre Scala 2.8 there were several criticisms about the inconsistencies on the collections API.
Here is a Scala 2.7 example:
- scala> "Hello" filter ('a' to 'z' contains _)
- res0: Seq[Char] = ArrayBuffer(e, l, l, o)
- scala> res0.mkString("")
- res1: String = ello
Notice how after the map function the return value is a ArrayBuffer, not a String. The mkString function is required to convert the collection back to a String.
Here is the code in Scala28:
- scala> "Hello" filter ('a' to 'z' contains _)
- res2: String = ello
In Scala28 it recognizes that the original collection is a String and therefore a String should be returned. This sort of issue was endemic in Scala 2.7 and several classes had hacks to work around the issue. For example List overrode the implementations for many of its methods so a List would be returned. But other classes, like Map, did not. So depending on what class you were using you would have to convert back to the original collection type. Maps are another good example:
- scala> Map(1 -> "one",
- | 2 -> "two") map {case (key, value) => (key+1,value)}
- res3: Iterable[(Int, java.lang.String)] = ArrayBuffer((2,one), (3,two))
But if you use filter in map then you got a Map back.
I don't want to go into detail how this works, but basically each collection is associated with a Builder which is used to construct new instances of the collection. So the superclasses can perform the logic and simply delegate the construction of the classes to the Builder. This has the effect of both reducing the amount of code duplication in the Scala code base (not so important to the API) but most importantly making the return values of the various methods consistent.
It does make the API slightly more complex.
So where in pre Scala 2.8 there was a hierarchy (simplified):
Iterable[A]In 2.8 we now have:
|
Collection[A]
|
Seq[A]
TraversableLike[A,Repr]The *Like classes have most of the implementation code and are used to compose the public facing API: Seq, List, Array, Iterable, etc... From what I understand these traits are publicly available to assist in creating new collection implementations (and so the Scaladocs reflect the actual structure of the code.)
/ \
IterableLike[A,Repr] Traversable[A]
/ \ /
SeqLike[A,Repr] Iterable[A]
\ /
Seq[A]
Labels:
2.8,
collections,
Scala
Subscribe to:
Posts (Atom)