Languages On The JVM - Groovy, Ruby, Scala, Clojure
Languages On The JVM - Groovy, Ruby, Scala, Clojure
Survey of Dynamic
Languages on the
JVM
Groovy, Ruby, Scala, Clojure
2
What to (Not) Expect
> Discussion on a small > “Hello World”
subset of the languages > Coverage of all features
> Highlight interesting > Which is a 'better'
language features language
> How the features are used > An apple to apple
> Contrast with Java comparison
> Java bashing
3
Groovy
groovy.codehaus.org/
4
Language Features – 1
> Object oriented programming language
> Syntax is very similar to Java – feels very much like Java
• Runs Java sources files
> Compact and concise syntax
• Optional semi colon and parenthesis
• Native syntax for list, maps and regex
> Seamless bi directional integration with Java
• Groovy extending Java class implementing Groovy interfaces
• Reuse Java's infrastructure – classes, security, threads, etc
> Closure, properties and operator overloading support
> Builder library to easily created nested data
5
Language Features – 2
> Easy integration with Java application with JSR-223
• Only one JAR – embeddable/groovy-all-1.x.y.jar
Probably one of the best feature
> MOP provides the meta programming capabilities
• A runtime layer which any application can participate
6
A Valid Java Program
import java.util.*;
public class Erase {
private List<String> filterLongerThan(List<String> list, int len) {
List<String> result = new ArrayList<String>();
for (String n: list)
if (n.length() <= len)
result.add(n);
return (result);
}
public static void main(String... args) {
List<String> names = new ArrayList<String>();
names.add(“Fred”); names.add(“Barney);
names.add(“Wilma”); names.add(“Betty”);
System.out.println(names);
Erase e = new Erase();
List<String> shortNames = e.filterLongerThan(names, 5);
System.out.println(shortNames);
}
}
7
A Valid Groovy Program
import java.util.*;
public class Erase {
private List<String> filterLongerThan(List<String> list, int len) {
List<String> result = new ArrayList<String>();
for (String n: list)
if (n.length() <= len)
result.add(n);
return (result);
}
public static void main(String... args) {
List<String> names = new ArrayList<String>();
names.add(“Fred”); names.add(“Barney);
names.add(“Wilma”); names.add(“Betty”);
System.out.println(names);
Erase e = new Erase();
List<String> shortNames = e.filterLongerThan(names, 5);
System.out.println(shortNames);
}
}
8
Groovy Way
Automatically imports java.util.*
9
Example – A Groovy Class
public class Person { Map literal
def props = [:]
Statically type
String name Interpolated string
int age = 45 Weakly type
def email
String toString() { “${name}, ${age}, ${gender}“}
Object get(String n) { props[n] }
void set(String n, Object v) { props[n] = v }
}
Dynamic properties
if (person.isAdult())
...
16
Example – D&D Style Die Roll
Integer.metaClass.getProperty = { String sym ->
//Check if sym is in 'd<digit><digit>' format
if (!(sym ==~ /^d\d+$/))
return (-1)
def face = sym.split(/d/)[1].toInteger()
def rand = new Random()
def result = []
delegate.times {
result += (Math.abs(rand.nextInt()) % face) + 1
}
result
}
//D&D style dice roll
println 5.d10
[2, 7, 5, 4, 10]
17
Ruby
www.ruby-lang.org
18
Language Features
> Supports multiple programming paradigm
• Imperative, object oriented, functional and reflective
> Excellent support for reflective programming /
metaprogramming
• Ruby re-introduce to developers
> Continuation support
• Freeze a point in the application and return to it later
> Supports reuse through inheritance, mixins and open
classes
• Open classes is the ability to modify and existing class including
those from the host library
Eg. add rot13() method to java.lang.String
19
Example – A Ruby Class
Class member Create getter/setter for
class Song
@@plays = 0 members
attr_accessor :name, :artist, :duration
def initialize(n, a, d) Denotes symbol
@name = n; @artist = a; @duration = d
end
def duration_in_minutes
@duration / 60
end Instance member
def duration_in_minutes=(v)
@duration = v * 40
end Methods
def play
@@plays += 1
end
end
20
Example – A Ruby Session
s = Song.new("Cavatina", "John Williams", 200)
puts s
#<Song:0x9dca26>
s.duration_in_minutes = 4
s.play
Adding a new method to class
class Song
def to_s
"song = #{@name}, artist = #{@artist}, duration =
#{@duration}, plays = #{@@plays}"
end
end
puts s
song = Cavatina, artist = John Williams, duration = 200,
plays = 1
21
Objects and Method Calls
> Everything in Ruby is an object
• Objects, things that look like primitive and classes
24
Example – Object Instantiation
> Set the creation time on an object if the object has a
property call timestamp
Rename new to old_new
28
callcc
> callcc to construct a continuation object in Ruby
• Encapsulates the state of the application up to callcc
• Use the continuation object to jump to just after the callcc
result = 1
i = 1
callcc {|$cont_obj|}
31
Scala
www.scala-lang.org
32
Language Features – 1
> A hybrid of object and functional
• Supports mutable and immutable (functional) structures
• Defaults to immutable for collections
> Objects, singletons and traits
• Singleton is a language concept
• Very similar to interfaces but with fully implemented methods
Cannot be instantiated, can only be mixed into a class or object
• Supports operator overloading
Operators are all method calls
> Statically typed – unique in the world of script language
• Can infer types from code during declaration
• Easily implement new types and corresponding operations
• Supports user define implicit type conversion
33
Language Features – 2
> Statically typed higher order functions
• More rigorous in what you can pass to a method
> Supports many high level concurrency abstraction
• Monitors, atomic variables, semaphores, workers, channels, etc
• Erlang style actors
34
Statically Typed
> Must provide type in method definition
• Elsewhere Scala can infer type from the context
var map = Map[Int, String](1 -> “Cat”, 2 -> “Dog”)
• Method return type, variable declaration
> Including closure / functions types
• var myfunc: ((Int, Int) => Complex) = null
Method declaration
def sumOfFactors(number: Int): Int = {
var sum = 0
for (i <- 1 to number)
Inferring from
if ((sum % i) == 0) context
sum += i
sum
}
35
Defining Classes
The minimal class
class Person(val name: String)
Default constructor
class Employee(override val name: String
, val id: String) extends Person(name) {
var salary: Double = _
def this(name: String, id: String, _salary: Double) {
this(name, id)
salary = _double Overloaded constructor
}
def calculateSalary() = {
salary
}
override def toString(): String = name + “(“ + id + “)”
}
38
Traits
> Similar to interfaces with partial implementations
trait Greetings {
def sayHello(name: String) = “Hello “ + name
}
• Mixin to instance
Only applicable if there are no abstract methods
39
Selective Mixin
> Can enforce mixing traits only into certain classes
• By extending from a class
> Late binding with super object
> Resolution of super proceeds from right to left
• Eg class A extends B with TraitA with TraitB
• TraitB → TraitA → A – assuming B is a class
• Excellent for implementing decorator or chain-of-command
pattern
40
Example – Selective Mixin – 1
class Person(val name: String) {
def calculateSalary(base: Double) = base
}
class Employee(...) extends Person(...) {
def mySalary() = calculateSalary(salary)
... Can only be mixin to
} classes that extends
trait SpotBonus extends Person { from Person
override def calculateSalary(base: Double) =
super.calculateSalary(base + (base * 0.05))
}
41
Example – Selective Mixin – 2
println(“salary = “ + fred.mySalary)
42
Operators on Types
> All method calls, no notion of operators
• Operator precedence is based on ordering of symbols
• Eg. all letters, |, ^, &, < >, = !,:, + -, * % /, all other
special characters
• Unary operators, prefixed with unary_
class Employee(override name: String ... //As before
def +(_salary: Double) = this.salary + _salary
def -:(_salary: Double) = this.salary - _salary
def unary_>>!(): Employee = ... //promotion
def unary_<<!(): Employee = ... //demotion
45
Determining a Prime Number
> Is x a prime number?
> Does x have a factor in the range of 3 to (x – 1)?
> Eg. Is 97 a prime number?
• Are there any factors in 3 to 96
> For larger number, partition range and find factors in
parallel
> Eg. 97, partition size of 20
• 3 – 22
• 32 – 42
• 43 – 62 97 is a prime number if there are no
factors in these ranges
• 63 – 82
• 83 – 96
46
Example – Determining Prime – 1
import scala.actors.Actor._
val caller = self
def haveFactorInRange(primSusp: Int, min: Int, max: Int): Boolean = {
((min to max).filter { x => ((primSusp % x) == 0) }.size != 0)
}
//No checking done
def isPrime(primSusp: Int): Boolean = {
val range = primSusp - 3
val partition = (range / 20) + (if ((range % 20) > 0) 1 else 0)
var haveFactor = false
for (i <- 0 until partition) {
val min = 3 + (i * 20) Creates an actor and
val max = if ((min + 19) > primSusp) starts it
(primSusp - 1) else (min + 19)
actor {
caller ! haveFactorInRange(primSusp, min, max)
}
} Execute the function and send
... the result to the collator 47
}
Example – Determining Prime – 2
48
Clojure
http://clojure.org
49
Language Features – 1
> Functional language
• Verb (functions) is the central theme, not noun (objects)
• No side effects – only depends on its arguments
Most Java method do not qualify as functions
• Give the same argument, will return the same result EVERYTIME
Functions are stateless
f(x) = f(y) if x is equals y
> Higher order functions
• f(x) → g(y) where x and y can be functions
• Closure is very natural
(defn make-greeter [greetings]
(fn [name] (format “%s, %s” greetings name)))
((make-greeter “Bonjour”) “Jean”) → “Bonjour, Jean”
Clojure
(defn fac [f]
(if (zero? f)
1
(* f (fac (dec f)))))
52
Calculating 10! with Sequences
> Create a list of values, apply a function over these value
• x! = (x – 1)! * x
(appy * (range 1 11))
(range 1 11) → (1 2 3 4 5 6 7 8 9 10)
(apply * (1 2 3 4 5 6 7 8 9 10))
55
Creating a Swing Frame
;Create a button
(def button
(doto (JButton. "Press me")
(.addActionListener act-listener)))
;Create a panel
(def panel Apply all following
(doto (JPanel.) methods to the instance
(.add button)))
;Create a frame
(doto (JFrame.)
(.setTitle "Hello")
(.setDefaultCloseOperation JFrame/DISPOSE_ON_CLOSE)
(.add panel)
(.addWindowListener win-listener)
(.pack)
(.setLocationRelativeTo nil) Accessing static member
(.setVisible true))
56
Concurrency
> Supports 4 concurrency model
• Agents – actors but pass functions instead of messages
• Atoms – like java.util.concurrent.atomic
• References – database like transaction semantics
a.k.a Software Transaction Memory (STM)
• Vars – thread local
Agents Atoms References Vars
Shared X X X
Isolated X
Synchronous X X
Asynchronous X
Coordinated X
Autonomous X X
57
Sharing Data via Managed References
foo
Thread A
Data
Thread A @foo
foo Data
Deference to access
Thread B immutable data
58
Agents
> Use to manage independent states
> Send functions to modify the state of the agent
• Functions are executed asynchronously
• Only one function is evaluated at a time
Some notion of ordering
60
Using ref
(defstruct emp :id :name)
(def foo (ref (struct '123 “Fred”))) → {:id 123 :name “Fred”}
@foo → {:id 123 :name “Fred”}
time
foo alter by another transaction Transaction is retried
> At the start of the transaction
• Get an in transaction copy of foo's value (@foo)
• Value will never be inconsistent – data is immutable
> At the end of the transaction
• foo is check if it has changed during the transaction
-1
f (f(x)) = x where x is is the value of foo at the start of the transaction
time
foo alter by another transaction Function is retried
> Same semantics as alter
• Except at the end of the transaction
• If foo is altered, the function is retried
> Function must be commutative and without side effects
• Eg. deposit is a commutative operation
You can invoke deposit in any order, the final state of the account will still
be consistent
Withdrawal is not commutative
63
Lee Chuk Munn
Staff Engineer
chuk-munn.lee@sun.com
64
64
Relational Algebra (or SQL)
> Nice set of relational algebra to work on sets
• Relational algebra is the basis of SQL
>
65
Immutable Data
x y
z x y
66