0% found this document useful (0 votes)
1K views66 pages

Languages On The JVM - Groovy, Ruby, Scala, Clojure

This document summarizes key features of the dynamic programming language Groovy on the Java Virtual Machine. It provides examples of Groovy code and discusses how Groovy seamlessly integrates with Java while allowing for more concise syntax and dynamic features like closures and operator overloading. The document also briefly covers Ruby and how it supports multiple programming paradigms and excellent metaprogramming capabilities.

Uploaded by

chuk-lee-3725
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
1K views66 pages

Languages On The JVM - Groovy, Ruby, Scala, Clojure

This document summarizes key features of the dynamic programming language Groovy on the Java Virtual Machine. It provides examples of Groovy code and discusses how Groovy seamlessly integrates with Java while allowing for more concise syntax and dynamic features like closures and operator overloading. The document also briefly covers Ruby and how it supports multiple programming paradigms and excellent metaprogramming capabilities.

Uploaded by

chuk-lee-3725
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 66

Dynamic Languages for

the Java Virtual Machine


Lee Chuk Munn
Staff Engineer
1
Objective

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.*

Native list syntax

def names = ["Ted", "Fred", "Jed", "Ned"]


Creates an ArrayList
println names

def shortNames = names.findAll { Closure support


it.size() <= 3
}

def diff = names - shortNames


print diff
Operator overloading

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

Person fred = new Person(name: 'Fred'


, email: 'fred@bedrock.com')
Constructor with
property/keyword
fred.gender = 'male' parameters

Adding a property dynamically


10
Operator Overloading
> Every operator can be overloaded via corresponding
method
• Eg. plus() for '+', leftShift() for '<<', etc.
> Special method for switch classification
• Override isCase()
Person fred = …
public class Family {
def members = [] Person wilma = …
def plus(Person o) { Family flintstones = …
members += o flintstone += fred + wilma
members
} Person barney = …
def plus(Family f) { Person betty = …
members += f.members Family rubble = …
members
rubble += barney + betty
}
}
11
Category
> Add temporary methods or behaviour to instances of
object code block
class StringCalcutation {
static def plus(String self, String operand) {
try {
return (self.toInteger()
+ operand.toInteger()).toString()
} catch (NumberFormatException f) {
return (self << operand)
}
}
}

println “43” + “43” → “4343”


use(StringCalculation) { Redefine the behaviour
of + in code block
println “43” + “43” → “86”
} Example adapted from Groovy in Action by Dierk Konig et al 12
Closure
> A piece of code that is wrapped in an object
• Anonymous functions/methods
Takes 2 parameters.
• Behaves like data, but can be invoked Closure has a default
value

def perform(int times, Closure c = {}) {


for (i = 0; i < times; i++)
c.call(i)
}

perform(3) { x -> println “hello: ${x}” }

Parameter Code block not executed but


pass to perform a parameter
13
Example – New Controls with Closure
def withLock(Lock l, Closure c) {
l.lock();
try {
c.call()
} finally {
l.unlock();
} Closure runs in the context of lock
}
Lock lock = new ReentrantLock()
withLock(lock) { println “I have acquired the lock” }

Closure with parameters


def logInfo = { logger, msg -> logger.log(Level.INFO, msg) }
withLock(lock
, logInfo.curry(Logger.getLogger("groovy")).curry("Hello"))

Use curry to wrap parameters


14
Meta Object Protocol
> Provides dynamic behaviour to Groovy
• Intercept method calls, create classes and methods, etc
> MOP consists of
• Formalized behaviour for resolving methods/properties
• Two major classes: GroovyObject and MetaClass
> Override methods in MetaClass to redefine behaviour
String.metaClass.constructor = { Replace the default
constructor = constructor
String.class.getConstructor(String.class)
constructor.newInstance((new Date()).toString())
}

println new String() → “Sat Nov 21 ...”

> Lots of libraries uses MOP


Example adapted from Groovy in Action by Dierk Konig et al 15
Example – ExpandoMetaClass
> Expando class allows developers to add methods to an
object dynamically
> Two variants
• Expando
• ExpandoMetaClass

def person = new ExpandoMetaClass(Person)


person.isAdult = { age >= 18 }

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

s = Song.new Invoking the new method on


the Song object
> Everything is a method call
• Message passing masquerading as method calls
• obj.fred is the same as obj.send(:fred)as
­ Method invocation means sending a message to the object
­ Use respond_to? to inspect if an object supports a particular message
• Methods can be invoked with our without parenthesis
­ Excellent for readability and DSL

x = 1 + 2 – 3 is equivalent to x = 1.+(2.send(:+, 3))

puts ugly_d.quack if ugly_d.respond_to? :quack


22
Reuse
> Inheritance – traditional OO way Inherit from Song
class KaraokeSong < Song
... This means super.to_s – from
def to_s context
super + “[#{@lyrics}]”
end
> Mixins – adding a module into a class or object
• Cannot be instantiated Mixin to class
or instance
module ClassName class Song
def class_name include ClassName
self.class.name
end s = Song.new(...).extend(ClassName)
end

> Open classes – adding methods to class or object


class String
def rot13
self.tr(“A-Ma-mN-Zn-z”, “N-Zn-zA-Ma-m”)
end
end 23
Metaprogramming with Ruby
> Technique by which a program can manipulate another
program or itself as their data
> Ruby relies on metaprogramming heavily
• Eg. in declaring properties
> Introspect into a a class, object or the running environment
• Eg. ObjectSpace.each_object(String) {|x| puts x}
> Allows you to trap interesting behaviour and override or
enhance them
• Similiar AOP
• Eg. creating a method, instantiating an object, invoking a missing
method, querying if a member is defined, etc.
• Eg. emulate ExpandoMetaClass in Groovy by trapping
undefined method names

24
Example – Object Instantiation
> Set the creation time on an object if the object has a
property call timestamp
Rename new to old_new

class Class Provide our own 'new'


alias_method :old_new, :new
def new(*args)
result = old_new(*args)
result.timestamp = Time.now if defined?(result.timestamp)
result
end
end
Set the time if timestamp exists

Example adapted from “Programming Ruby 2nd Edition by Dave Thomas” 25


Example – Implementing ExpandoMetaClass
> A Groovy feature that allows you to add methods to
instances on the fly
Add the method to
class ExpandoMetaClass instance
def method_missing(name, *args)
if args[0].is_a?(Proc)
self.class.instance_eval do
define_method(name.to_s.chomp("="), args[0])
end
else
super class Foo < ExpandoMetaClass
end end
end
end f = Foo.new
f.greet = lambda {|t| "Hello #{t}!"}
f.greet "Fred"
26
Example – JavaBean Style Properties
class Module
def java_bean(*syms)
syms.each do |s|
pn = s.to_s.split("_").collect!{|x| x.capitalize}.join
class_eval %{
def get#{pn}
@#{pn} class Demo
end java_bean :my_name
} …
class_eval %{
end
def set#{pn}(v)
@#{pn} = v
end demo = Demo.new
} demo.setMyName(“fred”)
end puts demo.getMyName
end
end

Caution: This will probably infuriate Rubyists 27


Continuations
> Abstract representation of “the rest of the code to be
executed”
if (i > 10) The continuation of “if (i > 10)” is
puts “i > 10”
puts “i > 10” iff i > 10
else
puts “i < 10” puts “i < 10” iff i < 10
end
> Uses of continuations
• Coroutines, escape and reenter loops/recursion, debugger, need
to backtrack
• See
http://repository.readscheme.org/ftp/papers/PLoP2001%5Fdfer
guson0%5F1.pdf
• Eg. Able to return to the point of exception after handling the
exception

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|}

Ruby passes a continuation


result *= i object to block
i += 1
$cont_obj.call if (i <= 10)

Returns to the statement just


after the callcc
29
Example – Coroutine 1
def ping
puts "PING 1"
save_and_resume($ping_cont,
pong
nil)
PING 1
puts "PING 2"
save_and_resume($ping_cont, $pong_cont)
PONG 1
puts "PING 3" PING 2
save_and_resume($ping_cont, $pong_cont)
end PONG 2
def pong
puts "PONG 1" PING 3
save_and_resume($pong_cont,
puts "PONG 2"
$ping_cont)
PONG 3
save_and_resume($pong_cont, $ping_cont)
puts "PONG 3"
save_and_resume($pong_cont, $ping_cont)
end
ping
Example adapted from “Call with Current Continuation
Patterns” by Darrell Ferguson, Dwight Deugo 30
Example – Coroutine 2

Create a current continuation


for the current location

def save_and_resume(save_cont, resume_cont)


callcc {|save_cont|}
resume_cont.call unless resume_cont == nil
end

Resume the other routine

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 + “)”
}

var fred = new Employee(“James”, “007”)


println(fred name) //Equivalent to fred.name 36
Singletons
> Refer to as companion objects in Scala
• Use extensively in Scala class libraries
> Defined in the same file as the class
• Can access private constructors
object Employee {
def apply(name: String, id: String) Curried function
= new Employee(name, id)
def apply(name: String, id: String, salary: Double)
(verify: (String, String, Double)=> Option[Employee])
Singleton :Option[Employee] = {
if (verify(name, id, salary))
Some(new Employee(name, id, salary))
else
Closure's signature
None
}
} Option indicates we may not
be getting any result 37
Example – Singletons as Factories

var fred = Employee(“Fred”, “007”)

var obj = Employee("Barney", "001", 12000)


{(name, id, salary) => (salary <= 10000)}
Return type is not Employee
Curried function so
var barney: Employee closure appears outside
if (obj.isEmpty) { of formal parameter list
println("Salary is too high")
} else {
barney = obj.get
}

38
Traits
> Similar to interfaces with partial implementations
trait Greetings {
def sayHello(name: String) = “Hello “ + name
}

> Mixed in to classes or selectively to object instances


• Mixin to class
class Employee(override val name: String, val id: String)
extends Person(name) with Greetings {

• Mixin to instance
­ Only applicable if there are no abstract methods

val fred = new Employee(“Fred”, “007”) with Greetings

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))
}

trait ThirteenMonth extends Person {


override def calculateSalary(base: Double) =
super.calculateSalary(base + base)
}

41
Example – Selective Mixin – 2

val fred = new Fred(“Fred”, “007”, 5000)


with AnnualLeave with ThirteenMonth

println(“salary = “ + fred.mySalary)

Resolution goes from right to left


Fred.mySalary
ThirteenMonth.calculateSalary
AnnualLeave.calculateSalary
Fred.calculateSalary

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

fred.salary = fred + 1000 //Method call fred.+(1000)


fred >>! //promote fred
100 -: fred

Instance to follow method


43
Implicit Type Conversion
> Most language have build in implicit conversion
• Eg. byte + int – byte is converted to int
> Scala allows you to define implicit conversion
• Use implicit keyword on method
var yesterday = 1 days ago Converter that takes 1 and
return ???.days(“ago”)
class DateHelper(num: Int) {
def days(when: String) = {
var date = Calendar.getInstance()
when match {
case “ago” => date.add(Calendar.DAY_OF_MONTH, -num)
...
}
date.getTime()
}
}
def implicit convertInt2DateHelper(num: Int) = new DateHelper(num)
*
Adapted from Programming Scala by Venkat Subramaniam 44
Concurrency
> Lots of abstraction to support concurrency and asynchrony
• Signals, monitors, atomic objects, semaphores, workers, mail
boxes, actors etc
> Actor based model
• A computation entity that inherently concurrent
• Communicate by send it messages
• Can change its state or spawn new actors based on messages
> Two ways of using actors
• actor method
• Extend Actor class
> Communications
• ! to send a message
• receive – case to select message based on type

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

def isPrime(basis: Int): Boolean = {


... Waits for messages
var haveFactor = false from actors
...
(0 until partition).foreach { x =>
receive {
case ans: Boolean =>
haveFactor = haveFactor || ans
case _ =>
}
}
Match the message type
against the discriminator
!haveFactor
}

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”

Lambda Parameter Body 50


Language Features – 2
> All data is immutable – no data is ever change*
(def foo '(a b c)) → (a b c) Reassigned
(concat foo '(x y z)) → (a b c x y z)
foo → (a b c)
(def foo (concat foo '(x y z))) → (a b c x y z)
> Everything is a sequence – with abstractions
• List – (a b c)
• Vector – [a b c]
• Set – #{a b c}
• Map – {:x a, :y b, :z c}
> Homoiconic – the data structure is the language
• No language syntax – just have to know how to write parenthesis
• Evaluation rules – first element is the function name
­ Everything else are parameters
*except for refs
51
Calculate 10!
Java
public int fac(final int f) {
int tot = 1;
for (int i = 1; i < f; i++
tot *= i
return (tot);
Function defintion
}

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))

> Lazy (is a virtue) and infinite sequences


• Infinite sequence that will only generate the next value iff required

;generate an infinite factorial list


(defn fac Generate an infinite
Overloaded function sequence of factorials
([] 1)
([x] (apply * (range 1 (inc x)))))
(defn fac-list [] (map fac (iterate inc 1)))
Take 5 from list
(take 5 (fac-list)) → (1 2 6 24 120) 53
Calling Java
> Importing Java classes
(import '(java.awt.event ActionEvent)
> Instantiating Java classes
(def f (new JFrame “Thisis a frame”))
(def f (JFrame. “This is a frame”))
> Accessing methods and members
(. f setVisible true)
(.setVisible f true)
(.getDefaultButton (.getRootPane f))
→ (.. f getRootPane getDefaultButton)
> Implementing interfaces and extending classes
• With type hints Type hint
(proxy [ActionListener][]
(actionPerformed [#^ActionEvent a-evt] ( … ))) 54
Creating a Swing Frame
;Import the relevant classes
(import
'(javax.swing JFrame JPanel JButton)
'(java.awt.event ActionListener
ActionEvent WindowAdapter WindowEvent))

;Implement an ActionListener Implements the


(def act-listener ActionListener
(proxy [ActionListener] []
(actionPerformed [a-evt]
(println (format "Button %s pressed"
(. a-evt getActionCommand))))
)
)

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

bar Most programming languages


Thread B eg. Java, C, etc.

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

(def foo (agent 0))


@foo → 0
(inc @foo) → 1 @foo is immutable
@foo → 0

(send foo inc)

... after some time ...


@foo → 1
59
References and STM
> References (ref) provide database like transaction
> Software transactional memory
• All or nothing
• Data are not visible until you commit
• All changes happens at constant time
­ You see all the changes at once
> No inconsistent data during transaction
• Thanks to Clojure's immutable data
> All references must occur in a transaction
• Create references with ref
• Use either alter or commute to change the ref
• dosync execute expressions in a transaction
­ alter and commute will only run in dosync

60
Using ref
(defstruct emp :id :name)
(def foo (ref (struct '123 “Fred”))) → {:id 123 :name “Fred”}
@foo → {:id 123 :name “Fred”}

(assoc @foo :gender 'male)


→ {:id 123 :name “Fred” :gender male}
@foo → {:id 123 :name “Fred”}
Create a transaction
(dosync
(alter foo assoc :gender 'male))
→ {:id 123 :name “Fred” :gender male}
(dosync
(commute foo assoc :gender 'male))
→ {:id 123 :name “Fred” :gender male}

@foo → {:id 123 :name “Fred” :gender male}


61
Handling Conflicts with alter
(dosync (alter foo assoc ...))

(assoc ...) (assoc ...)

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

• If it has, transaction is retried


­ Body of transaction must be side effect free
• Otherwise transaction commits → new value visible to all 62
Handling Conflicts with commute
(dosync (commute foo assoc ...))

(assoc ...) (assoc ...)

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

(def x '(a b c)) a b c

(def y (rest x)) a b c

x y

(def z (into x '(d))) d a b c

z x y
66

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy