JavaFX 2.0 and Scala, Like Milk and Cookies
JavaFX Colored Circles
I will go into more detail on why Scala in a bit, but I believe this is all best illustrated with a code example. One of the basic examples of JavaFX 2.0 functionality that comes with the SDK is a sample application called ColorfulCircles. The full source code can be found here:
With the help of Sven Reimers, we ported this to Scala on top of the ScalaFX library. The working application source can be found here:
– ScalaFX Colored Circles Code
Update: Dean Iverson has a great example of the same code in GroovyFX
Feel free to peruse the source code at your leisure, and take note of the following:
1. ScalaFX is More Concise
The ScalaFX version is shorter both in number of lines and more importantly number of characters.
Code Count (excluding licenses and imports):
- Lines:
- Java: 48
- ScalaFX: 42
- Characters:
- Java: 1602
- ScalaFX: 866
This is due to custom tailored DSL language that is fully expressive with less redundancy. In the Java version of the code you will notice a lot more boilerplate and syntactic repetition that is required by the language.
2. ScalaFX Code Looks Like the Output
While the output of the Colored Circles example is quite simple, it actually hides quite a bit of complexity in the way it is structured. Here is the output run from JavaFX 2.0 Build 45 using ScalaFX:
What you are actually seeing is a SceneGraph composed of the following layers:
- A Scene with a black background that contains…
- A Group that contains
- 30 semi-transparent Circles covered by…
- A rainbow-colored Rectangle overlay
- A Group that contains
When reading the ScalaFX code you get this nesting through the object-literal style declaration of the Nodes in the Scene as excerpted here:
// ScalaFX Scene Excerpt: scene = new Scene { content = Seq( new Group { circles = for (i <- 0 until 30) yield new Circle { ... } } new Rectangle { ... } ) }
However, the Java version does not give you the same hierarchical representation, and instead uses an imperative series of calls to constructors, getters, and collection methods.
3. Tailored Animation Syntax
Animations are very commonly used in creating good UIs, which is why JavaFX Script had a built-in construct to simplify the creation of animations. ScalaFX has a similar syntax that allows you to quickly and easily create animations, which is used in the ColorfulCircles example:
Seq( at(0 s) {circle.centerX -> random * 800}, at(0 s) {circle.centerY -> random * 600}, at(40 s) {circle.centerX -> random * 800}, at(40 s) {circle.centerY -> random * 600} )
This makes it trivially easy to create complex animations.
4. And the ScalaFX Version Has a Hidden Bonus Feature…
Unlike the JavaFX version, the contents are bound to the width and height of the stage. Binding in ScalaFX is as simple as replacing the assignment operator (=) with the bind operator (<==) as shown here:
// ScalaFX Property Setting: width <== scene.width height <== scene.height
While this is a simple operator change in ScalaFX, it requires complex enough code that they decided to omit it from the JavaFX sample. A loose translation to Java would be the following:
// Java Fixed Property Binding colors.widthProperty().bind(scene.widthProperty()) colors.heightProperty().bind(scene.heightProperty())
Although, the precise equivalent code in Java syntax would actually be the following:
// Java Dynamic Property Binding colors.widthProperty().bind(Bindings.selectDouble(primaryStage.sceneProperty(), "width")) colors.heightProperty().bind(Bindings.selectDouble(primaryStage.sceneProperty(), "height"))
Either of these versions is quite a bit more complex and unwieldy than the ScalaFX equivalent, and this is for a very simple binding!
About ScalaFX
ScalaFX is a UI DSL written within the Scala Language that sits on top of JavaFX 2.0 (not to be confused with Ingo Maier’s great work on Functional Reactive Programming for Swing). This means that every ScalaFX application is also a valid Scala application. By extension it supports full interoperability with Java and can run anywhere the Java Virtual Machine (JVM) and JavaFX 2.0 are supported.
Some of the features of ScalaFX include:
A Programmer-Friendly Object-Literal-Like Syntax
ScalaFX uses a simple, hierarchical pattern for creating new objects and building up the scene graph. Here is a simple example that creates a new stage with a rectangle that changes color based on mouse events:
stage = new Stage { title.value = "Hello Stage" width = 600 height = 450 scene = new Scene { fill = Color.LIGHTGREEN content = new Rectangle { x = 25 y = 40 width = 100 height = 100 fill <== when (hover) then Color.GREEN otherwise Color.RED } } visible = true }
Unlike the builders you find in the core JavaFX APIs, the ScalaFX object declaration syntax uses the normal object API. This means that you can use the same operators and convenient syntax to create and modify your scene graph. Also, anything that is permissible in a Scala block (such as variable declarations, method calls, binding, etc.) can also be done inline while constructing objects. For JavaFX builders you need to declare binding after you finish creating your objects, which leads to disassociated and hard to maintain code.
Natural Language Bind Expressions
One of the greatest advantages of using the Scala language as a DSL is the rich support for operators as methods. This is similar to the C++ concept of operator overloading, but much more uniform and clean in its application.
The ScalaFX bind library exposes normal operators such as &&, ||, +, -, *, / on top of all bindable objects. Also, Scala supports operator precedence, so it looks and feels like you are writing normal expressions even though you are creating bound objects under the covers. As a result, you have the full functionality available from the JavaFX 2.0 binding libraries with code that looks akin to mathematical expressions and operators.
Here are some examples of what you can do with the ScalaFX bind API:
Infix Addition/Subtraction/Multiplication/Division/etc.
height <== rect1.height + rect2.height
Aggregate Operators
width <== max(rect1.width, rect2.width, rect3.width)
Conditional Expressions
color <== when (hover) then Color.GREEN otherwise Color.RED
Complex Boolean Expressions and String Concatenation
text <== when (rect.hover || circle.hover && !disabled) then textField.text + " is enabled" otherwise "disabled"
Free-form Invalidation and Change Handlers
rect.hover onInvalidate { needsRepaint = true }
Fully Type-Safe APIs
This may seem like an insignificant point… Type safety is something that Java developers have always had (and often take for granted), and developers in other scripting languages live without (and unknowingly suffer with runtime errors as a result). However, it is a critical feature if you are developing applications that cannot have unexpected runtime errors and bugs after deployment.
A good compiler will be able to pick up many common coding mistakes through comparison of expected and actual types, and a great compiler (like Scala) will automatically infer types for you so you don’t have to tediouisly repeat them throughout your code.
ScalaFX gets the best of both worlds with a scripting-like DSL syntax where you can rarely have to explicitly type objects, with the strong type-safety of the Scala compiler that will infer and check the types of every expression and API call. This means less time spent debugging weird code bugs and misspellings, and higher quality code right out of the gate!
Seamless JavaFX/ScalaFX Interoperability
It is often the case that you do not have complete freedom about the predominant language of the codebase, or of the libraries you are including functionality from. Even in a mixed environment codebase where you have Java, Scala, and possibly other JVM languages, ScalaFX will seamlessly convert and interoperate.
ScalaFX gets this functionality through the implicit operator capabilities of Scala. Anywhere your program expects a JavaFX typed object, it will automatically insert the code to convert from ScalaFX wrapped objects to JavaFX native classes. Any time you use a ScalaFX specific feature, the compiler automatically creates a ScalaFX wrapper object that allows you to call advanced methods and access the full functionality. This all happens behind the scenes, letting you focus on writing clean code, and not fussing about integration and interoperability.
With all this interoperability magic happening behind the scenes, there is some additional overhead on your application. We have taken pains to minimize this using features like @specialize in the Scala language, which allows us to avoid boxing and unboxing costs on primitives. However, without real benchmarks it is hard to tell just how good of a job we have done. Hopefully more on this in a future post.
Finding out More About ScalaFX
The ScalaFX project site is hosted by Google Code including a couple mailing lists that you should join if you are interested:
At the time of writing we do not have a bundled release, but are interested in early adopter feedback. If you would like to give it a try, please download the source and give it a quick spin!
I will have more details about ScalaFX at my upcoming JavaOne session with Dean Iverson entitled “JavaFX 2.0 With Alternative Languages“. Come to hear more about Scala, Groovy, and other JVM languages you can use to write simpler, cleaner code.
Reference: JavaFX 2.0 and Scala, Like Milk and Cookies from our JCG partner Stephen Chin at the Steve On Java blog.