Introduction
Visage programs are very descriptive of the UI due to the Object Literal syntax, but this also introduce a very high level of nesting in typical programs. The goal of the default properties feature was to create a simplified syntax that makes it easier to read nested data structures.
Details
With the default properties support you can take code that looks like this:
Stage {
scene: Scene {
contents: Rectangle {
width: 100
height: 100
}
}
}and reduce it to this:
Stage {
Scene {
Rectangle {
width: 100
height: 100
}
}
}So how did the compiler know that the "scene" and "content" labels were optional? This is because those class variables were created using the new "default" keyword like this:
public class Stage {
public-init default var scene:Scene;
}
public class Scene {
public-init default var content:Node[];
}Multiple Defaults
Each class can have 1 and only 1 variable declared as the default. Declaring multiple defaults will result in a compiler error like the following:
C:\dev\project\SomeClass.fx:50: Variables entries and centered both have the default modifier.
Only one class variable can be declared as the default.
public default var centered:Number;Mixing With Labeled Variables
It is valid to have a class with multiple variables, only one of which is the default. For example, you could declare a class like the following:
public class Text {
public default var content:String;
public var fontSize:Integer;
public var fontName:String;and use it as follows:
Text {
"Visage default properties rock!"
fontSize: 24
fontName: "Arial Black"
}If you declare variables before the default, they will be scoped at the block level and be available to all the properties. To declare private variables, add a label before the default variable.
Subclassing
If a subclass also defines a default variable, it will shadow the superclass default. For example, the following code:
class SuperDefault {
public default var contents:String[];
}
class ShadowDefault extends SuperDefault {
public default var shadow:String[];
}
def sd = ShadowDefault {
["a", "b", "c"]
}
println("contents: {sd.contents.toString()}, shadow: {sd.shadow.toString()}");will set the value for "shadow" rather than "contents", resulting in the following output:
contents: [ ], shadow: [ a, b, c ]
Compatibility
This change is not backwards compatible due to the addition of the "default" keyword to the language syntax. However, this is an easy change (rename) that will fix most programs. It also does not affect existing compiled binaries.
These changes themselves are binary compatible with previous compiler releases. This means that you can compile code using defaults against compiler versions that do not use this feature. Also, the resulting class files can be run on older compiler binaries.
Does "default" need to be a reserved word? I would have thought it would be like "init", which is a keyword but not reserved, so that you can still have an identifier called "init".