Showing posts with label 2.8. Show all posts
Showing posts with label 2.8. Show all posts
Tuesday, April 20, 2010
Breaks
Scala 2.8 added the break control flow option. It is not implemented as a special language feature. Rather it is simply implemented as an object/trait using standard Scala mechanisms. If you are interested in creating a control flow object similar to this look at the Defining Custom Control Structures post.
The Break functionality is works basically how you would expect:
Pretty intuitive but beware, break only breaks out to the first enclosing breakable. Here is an example of the issue:
Fortunately the implementers provide an elegant way to handle these sorts of cases. The Breaks object extends the Breaks class. By instantiating other instances of Breaks it is possible to control which breaks capture
The Break functionality is works basically how you would expect:
- // Import the control flow methodsmethods
- scala> import util.control.Breaks._
- import util.control.Breaks._
- // pass a function to the breakable method
- scala> breakable {
- | for (i <- 1 to 10 ) {
- | if(i > 5) break // call break when done
- | println(i)
- | }
- | }
- 1
- 2
- 3
- 4
- 5
Pretty intuitive but beware, break only breaks out to the first enclosing breakable. Here is an example of the issue:
- scala> def loop(f : Int => Boolean) = breakable {
- | for (i <- 1 to 300) if (f(i)) break else println(i)
- | }
- loop: (f: (Int) => Boolean)Unit
- // This never ends because break is caught by breakable in the loop method
- scala> breakable {
- | while(true) {
- | loop{ i => break; true }
- | }
- | }
Fortunately the implementers provide an elegant way to handle these sorts of cases. The Breaks object extends the Breaks class. By instantiating other instances of Breaks it is possible to control which breaks capture
- scala> import scala.util.control._
- import scala.util.control._
- scala>
- scala> def loop(f : Int => Boolean) = {
- | val Inner = new Breaks
- | Inner.breakable {
- | for (i <- 1 to 4) if (f(i)) Inner.break else println(i)
- | }
- | }
- loop: (f: (Int) => Boolean)Unit
- scala>
- scala> val Outer = new Breaks
- Outer: scala.util.control.Breaks = scala.util.control.Breaks@1ba4806
- scala> Outer.breakable {
- | while(true) {
- | loop{ i => if(i==4) Outer.break; false}
- | }
- | }
- 1
- 2
- 3
Labels:
2.8,
break,
control structure,
intermediate,
Scala
Tuesday, April 6, 2010
Scala 2.7 to 2.8 migration help
Scala 2.8 has some very significant differences from Scala 2.7 so if you want to migrate from Scala 2.7 to 2.8 you might want to view this Stack overflow topic:
What are the biggest differences between Scala 2.8 and Scala 2.7?
It has some good tips.
What are the biggest differences between Scala 2.8 and Scala 2.7?
It has some good tips.
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, January 20, 2010
Case classes in 2.8
Thanks to Scala 2.8's default parameters case classes have a couple wonderful new features in Scala 2.8. Specifically the copy method and the ability to have case classes with default parameters.
- // constructor methods have defaults defined
- scala> case class Node (name:String, left : Option[Node] = None, right : Option[Node] = None)
- defined class Node
- // the name is the only required parameter because it does not have a default
- scala> val child = Node("leaf")
- child: Node = Node(leaf,None,None)
- // left is being assigned here because the name of the parameter is not explicit
- scala> val parent = Node("parent", Some(res0))
- parent: Node = Node(parent,Some(Node(leaf,None,None)),None)
- // now the left node is not defined just the right
- scala> val node = Node("node", right=Some(res0))
- node: Node = Node(node,None,Some(Node(leaf,None,None)))
- /*
- The real power is the copy constructor that is automatically generated in the case class. I can make a copy with any or all attributes modifed by using the copy constructor and declaring which field to modify
- */
- scala> parent.copy(right = Some(node))
- res4: Node = Node(parent,Some(Node(leaf,None,None)),Some(Node(node,None,Some(Node(leaf,None,None)))))
- scala> parent.copy(left=None)
- res5: Node = Node(parent,None,None)
- scala> parent.copy(name="hoho")
- res6: Node = Node(hoho,Some(Node(leaf,None,None)),None)
- scala> parent.copy(name="hoho", left=None)
- res7: Node = Node(hoho,None,None)
Labels:
2.8,
case-classes,
Scala
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
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)