Uber Conf 2010 - Notes from Scala for Java Programmers Workshop

I spent the first half of Day 3 of Uber Conf 2010 (Day 2 and 1) in Scala for Java Programmers workshop by Venkat, took extensive notes, and noted/tried pretty much all the code samples.

<warning>
This is a code intensive and slightly long entry.
</warning>

A more complete entry covering other events of Day 3 will come later today.

Lets go down the rabbit hole!

  • Why Scala ? - Scala is highly concise, expressive, nice support for XML processing, pattern matching, inherent support for authoring concurrent code - lot of good things to write efficient code.
  • Scala means SCAlable LAnguage - comes from the fact that you can write either a small script or a complete application using Scala.
  • An application developed on single core and deployed on multi-core can easily misbehave, primarily because of the concurrency model in Java. Scala makes it much easier to write concurrent applications (more on this below).
  • Writing correct synchronized code in Java requires divine power. Multi-threaded programming in Java is like working with mother-in-law, basically waiting for you to fail.
  • Scala complies with Java semantics without you worrying about it. "-savedcompile" saves the generated class files as JAR in the local directory.

Here is the first sample code that calculates the factorial of a number:

def fact(number: Int) = {
 var total = 1
 for (i <- 1 to number) {
     total = total \* i
 }
 total
}

println(fact(5))

Key points about this code (differences from Java):

  • Each class is "public" by default
  • No "main" method
  • "return" keyword is not required
  • The index "i" is assigned a type using inference, integer in this case
  • "var" defines a variable

This was done as a user exercise and so I wrote my first Scala code today ... yeee-haw!

  • Recursion is very expressive but expensive because of multiple stacks. Scala makes it run iterative and so less expensive
  • Scala supports tail recursion to a fairly decent extent, only one level of stack and so less expensive.

Here is a re-write of the above function using simple iterative recursion:

def total(number:Int) : Int = {
    if (number == 1)
       return 1
    number \* total (number - 1)
}

println(total(5))

And now this method converted to use tail recursion

def total(number: Int) : Int = {
   def totalWithAccumulator(accumulator: Int, number: Int) : Int = {
       if (number == 1) 
           accumulator
       else
           totalWithAccumulator(accumulator \* number, number - 1)
   }
   totalWithAccumulator(1, number)
}
println(total(5))

Here is a function that calculates the total of elements in a list:

def total(list: List[int]) = {
    var total = 0
    for (e <- list)
       total = total + e
    total
}

val list = List(1,2,4,5,6,3)
println(total(list))

This is using iterative approach - keep modifying the variable over & again and tells the next step. In functional, variables are constant and never changed. And here is a new method using the functional capabilities:


// imperative
def total(list: List[int]) = {
    var total = 0
    for (e <- list)
        total = total + e
    total
}

// functional
def total2(list: List[int]) = {
    list.foldLeft(0) {
       (carryOver, e) => carryOver + e
    }
}

val list = List(1,2,4,5,6,3)
println(total(list))
println(total2(list))

In Scala

a.+(b);

is equivalent to
a + b

".", parentheses, and ";" are optional.

When the method name ends with the colon, Scala will transpose them. The following code snippet shows this and some other features of the language:

val list = List(1,2,4,5,6,3)

// Imperative
var total1 = 0
for (e <- list)
    total1 = total1 + e
println("Total is " + total1)

// Functional
val total2 = list.foldLeft(0) { (carryOver, e) => carryOver + e }
println("Total is " + total2)

// Transposition using colon
// /: is a different name for foldLeft
var total3 = (0 /: list) { (carryOver, e) => carryOver + e }
println("Total is " + total3)

// No name required if the parameters are used only once
var total4 = (0 /: list) { _ + _ }
println("Total is " + total4)

// Pipe the method
def add(op1: Int, op2: Int) = { op1 + op2 }
val total5 = (0 /: list) { add }
println("Total is " + total5)
  • No primitive types in Scala, everything is an object

Code samples of closures in Scala ...

def totalSelectedNumbers(list:List[Int], selector: Int => boolean) = {
    var total = 0
    for (e <- list)
        if (selector(e)) total = total + e
    total
}


val list = List(1,2,4,5,6,3)
println(totalSelectedNumbers(list, { e => true }))
println(totalSelectedNumbers(list, { e => e % 2 == 0 }))
println(totalSelectedNumbers(list, { e => e > 4 }))
println(totalSelectedNumbers(list, { _ > 4 }))

Notice how "println" becomes more concise over subsequent lines. And a further cleaner, and concise, version can be written by allowing multiple lists to be passed to the function as shown below:

// Multiple lists to the function
def totalSelectedNumbers(list:List[Int]) (selector: Int => boolean) = {
    var total = 0
    for (e <- list)
       if (selector(e)) total = total + e
    total
}

val list = List(1,2,4,5,6,3)
println(totalSelectedNumbers(list) { _ > 4 })

Here is another exercise to write a function that doubles the number in the list:

val list = List(1,2,4,5,6,3)
println(list.map { _ \* 2 })

And another exercise to find the maximum number of a list

val list = List(1,2,4,5,6,3,2,7)
val max = (list(0) /: list) { (max, e) =>
             if (e > max) e else max
          }
println (max)


And then a simplified method definition ...

println((list(0) /: list) { Math.max })

  • In Scala: "val" creates a pointer that cannot change, "var" creates a pointer that can change but the objects are immutable.
  • In Scala, everything is public unless you say otherwise.
  • Code within the class runs within the primary constructor. In Scala, there is only one constructor, every other is called as auxiliary constructor and they always go through the primary constructor. Only primary constructor can call super (only path to the base class)

Here is a simple class definition:

class Car(val year: int, var miles: Int) {

    // invokes with primary constructor
    println("hello there")

    // year has a getter, miles has a getter/setter
    def drive(dist: Int) = {
       miles += dist
    }

    // private method only to this instance
    private[this] def tuneup {}
}

val car = new Car(2010, 0)
println(car.year)
println(car.miles)
car drive 10
println(car.miles)
  • Scala is a purely OO language, new methods can be defined easily on any object

Here is a sample code that demonstrates adding a new method:

import java.util._ // static import

class IntUtil(number: Int) {
   def days = this
   def ago = {
      var cal = Calendar.getInstance()
      cal.add(Calendar.DAY_OF_MONTH, -number)
      cal.getTime()
   }
}

val num = 2
val obj = new IntUtil(num)
println(obj.days.ago)
  • Scala has no primitive types, everything is an object.
  • New methods can be easily added using "implicit conversion"

Here is a code sample that shows how to perform "implicit conversion" and add a new method to a "val"

import java.util._ // static import

class IntUtil(number: Int) {
   def days = this
   def ago = {
      var cal = Calendar.getInstance()
      cal.add(Calendar.DAY_OF_MONTH, -number)
      cal.getTime()
   }
}

val num = 2
val obj = new IntUtil(num)
println(obj.days.ago)

// implicit conversion - only one conversion can be applied per object (or class??)
implicit def pleaseConvertInt2WonderfulIntUtil(number: Int) = new IntUtil(number)

println(2.days.ago)
  • To create Singleton, use the word "object" such as:
class Car {
}

object Car {
    // place all the static methods here
}
  • This singleton object is also called the "companion" object and it must exist in the same file as the original object.
  • Companion object is used to create the factory pattern.
  • Adding "private" to the class definition makes the constructor private.
  • "apply" is a special method: "blah.apply(something)" is equivalent to "blah(something)"
  • "apply" has a cousin "update" and takes 2 parameters

Here is a code that demonstrates some of the above mentioned features:

import scala.collection.mutable._

class Pen private (val color: String) {
    println(color + " pen being created")
}

// companion object - singleton
object Pen {
    val pens : Map[String, Pen] = Map()
    def createPen(color: String) = {
        if (!pens.contains(color))
            pens(color) = new Pen(color)
            // == pens.update(color, new Pen(color)
        pens.get(color)
    }
}

val bluePen = Pen.createPen("blue")
val bluePen2 = Pen.createPen("blue")
val redPen = Pen.createPen("red")

Running this code shows that "blue" pen is created only once and cached during second attempt. Notice, how the Pen is created using "createPen" factory method. This code can be changed to use "apply" as:

import scala.collection.mutable._

class Pen private (val color: String) {
    println(color + " pen being created")
}

// companion object - singleton
object Pen {
    val pens : Map[String, Pen] = Map()
    def apply(color: String) = {
        if (!pens.contains(color))
            pens(color) = new Pen(color)
        pens.get(color)
    }
}

val bluePen = Pen("blue")
val bluePen2 = Pen("blue")
val redPen = Pen("red")

Notice how default constructors instead of the factory pattern are now used.

Here is a piece of code that has two classes with similar functionality:

class Human(val name: String) {
 def listen = println("I am " + name + " your friend")
}

class Animal(val name: String)

class Dog(override val name: String) extends Animal(name) {
 def listen = println("I am " + name + " your friend")
}

val peter = new Human("Peter")
peter.listen

val rover = new Dog("Rover")
rover.listen

This violates the DRY principle. Scala Traits allows to encapsulate the code as shown below:

trait Friend {
 val name: String
 def listen = println("I am " + name + " your friend")
}

class Human(val name: String) extends Friend

class Animal(val name: String)

class Dog(override val name: String) extends Animal(name) with Friend

val peter = new Human("Peter")
peter.listen

val rover = new Dog("Rover")
rover.listen


// include trait at an object level
class Cat(override val name: String) extends Animal(name)

val molly = new Cat("Molly") with Friend
molly.listen
  • XML processing is a first class citizen in Scala
val xml = therethere
println(xml)

// XPath query
println(xml \\\\ "@greet")
println(xml \\\\ "where")
val stock = Map("APPL" -> 250, "GOOG" -> 300)

def createStock() = {
 stock.map { entry =>  }
}

// Scala code within XML
val xml = { createStock() }

println(xml)

Here is the last exercise from the workshop: Use Yahoo Weather API to find the temperature of Denver, CO:

import scala.xml._
import scala.io._
import java.net._

val theURL = "http://weather.yahooapis.com/forecastrss?w=2391279&u=f"

val xmlString = Source.fromURL(new URL(theURL)).mkString
//println(xmlString)    // for debugging

val xml = XML.loadString(xmlString)

val city = xml \\\\ "location" \\\\ "@city"
val state = xml \\\\ "location" \\\\ "@region"
val temperature = xml \\\\ "condition" \\\\ "@temp"

println("Temperature in " + city + ", " + state + " is " + temperature)
  • Actors enable concurrency in Scala, "receive" is used to receive the response from each Actor
  • Don't use "receive" outside, use receive within
  • OK to share Java code within Scala only if its mutable
  • Scala has "tuples", are immutables, and really good candidate for concurrency

Here is a sample code refactoring the above code in a method, called 50 times in a loop, printed once using traditional method invocation and once using Actors. The total time taken for the two set of executions is then printed.

import scala.xml._
import scala.io._
import java.net._
import scala.actors._
import Actor._

def getTemperature(woeid: Int) = {

    val theURL = "http://weather.yahooapis.com/forecastrss?w=" + woeid + "&u=f"

    val xmlString = Source.fromURL(new URL(theURL)).mkString
    val xml = XML.loadString(xmlString)

    val city = xml \\\\ "location" \\\\ "@city"
    val state = xml \\\\ "location" \\\\ "@region"
    val temperature = xml \\\\ "condition" \\\\ "@temp"

    (city, state, temperature)      // tuples are immutable
                                    // good candidates for concurrency
}

val start = System.nanoTime
for (woeid <- 2391250 to 2391299) {
    println(getTemperature(woeid))
}
val end = System.nanoTime
println("Time taken (without Actor): " + (end - start)/100000000.0) 

// Now dispatching to multiple actors
val start2 = System.nanoTime
val caller = self               // self is a pointer to my actor
for (woeid <- 2391250 to 2391299) {
    actor { caller ! getTemperature(woeid) }      // Dispatch 50 actors
}

for (woeid <- 2391250 to 2391299) {
    receive {
       case msg => println(msg)
    }
}
val end2 = System.nanoTime

println("Time taken (with Actor): " + (end2 - start2)/100000000.0)

A sample result from running this script showed the results:

Time taken (without Actor): 171.62816
Time taken (with Actor): 29.05179

As you can see the difference is quite evident - approx 6x better performance when using Actors.

Overall, super excited after writing so much Scala code and learned something new.

Thank you Venkat for yet another great workshop!

Technorati: conf uberconf scala java workshop

Comments:

Hi,

I'm very sorry to say but some of your examples just look very ugly and are unnecessary complex.

I wouldn't have expected that from someone working at the "new Java company", but maybe your just at some managing position and not a developer.

For instance your factorial method, what's wrong with:

def fact(number: Int): Int =
if (number < 2) 1
else number \* fact(number - 1)

(Although I would propose using BigInt, because factorials become big quite fast.)
Notice that this code is tail recursive and does not incure any overhead.

Posted by steve on June 18, 2010 at 04:40 AM PDT #

Steve,

Agreed, the code could certainly be written more elegant. These are merely notes captured form a workshop for Java programmers who had no idea of Scala.

Posted by Arun Gupta on June 18, 2010 at 04:46 AM PDT #

I intend to learn a scripting language, and I have two choices, groovy+grails, and scala+lift.

Scala as a lang seems to be superior compared to Groovy, yet Grails is much more mature compared to Lift.

I'm really confused. Your advice would be appreciated.

Posted by Muhammed Al-Qaimari on June 22, 2010 at 06:03 PM PDT #

great post,

I hope it will help convincing the conservative part of the Java programming community to switch to Scala instead of becoming the "21st century Cobol programmers"

Luc

Posted by Luc Duponcheel on June 22, 2010 at 06:57 PM PDT #

about defining factorial for BigInt's:

one of the benefits of Scala is exactly the fact that, for BigInt's you can also code it as

def factorial(x: BigInt): BigInt =
if (x == 0) 1 else x \* factorial(x - 1)

while in Java you would have to write
something like

import java.math.BigInteger
import static java.math.BigInteger.ONE
import static java.math.BigInteger.ZERO

def factorial(x: BigInteger): BigInteger =
if (x == ZERO)
ONE
else x.multiply(factorial(x.subtract(ONE)))

Luc

Posted by Luc Duponcheel on June 22, 2010 at 07:05 PM PDT #

Arun, the fact version in your comment is not tail recursive. If anything needs to happen after the recursive call, the function won't be tail recursive; you need an accumulator to avoid the need for an operation to be performed after the recursive call (multiplication by number in your version).

Posted by Cristian Ferretti on June 23, 2010 at 12:36 AM PDT #

Steve, the fact version in your comment is not tail recursive. If anything needs to happen after the recursive call, the function won't be tail recursive; you need an accumulator to avoid the need for an operation to be performed after the recursive call (multiplication by number in your version).

Posted by Cristian on June 23, 2010 at 12:37 AM PDT #

Arun,
Thanks for the examples!
your time measurement for the actor example is even more convincing, if you said something about the number of processors used.
Fabiano

Posted by Fabiano Henrique on June 23, 2010 at 05:56 PM PDT #

hey hii ...sir cn u plz help me in learning java...

Posted by preeti phogat on June 25, 2010 at 06:34 PM PDT #

Post a Comment:
Comments are closed for this entry.
About

profile image
Arun Gupta is a technology enthusiast, a passionate runner, author, and a community guy who works for Oracle Corp.


Java EE 7 Samples

Stay Connected

Search

Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today