Porting Java To Scala

32
http://www.casualmiracles.com/ DEVELOPING THE SCALA BINDINGS FOR THE FLY OBJECT SPACE > <---- ---------> <---- > Channing Walton [email protected] Nigel Warren [email protected] CM, Java experience, CRE, UCL Presentation about my experience porting from Java to Scala

description

In this talk we contrast and compare the interface of the Java Bindings with the development and design of the Scala bindings and interfaces, with particular reference to the introduction of Scala language specific features such as the use of Options and the Scala Actors model.

Transcript of Porting Java To Scala

Page 1: Porting Java To Scala

http://www.casualmiracles.com/

DEVELOPING THE SCALA BINDINGS FOR THE FLY OBJECT SPACE

><----

--------->

<---->

Channing Walton [email protected]

Nigel Warren [email protected]

CM, Java experience, CRE, UCLPresentation about my experience porting from Java to Scala

Page 2: Porting Java To Scala

http://www.casualmiracles.com/

INTRODUCTION

State safe co-ordination and communication between

distributed system components.

Page 3: Porting Java To Scala

http://www.casualmiracles.com/

SPACES Tuple Spaces - Linda (a coordination language)

in - put a tuple into a space

rd – get a copy of a tuple from the space

out – remove tuple from the space

Subsequently …

Java Spaces - Jini – Java

Rinda – Ruby

PyLinda – Python

etc., etc.

Page 4: Porting Java To Scala

http://www.casualmiracles.com/

FLY

Fly is an ‘Object Space’

Network wide - Object level - Storage and Matching Matching – by Object Templates Object Serialisation – Native to a language or language neutural

Leasing – Information and resources have prescribed lifetimes

Page 5: Porting Java To Scala

http://www.casualmiracles.com/

FLY PRIME INTERFACE

public interface FlyPrime {

long write(Object entry, long leaseTime);

Object read(Object template, long waitTime);

Object take(Object template, long waitTime);

}

Page 6: Porting Java To Scala

http://www.casualmiracles.com/

DESIGN DIAMONDMinimise Interface

Minimise Uses

Complexity

Page 7: Porting Java To Scala

http://www.casualmiracles.com/

FLY SPACE DESIGNMinimal But Complete Interface

Minimal Use of OS interfaces

ThreadingObject Locking

DistributionMatchingExpiring

WriteReadTake

PthreadsSockets

Malloc - Free

Page 8: Porting Java To Scala

http://www.casualmiracles.com/

FLY SPACE INTERFACE HIERARCHY

MultiFly writeMany readMany takeMany

FlyPrime writereadtake

NotiFly notifyWrite notifyTake

Fly

Page 9: Porting Java To Scala

http://www.casualmiracles.com/

FLY SCALA

Scala Binding

Scala Space Interface

Fly Server

Scala Application Client

Scala Binding

Scala SpaceInterface

Scala Application Client

Page 10: Porting Java To Scala

http://www.casualmiracles.com/

FROM JAVA TO SCALA

• Syntactic Conversion

• Idiomatic API

• Idioms Internally

• Actors

• Java and Scala Compared

• What Next?

Page 11: Porting Java To Scala

http://www.casualmiracles.com/

SYNTACTIC

public interface NotiFly extends FlyPrime { boolean notifyWrite(Object template, NotifyHandler handler, long leaseTime); boolean notifyTake(Object template, NotifyHandler handler, long leaseTime); }

trait NotiFly extends FlyPrime { def notifyWrite(template: AnyRef, handler: NotifyHandler, leaseTime: Long): Boolean def notifyTake(template:AnyRef, handler:NotifyHandler, leaseTime:Long):Boolean}

Page 12: Porting Java To Scala

http://www.casualmiracles.com/

SYNTACTIC

public static void main(String[] args) throws Exception { FileInputStream f = new FileInputStream(new File(args[0])); DataInputStream dis = new DataInputStream(f); StatsDecoder decoder = new StatsDecoder(); long time = dis.readLong(); while ( true ) { int size = dis.readInt(); StatsBean [] beans = decoder.getStatsArray(dis); Stats.writeStats(beans); System.out.println("--------------"); long nextTime = dis.readLong(); Thread.sleep(nextTime-time); time = nextTime; } }

def main(args: Array[String]) {

val f = new FileInputStream(new File(args(0))); val dis = new DataInputStream(f);

val decoder = new StatsDecoder();

var time = dis.readLong(); while (true) { val size = dis.readInt(); val beans = decoder.getStats(dis); StatsPrinter.writeStats(beans); System.out.println("--------------"); val nextTime = dis.readLong(); Thread.sleep(nextTime - time); time = nextTime; } }

Page 13: Porting Java To Scala

http://www.casualmiracles.com/

IDIOMS - OPTION

An Option represents an optional value

Two subclasses: Some and None

Java has … null

Experiment with Options in Java later

Page 14: Porting Java To Scala

http://www.casualmiracles.com/

IDIOMS - OPTION

trait FlyPrime {

def read[T <: AnyRef](template: T, waitTime: Long): Option[T]}

fly.read(template, 0L) match { case None => { println("No ball in play") serveBall(fly) println("Served Ball - Please start a Pong") } case Some(gameBall) => { println("Received ball - game on!") returnBall(fly, gameBall) }}

pattern matching - scala can extract values from the matching pattern - Some(ball)no types

Page 15: Porting Java To Scala

http://www.casualmiracles.com/

IDIOMS - OPTION

trait FlyPrime {

def read[T <: AnyRef](template: T, waitTime: Long): Option[T]}

fly.read(template, 0L) match { case None => // do nothing case Some(gameBall) => doSomething(gameBall)}

fly.read(template, 0L).map((x:T) => doSomething(x))

fly.read(template, 0L).map(doSomething(_))

do nothing for none - verbose to use pattern matching(x:T) => doSomething(x) is a first class function

Page 16: Porting Java To Scala

http://www.casualmiracles.com/

ASIDE

Options can be implemented in other languages

Clumsy in Java but still useful

An experiment:

Problems exposed where null was not expected

Clarify business logic and behaviour

Page 17: Porting Java To Scala

http://www.casualmiracles.com/

IDIOMS - RETURN VALUES

int iterations = 10000;if (args.length > 0) iterations = Integer.parseInt(args[0]);

val iterations = if (args.length > 0) args(0).toInt else 10000

def urlFor(path: String) = try { new URL(path) } catch { case e: MalformedURLException => new URL("http://www.scala-lang.org") }

pattern matching for exceptionsexceptions are runtime

Page 18: Porting Java To Scala

http://www.casualmiracles.com/

IDIOMS - FILTERING

public Collection<FlyServerRep> getMatchingReps(String [] tags) { Collection matched = new ArrayList<FlyServerRep>(); for (FlyServerRep rep : reps.values()) { if (rep.tagsMatch(tags)) { matched.add(rep); } } return matched; }

def getMatchingReps(tags:Array[String]):Collection[FlyServerRep] = reps.values.filter((rep:FlyServerRep) => rep.tagsMatch(tags)).toList

def getMatchingReps(tags:Array[String]):Collection[FlyServerRep] = reps.values.filter(_.tagsMatch(tags)).toList

filter items from a collection

Page 19: Porting Java To Scala

http://www.casualmiracles.com/

IDIOMS - COMPREHENSIONS

public StatsBean[] getStatsArray(DataInputStream dis) throws IOException { long statsCount = dis.readLong(); StatsBean [] stats = new StatsBean[(int)statsCount]; for (int i = 0; i < statsCount; i++) { stats[i] = StatsBean.makeBeanFromStream(dis); } return stats;}

def getStats(dis: DataInputStream): Seq[StatsBean] = for (i <- 0 until dis.readLong().toInt) yield StatsBean.makeBeanFromStream(dis)

Create an array of itemsfor comprehension - iterate over something collecting results of the expression after yield

Page 20: Porting Java To Scala

http://www.casualmiracles.com/

FOR COMPREHENSION

Syntax: for ( seq ) yield e

Where seq is a sequence of generators, definitions and filters

e evaluated for each binding of generators and definitions

Return a sequence of evaluated values

generator— roughly speaking, an expression that pulls an item from a collectioneasier to show an example...

Page 21: Porting Java To Scala

http://www.casualmiracles.com/

FOR COMPREHENSION

val names = for {

p <- persons // a generator

n = p.name // a definition

if (n startsWith "To") // a filter

} yield n

p bound to each item in persons

Page 22: Porting Java To Scala

http://www.casualmiracles.com/

IDIOMS - FOLD /*** @return the lease of the last entry written*/public long writeMany(Collection entries, long lease) { long lastLease = 0; for (Object entry : entries) { lastLease = codec.write( entry, lease ); } return lastLease;}

def writeMany(entries: Collection[AnyRef], lease: Long): Long = (0L /: entries){(previousLease, nextEntry) => codec.write(nextEntry, lease)}

method writes entries to the space and returns the lease of the last item writtenfunction takes two parameters, ignores previousLease, returns the result of codec.writegood use of fold?

Page 23: Porting Java To Scala

http://www.casualmiracles.com/

IDIOMS - ACCESSORS public class FlyServerRep { private String [] flyTags; private InetAddress flyAddr; FlyServerRep(InetAddress addr, String[] tags) { flyAddr = addr; flyTags = tags; } public String[] getFlyTags() { return flyTags; }

public void setFlyTags(String[] flyTags) { this.flyTags = flyTags; }

public InetAddress getFlyAddr() { return flyAddr; }

public void setFlyAddr(InetAddress flyAddr) { this.flyAddr = flyAddr; }}

class FlyServerRep(var flyAddr:InetAddress, var flyTags:Array[String])

var on constructor parameters, scala generates accessor methods: x and x_

Page 24: Porting Java To Scala

http://www.casualmiracles.com/

IDIOMS - FUNCTIONS public Object read(Object template, long timeout) { Object ret = codec.read(template, 0); .... while(...) ret = codec.read(template, 0);

def read[T <: AnyRef](template: T, timeout: Long): Option[T] = retrieve(template, timeout, codec.read)def take[T <: AnyRef](template: T, timeout: Long): Option[T] = retrieve(template, timeout, codec.take)

private def retrieve[T](template: T, timeout: Long, m: (T, Long) => Option[T]): Option[T] = { var ret = m(template, 0L) .... while(...) ret = m(template, 0)

public Object take(Object template, long timeout) { Object ret = codec.take(template, 0); .... while(...) ret = codec.take(template, 0);

Page 25: Porting Java To Scala

http://www.casualmiracles.com/

CONTROL ABSTRACTIONSystem.out.println("Processing " + iterations + " writes and reads");long start = System.currentTimeMillis();for (int i = 0; i < iterations; i++) { space.write(object, 1000); space.read(template, 0L);}long end = System.currentTimeMillis();float timeInSeconds = (float) (end - start) / 1000.0f;System.out.println("Which took " + timeInSeconds + " seconds\n");

Page 26: Porting Java To Scala

http://www.casualmiracles.com/

CONTROL ABSTRACTIONTime("Processing " + iterations + " writes and takes", iterations) { space.write(obj, 1000) space.take(template, 0L)}

object Time { def apply(name: String, iterations: Int)(block: => Unit): Unit = { println(name) val start = System.currentTimeMillis()

for (i <- 0 until iterations) block

val end = System.currentTimeMillis() val timeInSeconds = (end - start) / 1000.0F println("Completed in " + timeInSeconds + " seconds\n") }}

apply methods have special meaning - invoked using a method-less expressioneg Time (... is the same as Time.apply(...

Page 27: Porting Java To Scala

http://www.casualmiracles.com/

CONTROL ABSTRACTION

trait NotiFly extends FlyPrime { def notifyWrite(template: AnyRef, leaseTime: Long)(block: => Unit): Boolean}

fly.notifyWrite(template, LEASE){ println("Block Template matched!")}

Page 28: Porting Java To Scala

http://www.casualmiracles.com/

ACTORS

Scala’s primary concurrency construct

Concurrent processes communicating by exchanging messages

Scala Actor implementation is a library - several of them

Page 29: Porting Java To Scala

http://www.casualmiracles.com/

ACTORS

trait NotiFly extends FlyPrime { def notifyWrite(template: AnyRef, leaseTime: Long, actor: Actor): Boolean}

import scala.actors.Actor._val myActor = actor { // factory method taking a block loop { // we want the actor to keep processing messages react { // handle messages case FlyPrime.ACTOR_MESSAGE => println("Actor received a message!") } } }

fly.notifyWrite(template, LEASE, myActor)

Page 30: Porting Java To Scala

http://www.casualmiracles.com/

JAVA TO SCALA COMPARED Java has 1556 LoC, Scala has 934 LoC => 60%

Core code is about half the size

Why?

Most algorithms can be characterised as Searching, Sorting, Filtering, Mapping, Combining, Counting (Peter Norvig)

Scala and functional languages provide good abstractions for these

Java is 2% faster

Need more comprehensive tests to find out why

Page 31: Porting Java To Scala

http://www.casualmiracles.com/

WHAT NEXT? Scala 2.8

Port from 2.7.7 complete

Available for 2.8 soon

Implement the library from scratch?

Design of existing library is the same as the Java library

Current version made improvements in the small

Perhaps a more functional approach would be better?

Page 32: Porting Java To Scala

http://www.casualmiracles.com/

FROM JAVA TO SCALA

><----

--------->

<---->

2/3 lines of codecould be better