languages on the jvm - groovy, ruby, scala, clojure

66
1 Dynamic Languages for Dynamic Languages for the Java Virtual Machine the Java Virtual Machine Lee Chuk Munn Staff Engineer

Upload: chuk-lee-3725

Post on 18-Nov-2014

1.080 views

Category:

Documents


1 download

DESCRIPTION

A look at 4 languages running on JVM.

TRANSCRIPT

Page 1: Languages on the JVM - Groovy, Ruby, Scala, Clojure

1

Dynamic Languages forDynamic Languages forthe Java Virtual Machinethe Java Virtual MachineLee Chuk MunnStaff Engineer

Page 2: Languages on the JVM - Groovy, Ruby, Scala, Clojure

2

Objective

Survey of Dynamic Languages on the

JVM

Groovy, Ruby, Scala, Clojure

Page 3: Languages on the JVM - Groovy, Ruby, Scala, Clojure

3

What to (Not) Expect

> Discussion on a small subset of the languages

> Highlight interesting language features

> How the features are used

> Contrast with Java

> “Hello World”

> Coverage of all features

> Which is a 'better' language

> An apple to apple comparison

> Java bashing

Page 4: Languages on the JVM - Groovy, Ruby, Scala, Clojure

4

Groovygroovy.codehaus.org/

Page 5: Languages on the JVM - Groovy, Ruby, Scala, Clojure

5

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

Page 6: Languages on the JVM - Groovy, Ruby, Scala, Clojure

6

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

Page 7: Languages on the JVM - Groovy, Ruby, Scala, Clojure

7

A Valid Java Programimport 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);

}}

Page 8: Languages on the JVM - Groovy, Ruby, Scala, Clojure

8

A Valid Groovy Programimport 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);

}}

Page 9: Languages on the JVM - Groovy, Ruby, Scala, Clojure

9

Groovy Way

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

println names

def shortNames = names.findAll { it.size() <= 3 }

def diff = names - shortNamesprint diff

Automatically imports java.util.*

Native list syntax

Creates an ArrayList

Closure support

Operator overloading

Page 10: Languages on the JVM - Groovy, Ruby, Scala, Clojure

10

Example – A Groovy Classpublic class Person {

def props = [:]String nameint age = 45def email String toString() { “${name}, ${age}, ${gender}“}Object get(String n) { props[n] } void set(String n, Object v) { props[n] = v }

}

Person fred = new Person(name: 'Fred', email: '[email protected]')

fred.gender = 'male'

Map literal

Statically type

Weakly typeInterpolated string

Dynamic properties

Constructor with property/keyword parameters

Adding a property dynamically

Page 11: Languages on the JVM - Groovy, Ruby, Scala, Clojure

11

Operator Overloading

> Every operator can be overloaded via corresponding method• Eg. plus() for '+', leftShift() for '<<', etc.

> Special method for switch classification• Override isCase()

public class Family {def members = []def plus(Person o) {

members += omembers

}def plus(Family f) {

members += f.membersmembers

}}

Person fred = …Person wilma = …Family flintstones = …flintstone += fred + wilma

Person barney = …Person betty = …Family rubble = …rubble += barney + betty

Page 12: Languages on the JVM - Groovy, Ruby, Scala, Clojure

12

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

println “43” + “43” → “86”}

Redefine the behaviour of + in code block

Example adapted from Groovy in Action by Dierk Konig et al

Page 13: Languages on the JVM - Groovy, Ruby, Scala, Clojure

13

Closure

> A piece of code that is wrapped in an object• Anonymous functions/methods• Behaves like data, but can be invoked

def perform(int times, Closure c = {}) {for (i = 0; i < times; i++)

c.call(i)}

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

Code block not executed but pass to perform a parameter

Parameter

Takes 2 parameters. Closure has a default value

Page 14: Languages on the JVM - Groovy, Ruby, Scala, Clojure

14

Example – New Controls with Closuredef withLock(Lock l, Closure c) {

l.lock();try {

c.call()} finally {

l.unlock();}

}Lock lock = new ReentrantLock()withLock(lock) { println “I have acquired the lock” }

def logInfo = { logger, msg -> logger.log(Level.INFO, msg) }withLock(lock

, logInfo.curry(Logger.getLogger("groovy")).curry("Hello"))

Closure runs in the context of lock

Use curry to wrap parameters

Closure with parameters

Page 15: Languages on the JVM - Groovy, Ruby, Scala, Clojure

15

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

> Lots of libraries uses MOP

String.metaClass.constructor = {constructor =

String.class.getConstructor(String.class)constructor.newInstance((new Date()).toString())

}

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

Replace the default constructor

Example adapted from Groovy in Action by Dierk Konig et al

Page 16: Languages on the JVM - Groovy, Ruby, Scala, Clojure

16

Example – ExpandoMetaClass

def person = new ExpandoMetaClass(Person)person.isAdult = { age >= 18 }

if (person.isAdult())...

> Expando class allows developers to add methods to an object dynamically

> Two variants• Expando• ExpandoMetaClass

Page 17: Languages on the JVM - Groovy, Ruby, Scala, Clojure

17

Example – D&D Style Die RollInteger.metaClass.getProperty = { String sym ->

//Check if sym is in 'd<digit><digit>' formatif (!(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 rollprintln 5.d10[2, 7, 5, 4, 10]

Page 18: Languages on the JVM - Groovy, Ruby, Scala, Clojure

18

Rubywww.ruby-lang.org

Page 19: Languages on the JVM - Groovy, Ruby, Scala, Clojure

19

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

Page 20: Languages on the JVM - Groovy, Ruby, Scala, Clojure

20

Example – A Ruby Class

class Song@@plays = 0attr_accessor :name, :artist, :durationdef initialize(n, a, d)

@name = n; @artist = a; @duration = denddef duration_in_minutes

@duration / 60enddef duration_in_minutes=(v)

@duration = v * 40enddef play

@@plays += 1end

end

Methods

Instance member

Class member Create getter/setter for members

Denotes symbol

Page 21: Languages on the JVM - Groovy, Ruby, Scala, Clojure

21

Example – A Ruby Sessions = Song.new("Cavatina", "John Williams", 200)puts s#<Song:0x9dca26>

s.duration_in_minutes = 4s.play

class Song def to_s

"song = #{@name}, artist = #{@artist}, duration = #{@duration}, plays = #{@@plays}"

endend

puts ssong = Cavatina, artist = John Williams, duration = 200, plays = 1

Adding a new method to class

Page 22: Languages on the JVM - Groovy, Ruby, Scala, Clojure

22

Objects and Method Calls

> Everything in Ruby is an object• Objects, things that look like primitive and classes

> 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

s = Song.new Invoking the new method on the Song object

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

puts ugly_d.quack if ugly_d.respond_to? :quack

Page 23: Languages on the JVM - Groovy, Ruby, Scala, Clojure

23

Reuse

> Inheritance – traditional OO way

> Mixins – adding a module into a class or object• Cannot be instantiated

> Open classes – adding methods to class or object

class KaraokeSong < Song...def to_s

super + “[#{@lyrics}]”end

Inherit from Song

This means super.to_s – from context

module ClassName def class_name

self.class.nameend

end

class Song include ClassName

s = Song.new(...).extend(ClassName)

Mixin to class or instance

class Stringdef rot13

self.tr(“A-Ma-mN-Zn-z”, “N-Zn-zA-Ma-m”)end

end

Page 24: Languages on the JVM - Groovy, Ruby, Scala, Clojure

24

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

Page 25: Languages on the JVM - Groovy, Ruby, Scala, Clojure

25

Example – Object Instantiation

class Classalias_method :old_new, :newdef new(*args)

result = old_new(*args)result.timestamp = Time.now if defined?(result.timestamp)result

endend

Rename new to old_new

Provide our own 'new'

Set the time if timestamp exists

> Set the creation time on an object if the object has a property call timestamp

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

Page 26: Languages on the JVM - Groovy, Ruby, Scala, Clojure

26

Example – Implementing ExpandoMetaClass

> A Groovy feature that allows you to add methods to instances on the fly

class ExpandoMetaClassdef method_missing(name, *args)

if args[0].is_a?(Proc)self.class.instance_eval do

define_method(name.to_s.chomp("="), args[0]) end

elsesuper

endend

end

Add the method to instance

class Foo < ExpandoMetaClassend

f = Foo.newf.greet = lambda {|t| "Hello #{t}!"}f.greet "Fred"

Page 27: Languages on the JVM - Groovy, Ruby, Scala, Clojure

27

Example – JavaBean Style Properties

Caution: This will probably infuriate Rubyists

class Moduledef java_bean(*syms)

syms.each do |s|pn = s.to_s.split("_").collect!{|x| x.capitalize}.joinclass_eval %{

def get#{pn}@#{pn}

end}class_eval %{

def set#{pn}(v)@#{pn} = v

end}

endend

end

class Demojava_bean :my_name…

end

demo = Demo.newdemo.setMyName(“fred”)puts demo.getMyName

Page 28: Languages on the JVM - Groovy, Ruby, Scala, Clojure

28

Continuations

> Abstract representation of “the rest of the code to be executed”

> Uses of continuations• Coroutines, escape and reenter loops/recursion, debugger, need

to backtrack• See

http://repository.readscheme.org/ftp/papers/PLoP2001%5Fdferguson0%5F1.pdf

• Eg. Able to return to the point of exception after handling the exception

if (i > 10)puts “i > 10”

elseputs “i < 10”

end

The continuation of “if (i > 10)” is

puts “i > 10” iff i > 10puts “i < 10” iff i < 10

Page 29: Languages on the JVM - Groovy, Ruby, Scala, Clojure

29

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 = 1i = 1callcc {|$cont_obj|}

result *= ii += 1$cont_obj.call if (i <= 10)

Ruby passes a continuation object to block

Returns to the statement just after the callcc

Page 30: Languages on the JVM - Groovy, Ruby, Scala, Clojure

30

Example – Coroutine 1def ping

puts "PING 1"save_and_resume($ping_cont, nil)pongputs "PING 2"save_and_resume($ping_cont, $pong_cont)puts "PING 3"save_and_resume($ping_cont, $pong_cont)

enddef pong

puts "PONG 1"save_and_resume($pong_cont, $ping_cont)puts "PONG 2"save_and_resume($pong_cont, $ping_cont)puts "PONG 3"save_and_resume($pong_cont, $ping_cont)

endping

PING 1PONG 1PING 2PONG 2PING 3PONG 3

Example – Coroutine 1

Example adapted from “Call with Current Continuation Patterns” by Darrell Ferguson, Dwight Deugo

Page 31: Languages on the JVM - Groovy, Ruby, Scala, Clojure

31

Example – Coroutine 2

def save_and_resume(save_cont, resume_cont)callcc {|save_cont|}resume_cont.call unless resume_cont == nil

end

Example – Coroutine

Create a current continuation for the current location

Resume the other routine

Page 32: Languages on the JVM - Groovy, Ruby, Scala, Clojure

32

Scalawww.scala-lang.org

Page 33: Languages on the JVM - Groovy, Ruby, Scala, Clojure

33

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

Page 34: Languages on the JVM - Groovy, Ruby, Scala, Clojure

34

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

Page 35: Languages on the JVM - Groovy, Ruby, Scala, Clojure

35

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

def sumOfFactors(number: Int): Int = {var sum = 0for (i <- 1 to number)

if ((sum % i) == 0)sum += i

sum}

Method declaration

Inferring from context

Page 36: Languages on the JVM - Groovy, Ruby, Scala, Clojure

36

Defining Classesclass Person(val name: String)

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

}def calculateSalary() = {

salary}override def toString(): String = name + “(“ + id + “)”

}

var fred = new Employee(“James”, “007”)println(fred name) //Equivalent to fred.name

Overloaded constructor

Default constructor

The minimal class

Page 37: Languages on the JVM - Groovy, Ruby, Scala, Clojure

37

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)

= new Employee(name, id)def apply(name: String, id: String, salary: Double)

(verify: (String, String, Double)=> Option[Employee]):Option[Employee] = {

if (verify(name, id, salary))Some(new Employee(name, id, salary))

elseNone

}} Option indicates we may not

be getting any result

Curried function

Singleton

Closure's signature

Page 38: Languages on the JVM - Groovy, Ruby, Scala, Clojure

38

Example – Singletons as Factories

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

var obj = Employee("Barney", "001", 12000){(name, id, salary) => (salary <= 10000)}

var barney: Employeeif (obj.isEmpty) {

println("Salary is too high")} else {

barney = obj.get}

Curried function so closure appears outside of formal parameter list

Return type is not Employee

Page 39: Languages on the JVM - Groovy, Ruby, Scala, Clojure

39

Traits

> Similar to interfaces with partial implementations

> Mixed in to classes or selectively to object instances• Mixin to class

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

trait Greetings {def sayHello(name: String) = “Hello “ + name

}

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

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

Page 40: Languages on the JVM - Groovy, Ruby, Scala, Clojure

40

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

Page 41: Languages on the JVM - Groovy, Ruby, Scala, Clojure

41

Example – Selective Mixin – 1class Person(val name: String) {

def calculateSalary(base: Double) = base}class Employee(...) extends Person(...) {

def mySalary() = calculateSalary(salary)...

}trait SpotBonus extends 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)}

Can only be mixin to classes that extends from Person

Page 42: Languages on the JVM - Groovy, Ruby, Scala, Clojure

42

Example – Selective Mixin – 2

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

println(“salary = “ + fred.mySalary)

Resolution goes from right to leftFred.mySalaryThirteenMonth.calculateSalaryAnnualLeave.calculateSalaryFred.calculateSalary

Page 43: Languages on the JVM - Groovy, Ruby, Scala, Clojure

43

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 beforedef +(_salary: Double) = this.salary + _salarydef -:(_salary: Double) = this.salary - _salarydef unary_>>!(): Employee = ... //promotiondef unary_<<!(): Employee = ... //demotion

fred.salary = fred + 1000 //Method call fred.+(1000)fred >>! //promote fred100 -: fred

Instance to follow method

Page 44: Languages on the JVM - Groovy, Ruby, Scala, Clojure

44

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

Converter that takes 1 and return ???.days(“ago”)

*Adapted from Programming Scala by Venkat Subramaniam

Page 45: Languages on the JVM - Groovy, Ruby, Scala, Clojure

45

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

Page 46: Languages on the JVM - Groovy, Ruby, Scala, Clojure

46

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• 63 – 82• 83 – 96

97 is a prime number if there are no factors in these ranges

Page 47: Languages on the JVM - Groovy, Ruby, Scala, Clojure

47

Example – Determining Prime – 1 import scala.actors.Actor._val caller = selfdef haveFactorInRange(primSusp: Int, min: Int, max: Int): Boolean = {

((min to max).filter { x => ((primSusp % x) == 0) }.size != 0)}//No checking donedef isPrime(primSusp: Int): Boolean = {

val range = primSusp - 3val partition = (range / 20) + (if ((range % 20) > 0) 1 else 0)var haveFactor = falsefor (i <- 0 until partition) {

val min = 3 + (i * 20)val max = if ((min + 19) > primSusp)

(primSusp - 1) else (min + 19)actor {

caller ! haveFactorInRange(primSusp, min, max)}

}...

}

Creates an actor and starts it

Execute the function and send the result to the collator

Page 48: Languages on the JVM - Groovy, Ruby, Scala, Clojure

48

Example – Determining Prime – 2

def isPrime(basis: Int): Boolean = {...var haveFactor = false

...(0 until partition).foreach { x =>

receive {case ans: Boolean =>

haveFactor = haveFactor || anscase _ =>

}}!haveFactor

}

Waits for messages from actors

Match the message type against the discriminator

Page 49: Languages on the JVM - Groovy, Ruby, Scala, Clojure

49

Clojurehttp://clojure.org

Page 50: Languages on the JVM - Groovy, Ruby, Scala, Clojure

50

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

Page 51: Languages on the JVM - Groovy, Ruby, Scala, Clojure

51

Language Features – 2

> All data is immutable – no data is ever change*

> 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

(def foo '(a b c)) → (a b c)(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)

*except for refs

Reassigned

Page 52: Languages on the JVM - Groovy, Ruby, Scala, Clojure

52

Calculate 10!

Javapublic int fac(final int f) {

int tot = 1;for (int i = 1; i < f; i++

tot *= ireturn (tot);

}

Clojure(defn fac [f]

(if (zero? f)1(* f (fac (dec f)))))

Function defintion

Page 53: Languages on the JVM - Groovy, Ruby, Scala, Clojure

53

Calculating 10! with Sequences

> Create a list of values, apply a function over these value• x! = (x – 1)! * x

> Lazy (is a virtue) and infinite sequences• Infinite sequence that will only generate the next value iff required

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

;generate an infinite factorial list(defn fac

([] 1)([x] (apply * (range 1 (inc x)))))

(defn fac-list [] (map fac (iterate inc 1)))

(take 5 (fac-list)) → (1 2 6 24 120)

Overloaded functionGenerate an infinite sequence of factorials

Take 5 from list

Page 54: Languages on the JVM - Groovy, Ruby, Scala, Clojure

54

Calling Java

> Importing Java classes

> Instantiating Java classes

> Accessing methods and members

> Implementing interfaces and extending classes• With type hints

(import '(java.awt.event ActionEvent)

(def f (new JFrame “Thisis a frame”))(def f (JFrame. “This is a frame”))

(. f setVisible true)(.setVisible f true)(.getDefaultButton (.getRootPane f))

→ (.. f getRootPane getDefaultButton)

(proxy [ActionListener][](actionPerformed [#^ActionEvent a-evt] ( … )))

Type hint

Page 55: Languages on the JVM - Groovy, Ruby, Scala, Clojure

55

Creating a Swing Frame

;Import the relevant classes(import

'(javax.swing JFrame JPanel JButton)'(java.awt.event ActionListener

ActionEvent WindowAdapter WindowEvent))

;Implement an ActionListener(def act-listener

(proxy [ActionListener] [](actionPerformed [a-evt]

(println (format "Button %s pressed" (. a-evt getActionCommand))))

))

Implements the ActionListener

Page 56: Languages on the JVM - Groovy, Ruby, Scala, Clojure

56

Creating a Swing Frame;Create a button(def button

(doto (JButton. "Press me")(.addActionListener act-listener)))

;Create a panel(def panel

(doto (JPanel.)(.add button)))

;Create a frame(doto (JFrame.)

(.setTitle "Hello")(.setDefaultCloseOperation JFrame/DISPOSE_ON_CLOSE)(.add panel)(.addWindowListener win-listener)(.pack)(.setLocationRelativeTo nil)(.setVisible true))

Accessing static member

Apply all following methods to the instance

Page 57: Languages on the JVM - Groovy, Ruby, Scala, Clojure

57

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

Page 58: Languages on the JVM - Groovy, Ruby, Scala, Clojure

58

Sharing Data via Managed References

Data

bar

fooThread A

Thread B

DataThread A

Thread B

foo

Deference to access immutable data

@foo

Most programming languages eg. Java, C, etc.

Page 59: Languages on the JVM - Groovy, Ruby, Scala, Clojure

59

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 → 0

(send foo inc)

... after some time ...@foo → 1

@foo is immutable

Page 60: Languages on the JVM - Groovy, Ruby, Scala, Clojure

60

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

Page 61: Languages on the JVM - Groovy, Ruby, Scala, Clojure

61

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

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

Create a transaction

Page 62: Languages on the JVM - Groovy, Ruby, Scala, Clojure

62

Handling Conflicts with alter

time

(dosync (alter foo assoc ...))

(assoc ...)

> 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

­ f -1(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→

(assoc ...)

foo alter by another transaction Transaction is retried

Page 63: Languages on the JVM - Groovy, Ruby, Scala, Clojure

63

Handling Conflicts with commute

> 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

time

(dosync (commute foo assoc ...))

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

foo alter by another transaction Function is retried

Page 64: Languages on the JVM - Groovy, Ruby, Scala, Clojure

6464

Lee Chuk Munn Staff Engineer [email protected]

Page 65: Languages on the JVM - Groovy, Ruby, Scala, Clojure

65

Relational Algebra (or SQL)

> Nice set of relational algebra to work on sets• Relational algebra is the basis of SQL

>

Page 66: Languages on the JVM - Groovy, Ruby, Scala, Clojure

66

Immutable Data

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

x

(def y (rest x)) a b c

x y

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

x y

d

z