Thinking In Scala

Not pretending here to have the time or the inclination or, indeed, the capability to write the scala equivalent of the nice Java book, but I will write down what I consider to be really nice examples to get a Java developer to start thinking outside the box. These may be the "bad" approach to solving any one problem, but it shall not be boring…

Scala has a very nice functional aspect added on top of rather classic object-oriented. In fact, the two aspects are so nicely combined that I think scala is the next big thing in programming languages.

Collections

In scala, collections have some new methods, filter, fold, map, flatMap, foreach etc, which are very interesting in nature. Since most programs deal with collections of stuff, most of the time, these come in very handy - once you get used to them.

folding sample: test a condition on all members of a collection:

resp.foldLeft (true) ( (x,y) => x && y.contains("ahoi") && y.contains("1234.56") )

this basically turns into a big &&, starting with true, which is as neutral to && as 0 is to +

find how many elements in a collection meet a criteria

resp.filter ( _.contains("ahoi") ).size

ha ha - surely you can figure out what this does…but it does it in a really cool way. Depending on the actual type of the resp collection, there may not be an intermediary, filtered, collection! This captures one of the big things about functional programming: you're in essence building higher-order functions, not creating temporary stuff…unless those functions are temporary…? :)

They work on java containers as well

Remember that if you include the JavaConversions implicit conversions, you can use these on Java collections as well :)

import scala.collection.JavaConversions._

val resp = new java.util.ArrayList()
...
resp.filter ( _.contains("ahoi") ).size

Functional aspects

Trace - don't invoke the code every time

…the classic problem TRACE (myModel.toXml()). You don't want to invoke toXml all the time when trace is inactive. Yes, there's possible side effects when doing this, but poor performance is a given, when NOT doing it. Fixable with 3 lines of Java code or a macro in C++ - or a cool solution in scala:

   def trace (f : => Any ) = if ( traceIsOn )  println ( f )
...
   trace ( myModel.toXml )

myModel.toXml is only evaluated when traceIsOn…

Function composition: andThen

Tired of writing

  x=>g(f(x))

Then use this version:

  f andThen g

The more you use it, the more you get the intricacies of functional and the less contortions your mind goes through as you write code…

This exercise is really good: http://blog.tmorris.net/debut-with-a-catamorphism/

Think functional

There are a few components of thinking functionally and they will be useful tools in one's arsenal.

Pass functions around

  • Higher-level functions or passing pointers to functions or what-have-you. Having functions be full members of a language only increases its usefulness, even if it's just <pre>sort (list, compare (a,b) )</pre>.

No side effects

  • do not maintain state

Prefer myList.foreach ( x => whatever(x) ) which is the same as myList.foreach (whatever ) instead of for (x <- myList ) whatever (x).

Forget iterators and even the for… just use explicitely the underlying translations: foreach/map/flatMap.

Option type

Option is like checked exceptions !!!

Although I loved the Option:Some/None concept, after a while it got boring and started clogging up interfaces and replicating itself through the code like brushfire or checked exceptions. Knowing that checked exceptions were one of the first things scalaistas got rid of, It took me a while to figure out that Option hides some good functional goodies.

First, as a respectable Javaista, you figure out the .orElse methods and use them to get the beloved nulls and even better: default values.

…but then you find out the functional side: it defines the foreach/map/flatmap methods, so this is the new, null-safe, pattern:

   mymap ("key").foreach (println)

Be sure to read more here: http://blog.tmorris.net/scalaoption-cheat-sheet/ , http://blog.lostlake.org/index.php?/archives/50-The-Scala-Option-class-and-how-lift-uses-it.html and http://blog.tmorris.net/debut-with-a-catamorphism/

If(null)

   if (device2 != null) then device2.start()

becomes

   Option (device2) map {_.start()}

Granted, not a lot shorter…but the code seems easier to update to this form.

No nulls

The classic Java pattern where a field is declared null until the constructor initializes it doesn't look as nice in scala:

class ServiceOrder[T >:Null <: Service] (val what:Key[T]) {
   var entityIfAvailable : T = null
   this (e:T) = { this (e.key); this.entityIfAvailable = e }
}

The better way to do it is:

class ServiceOrder[T <: Service] (val what:Key[T]) {
   var entityIfAvailable : Option[T] = None
   this (e:T) = { this (e.key); this.entityIfAvailable = Some(e) }
}

…is because the >:Null would cascade everywhere and would just clog up the semantics of your API/classes…so, get used to Option[T]

Other language bits

Structural types: your own "for"

I bet you were wondering how you can build something like the "for", which takes any object that has a method "foreach" or "map"…

The answer is "structural types". Here's an example I found here: http://www.scala-lang.org/node/43

class File(name: String) {
  def getName(): String = name
}

def test(f: { def getName(): String }) { println(f.getName) }

test(new File("test.txt"))
test(new java.io.File("test.txt"))

Note how the test() takes an f which is basically an instance of any class that implements the "getName" method with the given signature. Long live static typing and smart compilers!

Homework: how do you build one that has either this OR that method? Well, the below compiles - but you can't call it from a class that has both methods…interesting, but I ran out of time for now.

   def test (f: {def name:String} ) = println (f.name)
   def test (f: {def getName:String} ) = println (f.getName)

Pattern matching

Don't forget pattern matching. Instead of

for ( optFish <- find "Nemo" ) optFish match {
   case Some (fish) => println (fish)
}

Use:

for ( Some(fish) <- find "Nemo" ) println (fish)

Objects are the only Statics

Sounds obvious, unti you try to make a static embedded class. It is possible, buy it works only if it's an ordinary class embedded in an object:

object Foo {
   class Bar
}
// ...
val myBar = new Foo.Bar

That's why objects are generally used in scala to define implicits and what not. Also, the language lets you import the contents of an object directly in your current context:

object ChocolateShop {
   import Foo._
   val myBar = new Bar
}

The thanks for this one go to Ismael: http://old.nabble.com/Re%3A-embedded-classes--p27232919.html

Other language bits

optional arguments

If you just one an argument to be there or not, you should use this version

def f (e:Option[WfElse] = None)

rather than the Java/C++ customary:

def f (e:WfElse*)

It is more explicit about what's going on and people can't pass you 3 meals when you'd be stuffed with the first anyways…

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License