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
http://www.casualmiracles.com/
INTRODUCTION
State safe co-ordination and communication between
distributed system components.
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.
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
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);
}
http://www.casualmiracles.com/
DESIGN DIAMONDMinimise Interface
Minimise Uses
Complexity
http://www.casualmiracles.com/
FLY SPACE DESIGNMinimal But Complete Interface
Minimal Use of OS interfaces
ThreadingObject Locking
DistributionMatchingExpiring
WriteReadTake
PthreadsSockets
Malloc - Free
http://www.casualmiracles.com/
FLY SPACE INTERFACE HIERARCHY
MultiFly writeMany readMany takeMany
FlyPrime writereadtake
NotiFly notifyWrite notifyTake
Fly
http://www.casualmiracles.com/
FLY SCALA
Scala Binding
Scala Space Interface
Fly Server
Scala Application Client
Scala Binding
Scala SpaceInterface
Scala Application Client
http://www.casualmiracles.com/
FROM JAVA TO SCALA
• Syntactic Conversion
• Idiomatic API
• Idioms Internally
• Actors
• Java and Scala Compared
• What Next?
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}
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; } }
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
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
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
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
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
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
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
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...
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
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?
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_
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);
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");
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(...
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!")}
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
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)
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
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?
http://www.casualmiracles.com/
FROM JAVA TO SCALA
><----
--------->
<---->
2/3 lines of codecould be better