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
Related posts:- Uber Conf 2010 – Day 4 Report – OSGi/Java EE in GlassFish and Getting Started with Clojure
- Uber Conf 2010 – Day 3 Report
- Java EE 6 & GlassFish – Spark IT 2010, Ruby Conf India 2010, Tech Days 2010
- Java EE 6, GlassFish, NetBeans, Eclipse, OSGi at Über Conf: Jun 14-17, Denver
- Über Conf Day 2 Trip Report