Planet JFX

The syntax for the JavaFX Script language is changing to further improve its clarity, ease-of-use, and support for compilation. As the language evolves, this page lists those changes and how to update your code.
Update: We distinguish between interpreter syntax [I], old compiler syntax [O] and syntax of the first official release [1.0].

Operations[]

  • Description: The language used to differentiate between functions and operations (procedures). The current syntax merges these two concepts into just one: function. Functions are no longer restricted to variable declarations and return expressions, and basically old-style operations with a new name.
  • Conversion: Rename all "operation" keywords to "function".

[I]:

  class Foo {
      function times2(x) { return x * 2; }
      operation print(s) { System.out.println(s); }
  }

[O]/[1.0]:

  class Foo {
      function times2(x) { return x * 2; }
      function print(s)  { System.out.println(s); }
  }

Attribute Initialization[]

  • Description: If a declared attribute had an initial value, it was set outside of the class body. Attribute initial values are now set as part of the declaration, like Java.
  • Conversion:

[I]:

  class Foo {
      attribute bar: Boolean;
  }

  attribute Foo.bar = true;

[O]:

  class Foo {
      attribute bar: Boolean = true;
  }

[1.0]:

  class Foo {
      var bar: Boolean = true;
  }

Replace Triggers[]

  • Description: Replace triggers were defined outside of the class body. Replace triggers are now part of the attribute declaration. Also, the syntax has changed, such that the trigger function now follows the keywords "on replace".
  • Conversion:

[I]:

  class Foo {
      attribute bar: Boolean;
  }

  trigger on Foo.bar = value {
      if (bar == true) {
          beep();
      }
  }

[O]:

  class Foo {
      attribute bar: Boolean on replace {
          if (bar == true) {
              beep();
          }
      };
  }

[1.0]:

  class Foo {
      var bar: Boolean on replace {
          if (bar) {
              println("BEEP!");
          }
      };
  }

[I] with Initialization:

  class Foo {
      attribute bar: Boolean = true;
  }

  trigger on Foo.bar = value {
      if (bar == true) {
          beep();
      }
  }

[O] with Initialization:

  class Foo {
      attribute bar: Boolean = true on replace {
          if (bar == true) {
              beep();
          }
      };
  }

[1.0] with Initialization:

  class Foo {
      var bar: Boolean = true on replace {
          if (bar) {
              println("BEEP!");
          }
      };
  }

Cardinality[]

  • Description: In interpreted JavaFX the cardinality operator was represented by '*' asterisk. Now, in compiled JavaFX, we use square brackets.
  • Conversion:

[I]:

class Foo {
  attribute names: String*;
}

attribute names = ["Monica", "Rachel", "Phoebe"];

[I]:

class Foo {
  attribute names: String[] = ["Monica", "Rachel", "Phoebe"];
}

[1.0]:

class Foo {
  var names: String[] = ["Monica", "Rachel", "Phoebe"];
}

Object literals without attributes[]

  • Description: In interpreted JavaFX, it was possible to mention just a class name to refer an object literal without attributes. In compiled JavaFX, curly brackets are required.
  • Conversion:

[I]:

Frame {
  title: "Show MenuSeparator"
  height: 180
  width: 320
  menubar: MenuBar {
    menus: Menu {
      text: "File"
      items: [MenuItem {
        text: "New"
      }, MenuItem {
        text: "Open"
      }, MenuItem {
        text: "Save"
      }, MenuSeparator, MenuItem {
        text: "Import"
      }]
    }
  }
  visible: true
}

[O]:

Frame {
  title: "Show MenuSeparator"
  height: 180
  width: 320
  menubar: MenuBar {
    menus: Menu {
      text: "File"
      items: [MenuItem {
        text: "New"
      }, MenuItem {
        text: "Open"
      }, MenuItem {
        text: "Save"
      }, MenuSeparator {
      }, MenuItem {
        text: "Import"
      }]
    }
  }
  visible: true
}

[1.0]:

import javafx.stage.*;
import javafx.scene.*;
import javafx.scene.text.*;
import javafx.scene.shape.*;

// No MenuBar currently in standard JavaFX, use another example
Stage {
  title: "Show MenuSeparator"
  height: 180
  width: 320
  scene: Scene {
    content: [
      Text {
        x: 10, y: 30
        content: "Hello, World!"
      }, Circle {},
      Text {
        x: 10, y: 80
        content: "Goodbye, World!"
      }
    ]
  }
}

Named instances[]

  • Description: In interpreted JavaFX, it was possible to use named instances that more or less represented what is now required in compiled JavaFX - the fully qualified constants, or to use object literals.
  • Conversion:

[I]:

Frame {
  title: "White Frame"
  background: white
  ...
}

[O]:

Frame {
  title: "White Frame"
  background: Color.WHITE
  ...
}

Or:

Frame {
  title: "White Frame"
  background: Color {
    red: 1
    green: 1
    blue: 1
    opacity: 1
  }
  ...
}

[1.0]:

Stage {
  title: "White Frame"
  scene: Scene {
    fill: Color.WHITE
  ...
}

Or:

Stage {
  title: "White Frame"
  scene: Scene {
    fill: Color { 
      red: 1 
      green: 1 
      blue: 1 
      opacity: 1 
    }
  ...
}

Note also the Frame replaced by Stage/Scene. Stage is optional (with default blank title).

Anonymous object literals[]

  • Description: In interpreted JavaFX, we could use anonymous object literals and the interpreter inferred type of such block of code. In compiled JavaFX, we need to use named object literals.
  • Conversion:

[I]:

...
    accelerator: {
      modifier: CTRL
      keyStroke: O
    }
....

[O]/[1.0]:

...
    accelerator: Accelerator {
      modifier: KeyModifier.CTRL
      keyStroke: KeyStroke.O
    }
...

Function overriding[]

  • Description: In old compiled JavaFX, when you override a function, it is needed to mention its return type in function's signature. In official JavaFX (1.0), it is no longer needed (but good practice anyway...) but you must use the overrride keyword.
  • Conversion:

[I]:

class MyWidget extends CompositeNode {
  ...
  function composeNode() {
    ...
  }
}

[O]:

class MyWidget extends CompositeNode {
  ...
  function composeNode(): Node {
    ...
  }
}

[1.0]:

class MyWidget extends CustomNode {
  ...
  override function create() {
    ...
  }
}

Bidirectional binding[]

  • Description: If you want to use the bidirectional binding feature, you have to use new 'with inverse' syntax in compiled JavaFX.
  • Conversion:

[I]:

...
  TextField {
    value: bind model.firstName
  }
...

[O]:

...
  TextField {
    value: bind model.firstName with inverse
  }
...

[1.0]:

...
  SwingTextField {
    text: bind model.firstName with inverse
  }
...

Casting from Number to Integer[]

  • Description: To avoid loss of precision error during compilation, use the intValue() function.
  • Conversion:

[I]:

...
var real: Number;
real = 6.42;
var integer: Integer;
integer = real;
...

[O]:

...
var real: Number;
real = 6.42;
var integer: Integer = real.intValue();
...

[1.0]: Idem, or perhaps just use casting:

...
var real: Number;
real = 6.42;
var integer = real as Integer;
...

Inheritance[]

  • Description: In current state of JavaFX compiler (as of March 2008) it may be needed to use 'as' construct as a workaround to avoid inheritance issues.

Not needed in 1.0.

  • Conversion:

[I]/[1.0]:

class Foo extends Rectangle {
  ...
}

...

...
  content: Canvas {
    content: Foo {
      ...
    }
    ...
  }
  ...
}

[O]:

class Foo extends Rectangle {
  ...
}

var foo :Foo = Foo {
  ...
};

...
  content: Canvas {
    content: foo as Node
    ...
  }
  ...
}

Loops[]

  • Description: The foreach loop was deprecated and the only one foreach-like loop in compiled JavaFX is for loop. You can use the for loop as you're used to use from Java for example and also as a foreach loop from interpreted JavaFX.
  • Conversion:

[I]:

...

  for (Integer i = 0; i < group.length; i++) {
    System.out.println(group[i]);
  }

  ...

  foreach (element in group) {
       System.out.println(element);
  }
...

[O]:

...

  for (Integer i = 0; i < group.length; i++) {
    System.out.println("{i} {group[i]}");
  }

  ...

  for (element in group where element.length() < 4) {
    System.out.println({element});
  }
...

[1.0]:

...

  for (i in [0 .. <group.length]) {
    println("{i} {group[i]}");
  }

  ...

  for (element in group where element.length() < 4) {
    println(element);
  }
...