Tuesday, January 20, 2009

The Protocopter Story

To steal the words of Chesterton... This posting is about a yachtsman, who thinks he's discovered a new island off the south seas, only to realize he had discovered England. The man lands (armed to the teeth) and plants the British flag in a barbaric temple which turns out to be the pavilion in Brighton. As Chesterton states, I will reiterate "I am that man."

The Beginning

The story begins over a year ago with Adam Lindsay's invention of LOLCode. I was shown this language sometime in the summer of 2007, and decided I would try my hand at writing an Eclipse plugin for it. The plugin turned into an interpreted runtime, which flowed to my more active involvement in the shaping of the language. While the language itself is rather humorous and very readable, the most interesting part to me were the concepts we were describing.

LOLCode is designed by committee, which although allows for many various interesting ideas to get discussed, also leads to very-long debates and slow decision making. However, a few major pieces of LOLCode were decided early that shaped it into a very interesting language. Of primary importance was the appeal to feline programmers. This untapped market could revolutionize the software business for decades to come. It was later agreed that other fuzzy and/or exceptionally cute lifeforms should also be allowed to participate in this revolution. The most exciting decision (for me) was the decision to use Prototype-OO as the basis for the language. Most other design decisions fell from this.

While designing LOLCode, not only were we having fun, we were also toying with some very interesting programming language designs. The choice of prototype-OO lead to several other interesting choices, that eventually got a few of us excited about the possibilities what the language could express. Not only could you perform acts for others, you may also be able to do so succinctly and elegantly. This lead to the idea for "Protocopter"

A Language that can fly

Protocopter is a language runtime (currently very buggy + implemented on top of Scala) that we were using to test out the ideas of LOLCode in a very minimal syntax. The idea was to reduce parse complexity (as most of us weren't compiler designers by profession) while ironing out details in the runtime. So far, we've had some very exciting results, and I'd like to go over the general design/implementation of Protocopter/LOLCode for you. For future reference I will only use protocopter, but the designs are interchangeable at this point. Protocopter is almost a "vm" for LOLCode.

SLOTS IN YR OBJECT

The primary design of Protocopter revolves around its object construct. An object is a "thing" that may contain any number of "slots". Each slot has a name, and contains any number of objects. The concept is very similar to Java's Map<String,Object> and almost exactly the same of a JavaScript object.

The most interesting part about Protocopter objects are that they have prototypes. A "prototype" is essentially a parent class only it remains an object. In Ruby, you can access a class and inject methods into it, but in Protocopter there is no need. Everything is an object. IF you want to create a "class", you simple make an object (places all methods/fields you want inside) and then prototype it to create "instances". The concept shouldn't be new for any AJAX developer, but it can be rather unintuitive for C/Java programmers.



The hard part in dealing with prototypes is defining how to look up a slot name on an object using its prototypes. In Javascript, when looking for slot 'x', the object itself is initially queries for slot 'x'. Then it proceeds to the prototype of the object, then the prototype of the prototype and so on. In Protocopter we made the decision to allow a list of prototypes per object. This means we needed a more sophisticated algorithm. At the writing of this article, we've implemented a Depth-First search on the prototype list. This means we first check the first prototype, then its first prototype, etc, until we've check as far down the tree as possible (the entire list), then recurse backwards searching for slot names. The algorithm also marks objects that have been visited to prevent cyclic references from causing infinite lookup times.


Now that we've defined objects, and slot lookups, what do prototypes really look like? The prototype list needs to be modified at runtime, therefore it should fit in a slot. Not only that, the prototype list is a LIST, ideally it should prototype the "ListPrototype" object, so we can re-use list functions when working with it. All of these decision were made, although we haven't thoroughly defined the "ListPrototype" object, or how one would work with it.

Putting FUN back into FUNction
Function are the next interesting piece to Protocopter. There was much debate over how to create them, and what they should look like. It was decided that the language should support blocks of code. Blocks of code operate with some "scope object". A scope object is the object used to look up local variables when a "block" is executing. The block references these slots on the scope object without any qualifiers.

Note: The initial script run by Protocopter is run in the scope of an anonymous prototype of the "Object" object. Other potential prototypes may be implementation defined, but are non-standard. "Object" is the only global inside Protocopter and the prototype of *every* object in the system.

It was then decided to turn Functions into first-class objects. A function consists of a code block and a list of arguments. When calling a function, the function object is prototyped, and the arguments/self slots are assigned to the prototype. The anonymous prototype is then used as the "scope object" for the code block of the function. To turn a function into a closure, simply insert the "scope object" for the scope a function is created, into the function's prototype list. Not only was this approach elegant, it made implementation much simpler (as it uses the already existing slot-lookup algorithm + prototype system).

WE HAZ A FLAVORZ
The next part of protocopter was defining enough operations to make it a viable "VM" for lolcode. The operations are listed below in the "Protocopter" syntax. Later in the article I attempt list the relative LOLCode->Protocopter conversions.
Slot Access
 expr '.' identifier 
This access the value of a slot from an object

Call Code Block/Function
 '!' expr expr expr*
This calls a given code block with the scope/arguments

Assign Slot
 l-value '<-' expr 
This assigns a value to a given slot


Create Prototype
 '~' expr 
This creates a prototype of an object

Append Prototype
 l-value '<<' expr 
This appends a prototype to a given object

Code Block
 '{' statement* '}' 
This creates a code block which will execute a series of statements.

Literal Translation
 '@' expr 
This treats a string expression as a code-literal (for slot lookup)

The above form the basis for Protocopter syntax (and allow mapping from LOLCode). I've also (somewhat successfully) tried to define a few convenience extensions in the current implementation. These are not needed in the language, but helped me write some test cases quickly.

Function Definiton
 
'{' ('|' arg-list '|')? statement* '}'
arg-list := arg (',' arg)*

This creates a Function object that takes a series of arguments.

Call-function inline syntax
expr '!' identifier call-arguments

This syntax calls a function identified by a given slot on an object, using the object as "self" for the function.

Function Closure syntax
'[' ('|' arg-list '|')? statement* ']'

This syntax creates a function that automatically prototypes the current scope.

Code-Block Closure syntax
'[' statement* ']'

This syntax creates a code-block that automatically prototypes the current scope.



IM IN YR LOOP WHILE YR NOT!

Now that we have some syntax available, it's easier to describe some issue's we're running into. The first is how to deal with while loops. Ideally, we want to implement tail-recursion optimizations and define while purely inside Protocopter like the function shown below (assuming 'if' is a valid function):


Object.while <- { |condition, loop|
! if current (!condition) [ ! loop; ! Object.while current condition loop ]
}


Note that I'm using some lazy syntax here with the || arguments, but let's look at the one-liner implementation. First, you should note that code blocks return the last value executed in their scope. Second you should note that "current" always refers to the current scope object. I could accomplish this same code in more lines, but I'm preferring brevity here. It might be more apparent what's going on if I write it without the syntax extensions.


Object.while <- ~Function
Object.while.block <- {
trueBlock <- {
!loop
! Object.while current condition loop
}
trueBlock << current
! if current (!condition) trueBlock
}
list <- ~ Object.libs.collection.List
list.0 <- 'condition'
list.1 <- 'loop'
Object.while.args <- list

Notice first, that we're creating an anonymous prototype of "Function" and placing a code-block and argument list inside it. Then notice to create a closure, we're making a code-block and then appending the current scope as a prototype. Also notice that we're using a very low-level mechanism of creating a list (assigning numbered slots). Although it gets into the details, I hope that's detailing some of what is going on at the lower-levels of protocopter.

The goal with the protocopter language is to provide a very simple low-level base that LOLCode can be implemented on, while provided nicer higher-level language features that make writing boiler-plate test-code easier (like functions/closures, etc.).

My next goal is to provide a few layers of niceties on top of the existing language extensions so you don't always have the verbose: "! function scope arg1 arg2" nonsense every time.

CAN HAZ CHEEZBURGER?
The most important part of Protocopter is the ability for LOLCode to compile into Protocopter instructions. Currently they're both interpreted, so it's a mere matter of source->source translation, but hopefully in the future Protocopter could be a form of byte-code.

Let's take a look at some LOLCode 1.3 spec examples and how they would look in Protocopter.



I HAS A var ITZ 0
---------------------------------------
var <- 0


HOW DUZ I foo YR bar
VISIBLE bar
FOUND YR NOOB
IF U SAY SO
---------------------------------------
foo <- { |bar|
! print current bar
null
}


I HAS A thingy ITZ A Bukkit
---------------------------------------
thingy <- ~ Bukkit


O HAI IM tired IM LIEK sleepy
I HAS A thingy ITZ 0
KTHX
---------------------------------------
tired <- ~sleepy
! { thingy <- 0 } tired


O HAI IM pile
I HAS A length IZ 0

HOW IZ I pushin YR item
ME HAS SRS length ITZ item
length R SUM OF length AN 1
IF U SAY SO

HOW IZ I popin
length R DIFF OF length AN 1
BTW Do bounds checking...
I HAS A mom ITZ ME'Z SRS length
ME'Z SRS length R NOOB
FOUND YR mom
IF U SAY SO
KTHX
---------------------------------------
pile <- ~Object
! {
length <- 0
pushin <- { |item|
self.(@length) <- item
self.length <- ! + current self.length 1
}
poppin <- {
self.length <- ! - current self.length 1
mom <- self.@length
self.@length <- null
mom
}
} pile


I HAS A fishBarrel ITZ A pile
fishBarrel IZ pushin YR "halibut" MKAY
fishBarrel IZ pushin YR "trout" MKAY
fishBarrel IZ pushin YR "salmon" MKAY
VISIBLE fishBarrel IZ popin MKAY BTW prints "salmon"
---------------------------------------
fishBarrel <- ~ pile
! fishBarrel.pushin current "halibut"
! fishBarrel.pushin current "trout"
! fishBarrel.pushin current "salmon"
! visible (! fishBarrel.popin current )



NOOOO HEZ STEALIN MAH BUKKIT!
We've almost discovered England, and dug our flag into Brighton. The only thing left is to look into a language known as IO. I discovered this language a few weeks ago and it made me very excited and also very sad. Not only is it almost exactly what we've been trying to implement with Protocopter, it even ups the ante with actor-based objects. In I/O all objects are actors and all slot-access/function calls are messages between actors. Most of the other work is already in-place in I/O. While this gives me the satisfaction of knowing we were on the right track, it also begs the question: What should we do with Protocopter?

Currently the I/O language is a little too far removed for LOLCode to compile into its world. However, would it be easier to finish Protocopter implementation, or re-define LOLCode 1.3 spec to fit the I/O language design? I leave the debate up to the readers and the LOLCode forums.

The unfortunately reality is that most of us trying to hack on Protocopter and LOLCode have more-than-full-time jobs and kids. I also try to place the needs of the scala-maven-community before some of my other nerdy hobbies (which are way below family/work), so Protocopter ends up being pretty low on the totem pole. Perhaps given enough insight, caffeine and hilarity to leverage, you'll see a 0.10 release of Protocopter (and 1.3 of LOLCode) out soon.

Anyone willing to help, please email me and we'll set you up with access to the project and whatever else you need. This blog now stand as the greatest single document of accumlated LOLCode-thought for the 1.3 spec. If you'd like to see the thought process that arrived at this point, please check out the LOLCode forums.

The current major issues in Protocopter are:
  • Sequence/List Prototype Definiton

  • Using Sequences for Prototype lists on objects, and runtime manipulation

  • self/this references in functions. How can we pass "scope" + "self" without being incredibly verbose

  • actor/continuation implementation + cleanup

  • parser refinement

  • Code-Block slot/metadata definitions

Monday, January 12, 2009

Leveraging Annotations in Scala

This post attempts to explain how to leverage Scala annotations in the Scala language.

I'm currently working on the ability to create Maven 2 plugins (Mojos) in the Scala language. Maven plugins are pretty easy to create, they basically involve creating a class that extends AbstractMojo and annotating fields on that class that should be injected with configuration/runtime information from maven. Bringing this feature to Scala however, required me to make some trade-offs. Should I use the "annotations in the documentation" approach that maven uses for java + groovy mojos? Or should I leverage Scala's annotation support (which means I don't have to write a parser)? I chose the annotation method, and below is how to make it work.

First, we need a few annotations to leverage. In the case of Maven Mojos, they're almost all defined for me. Here's a look at the "goal" annotation:

class goal(val name : String) extends StaticAnnotation


Scala defines two types of annotations (both extending from Annotation): Static and Classfile. Classfile annotations are retained in the .class file (i.e. the byte code) and are available at runtime (I believe?). Static annotations, on the other hand are 'available to the compiler'. I haven't read through the SLS (Scala Language Spec), so I'm not quite sure exactly what this means, but I know they're at least available in the Abstract Syntax tree (what we care about).

Those of you who use Java annotations will notice that Scala annotations do not provide as many options as Java annotations. I'm hoping this changes with time, but currently Scala takes the standpoint that Java does a well enough job of defining annotations and annotation processing tools. While I agree, I'd still like to be able to define annotations in Scala with a few more options. However, defining annotations in Scala is more elegant than with Java (That's right Mr. @interface....)

Next, let's make our first Maven mojo (something like the following):

@goal("echo")
class EchoMojo extends AbstractMojo {

@throws(classOf[MojoExecutionException])
override def execute() {
getLog.error("HAI WURLDZ!")
}
}


Next, we need to parse this file and create a "mojo description" xml file. Maven provides us with an interface that is used to look for mojo-annotated classes. We'll assume in your case (if you're leveraging annotations) that you already have hooks for where you will parse, and what you need to parse out. To actually perform the parsing, we're going to steal a trick from scaladoc + the eclipse plugin called a "presentation-only" compiler.

A "presentation-only" compiler is fairly easy to construct, you simply subclass the Scala "global" object and override its "onlyPresentation" method (as shown below). The "Global" class is the amalgamation of all the various modules of the Scala compiler, plus a few methods to execute compilation.


val compiler = new Global(settings, reporter) {
override def onlyPresentation = true
}


The Global class takes a settings object and a reporter. The settings object contains all of Scalac's command-line settings in code form. This is where you'll have to set the classpath and other fun flags (luckily for me, I get those for free from my maven mojo extractor interface). The Reporter is simply a "strategy" for where to pipe error/compilation output to. Once again, my choice is simple: The maven logger.

After creating a compiler, you actually need to execute it against a list of source files (hopefully the ones containing your annotations) like so:


val run = new compiler.Run
run.compile(sourceFiles.toList)


The "run" of the compiler should parse through all the files and generate an Abstract syntax tree for you. After which, you can easily go rip through them all and process them, like so:


for(unit <- run.units if !unit.isJava) {
extractMojos(unit)
}


I'm purposefully ignoring Java files, as they're only parsed for mixed java-scala projects, and the maven Mojo extractor for Java already exists.

Now for the real fun... What does extractMojos look like? Well, it has the following signature (give or take a few revisions in git):

def extractMojos(unit : compiler.CompilationUnit) : Unit


A CompilationUnit is a .scala or .java file that has been compiled. A .scala file may contain many packages and classes/traits/objects. We gain access to these by calling "unit.body". The body is the Abstract Syntax tree for the given file.

A little more context is needed for what we're going to do next. The Scala Compiler uses something called the Cake pattern. The gist of it is that you carve up functionality into modules (in this case traits) and mix them together as needed. One unfortunate problem with the Scala Compiler itself is that a lot of the modules have nested dependencies (i.e. trait XYZ { self : Global => } ), and therefore have to be mixed into a global. Therefore we're going to define our tree extraction methods on a trait (in a similar manner) and mix them into the compiler variable when we instantiate. The module will look something like this:


import scala.tools.nsc.ast._
import scala.tools.nsc.symtab.{Flags, SymbolTable}
import org.scala_tools.maven.mojo.annotations._
trait MojoAnnotationExtractor {
self: Global =>

/** Pulls all mojo classes out of the body of source code. */
def parseCompilationUnitBody(body : Tree) : List[MojoParsedInfo] = {
//TODO - Implement
}


What " self : Global => " portion of code means, is that the trait *must* be mixed into the Global class. Assuming the above layer (trait) is fully implemented, the entire "annotation extraction compiler" looks like the following:


val compiler = new Global(settings, reporter) with MojoAnnotationExtractor {
override def onlyPresentation = true
}
val run = new compiler.Run
run.compile(sourceFiles.toList)

//Extract mojo description
def extractMojos(unit : compiler.CompilationUnit) = {
import compiler._
for(info <- compiler.parseCompilationUnitBody(unit.body)) yield {
extractMojoDescriptor(info)
}
}
def extractMojoDescriptor(info : MojoParsedInfo) : MojoDescriptor = error("TODO - Implement")
import scala.tools.nsc.ast._
import scala.tools.nsc.symtab.{Flags, SymbolTable}
import org.scala_tools.maven.mojo.annotations._
trait MojoAnnotationExtractor extends CompilationUnits {
self: Global =>

/** Pulls all mojo classes out of the body of source code. */
def parseCompilationUnitBody(body : Tree) = {
for(unit <- run.units if !unit.isJava) yield {
extractMojos(unit)
}


I've added a few things in there. First is the "with MojoAnnotationExtractor" as part of the Global class initialization. This is mixing our our new extraction function (parseCompilationUnitBody), and allows us to call it inside the extractMojos method. We're finally able to get to the meat of our application, actually pulling in annotations and doing something with them.

The first thing we notice when attempting to parse the AST of a compilation unit body, is that we *must* keep track of package nesting ourselves... (there's no figuring it out after the fact, at least not cheaply that I found). I ended up with the following helper to ensure I knew the package for each class:


/** Pulls all mojo classes out of the body of source code. */
def parseCompilationUnitBody(body : Tree) = {

//List of all the info about mojos we've found
var mojoInfos : List[MojoClassInfo] = List()

/** Parses down into packages... */
def parsePackage(pkgName : String, pkgDef : PackageDef) {

pkgDef.stats foreach { _ match {
//We found a package, recurse into it, keeping track of where we are
case subPkgDef : PackageDef =>
parsePackage(pkgName + pkgDef.name + ".", subPkgDef)

//Find mojo classes
case classDef : ClassDef => parseMojoClass("", classDef)
case _ => //Ignore
}
}
}
//Pull top-level body if it's a package, or a class definiton.
body match {
case pkg : PackageDef => parsePackage("", pkg)
case classDef : ClassDef => parseMojoClass("", classDef)
case _ => Console.println("Error! Unexpected source file format for Scala Mojo Extractor");
}

mojoInfos
}


The parsePackage code above is used to recurse into package tree nodes, and pull out any classes defined on them. Scala converts the following code:

package x.y.z;
class A {}
into the following Tree:
Package X <- Package Y <- Package Z <- Class A
.
This is because the above code is syntactically equivalent to

package x {
package y {
package z {
class A {}
}
}
}


Now that we at least have a method of finding classes, let's start looking into annotations. We want to filter the classes we inspect based on whether they are executable Maven Mojos. All maven mojos need to define a "goal" with which to run, corresponding to our "goal" annotation. Let's throw this check before out parseMojoClass method:

for {
annotation <- classDef.mods.annotations
if annotation.tpe.safeToString == classOf[goal].getName
} {
mojoInfos = parseMojoClass(pkgName + pkgDef.name + ".", classDef) :: mojoInfos
}


The "ClassDef" node contains a "mods" branch which (among other things) holds A list of the annotations defined on a class. Every annotation has a Type "tpe" field. The "type" corresponds to the class of the annotation. In this case I'm being lazy and calling the 'safeToString' method on type which should give me the full class name of that type (in this case org.scala_tools.mojo.annotations.goal). I'm then comparing that to the runtime string of the class name, to ensure that the class does have a "goal" annotation. Note: This was the path of least resistance for me. Types are not guaranteed to be class names, so I'm hoping to figure out a better way of doing this in the future.

The Scala syntax tree is very nice for doing manipulations and compilation like things, but for my circumstances, I really just want a map of annotation to attribute lists for that annotation. Let's try to make an abstract method that will pull an annotation's name and all the "arguments" to it's constructor (i.e. @annotation(arg)). I wound up with something like this:


/** Parses a list of annotations into a list of MojoAnnotationInfo classes */
def parseAnnotations(annotations : List[Annotation]) = {
for {
annotation <- annotations
Annotation(constr, _) <- annotation
} yield {
// TODO - In the future the second arg to Annotation may be needed... (as it's what's inside the
//anonymous instantiation of an annotation, i.e. @xyz {}
//TODO - Do we need to match on constructor?
val argVals = for {
Apply(_, args) <- constr
arg <- args
argVal <- extractStaticValue(arg)
} yield argVal
new MojoAnnotationInfo(annotation.tpe.safeToString, argVals.toList)
}
}
/** Attempts to pull a static value from the given tree.
*
* @returns
* Some(value) if a value is found, None otherwise
*/
def extractStaticValue(tree : Tree) = tree match {
case Literal(c) => Some(extractConstantValue(c))
case _ => None
}
/**
* Extracts a constant variable's runtime value
*/
def extractConstantValue(c : Constant) = {
//TODO - handle other values
c.stringValue
}


The for loop defined in 'parseAnnotations' is looking at every annotation and pattern matching to rip out their constructor (constr member). If you need to support @annotation { val bodyVal = "someval" }, then you would also need to match against the second member of the "Annotation" AST node.

The annotation constructor is an instance of the "Apply" AST node (which I believe means 'function call', but don't quote me). Since I'm unconcerned over which "this" is being called, we are only extracting the 'args' field from the Apply node. We then iterate through the list of argument AST nodes, and pass them to our "extractStaticValue" function. Given that all annotation arugments must be statically accessible values, and that we implement extractStaticValue correctly, this should work just fine.

Next the 'extractStaticValue' method is pulling "Literal" AST nodes and extracting their values. A Literal AST can only hold a constant, so it pairs well with the 'extractConstantValue' method. As you can see, I'm getting away with murder because non of my mojo annotations take anything but Strings. In the "real world" you would need to handle static references as well constant values.

The 'extractConstantValue' method takes an AST constant and pulls its string value. The Constant AST class also has methods for pulling various other types of constants, however I'll leave a real implementation of 'extractConstantValue' as an excercise to the reader. Once again, I only care about string constants.


The next processing I'd like to perform is to determine if there are any 'vars' in the MojoClass that I can inject maven resources into. We'll assume we've defined a no-argument annotation called 'parameter' that you can place on var's like so:

@parameter
@expression("${project.build.directory}")
var outputDirectory : File = _;

The above should inject the Maven Project's build output directory into the variable "outputDirectory" at runtime. To do this, we need not only the name of the variable, but also it's type. let's weed through the class AST's "impl" node and look for var definitions that have a @parameter annotation.

You'll quickly notice that THERE IS NO VAR AST NODE!!! Scala's very slick in that it converts the syntax:

var xyz = _;

Into

def xyz = _
def xyz_= = _;


Therefore we need to look for the "Def" AST Nodes. Not only that, we need to look for "setters" (i.e. methods ending with the string "_$eq", where $eq is the mangled form of = in a method name)

Using the above code to parse through all annotations in a list, our "parameter" parser method looks like the following:

/** Pulls out information about all injectable variables based on mojo annotaitons. */
def parseMojoInjectedVars(classImpl : Tree) = {
for { node @ DefDef(mods,name,tparams,vparams,tpt,_) <- classImpl
if name.toString.endsWith("_$eq")
annotation <- mods.annotations
if annotation.tpe.safeToString == classOf[parameter].getName
argument @ ValDef(_,_,tpt,_) :: Nil <- vparams //setter should only have ONE argument!
} yield {
val argName = name.toString.slice(0, name.length - "_$eq".length)
//DO a real extraction of the type!
val argType = tpt.toString
val argAnnotations = parseAnnotations(mods.annotations)
new MojoInjectedVarInfo(argName,argType,argAnnotations)
}
}


Notice the DefDef (Def AST Node) is made up of modifiers (annotations + others), a name (e.g. outputDirectory_$eq), type parameters, v? (regular) parameters, a return type and a body. We use the name to filter out only var setter methods, and then look through the annotations for the parameter name. Finally we filter out only methods that have ONE regular parameter, and we extract the type of that parameter with the pattern match "ValDef(_,_,tpt,_)". We can then parse the annotations, and create our "Mojo Info" class.

One thing I should mention is that all types I've been parsing so far have been in *external* libraries, and are therefore referencing class files in a jar somewhere. I'll try to update the post as I get more robust in what my annotation processor can handle.

Viola, we've extracted all the info for the beginnings of a scala mojo annotation processor. The really fun part is generating a test case for it. The test case involves running a maven integration test, where a new Scala Mojo project defines a mojo in scala, and the above code is used to generate the scala definition. This integration-test project then has its *own* integration test where it creates another project and calls itself, verifying that it echoed "HAI" correctly to the output.

Anyway, I hope this post was not too long for most of you. The topic is fairly complex, and I'm not the best to be writing about it, however I hope that the few minutes it takes to read can save you the several hours of frustration I had trying to get things to work initially.

Saturday, January 3, 2009

Initial thoughts on JavaFX

So recently I've been reading a little bit about the new "JavaFX" platform Sun has released. Specifically I've been looking into the Fx Script language. When I first heard about it, I kept thinking "OH no, *another* JVM language. I hope they don't make it too similar to java!". However, I've been pleasantly surprised by the features so far.

Based on a few tutorials, JavaFX script appears to have chosen nice features from languages like Scala and Javascript, while adding one languages feature that truly distinguishes it (and IMHO makes it a worthwhile language to learn/use for its domain). Here's a list of features I saw in the tutorials that I believe make the core of the Fx Script language:
  • Declarative Constructors (like javascript) -
    { fieldName: value }

  • Truly Useful Type inferences (with types on the right) [like scala] -
    var radius = 5.0
    Note: types can be specified

  • Three main types of constructs (similar to scala) - mutable references, immutable reference and functions
    var mutableValue = 5.0
    def someStaticValue = 2.0
    function doSomething() {}
    These made me think scala's def=> Fx's function, Scala's var=> Fx's var and Scala's val=> Fx's def

  • Value Binding - (this is a truly compelling feature for JavaFX)
    var x = 0;
    def y = bind x;
    The above code means that x and y will always have the same value, even though y is immutable. This is useful for synching your model to your view. I'm excited to start toying with this. I've only shown on possible syntax, there are actually a few ways to bind variables.

  • Bound functions -
    var x = 0;
    def foo = bound function(...) {...};
    The above code means that the function foo will see any changes made to "x". I.e. foo is no longer a closure in the sense that it retains the value of x during its call.



Anyway, I'm pleasantly surprised with JavaFX and the Fx Script language. I think a few good ideas from other JVM languages are finally really starting to take hold. Most importantly, I'm glad Scala isn't the only viable JVM language with really useful type-inference. I'm hoping the other statically typed languages will follow suit (This means you java!).