|
Spec-Zone .ru
спецификации, руководства, описания, API
|
A qualified name is a reference to a package or class. The reference is specified by a dot separated list of package and subpackage names.
java.lang.Object is a qualified name referencing the Object class in the lang subpackage of the java package. These are some ways that qualified names are used:
import java.util.GregorianCalendar;
class FooWriter extends java.io.PrintWriter {}
var baseFile = new java.io.File("base.txt");
An object literal is the primary way that new instances of a class are created in JavaFX Script. They also allow adding new functionality to the instance including functions and additional on-replace clauses on instance variables.
The qualifiedName must reference a JavaFX Script class.
For these examples assume a Point class defined like this:
class Point {
var x : Number;
var y : Number;
}
An object literal creates an instance of the class and sets the initial values of instance variables:
def somewhere = Point {
x: 3.2
y: 7.8
}
Note that the instance variable initializers may be written in any order and that the initializing expressions are evaluated in the order written.
An object literal need not provide initializers for instance variables, though some classes may require certain instance variables to be initialized for proper functioning of an instance. Thus these are valid:
def default = Point {}
def high = Point {
y: 92.1
}
See the Classes chapter for more information on instance variable initialization.
Variables and functions local to the object literal may be supplied to assist in its construction. Here, the local variable radius is defined.
def location = Point {
def radius = 10.3;
x: radius * 2
y: radius * 5
}
Often local variables are used in the construction of nested object literals to allow cross-referencing. For example:
class Tree {
var value : String;
var children : Tree[];
var previousSibling : Tree;
function format(indent : String) : String {
"{indent}{value} "
"{if (previousSibling != null) '(prev:{previousSibling.value})' else ''}"
"\n"
"{for (kid in children) kid.format(' {indent}')}"
}
}
def root = Tree {
def tunicates = Tree {
value: 'Urochordata'
}
def skulledBeasts = Tree {
def hagfish = Tree {
value: 'Hyperotreti'
}
def us = Tree {
value: 'Vertebrata'
previousSibling: hagfish
}
value: 'Craniata'
children: [ hagfish, us ]
previousSibling: tunicates
}
value: 'Chordata'
children: [ tunicates, skulledBeasts]
}
println( root.format("") );
Which uses local defs within nested object literals to build sibling relationships. Its output is:
Chordata
Urochordata
Craniata (prev:Urochordata)
Hyperotreti
Vertebrata (prev:Hyperotreti)
Additional on-replace clauses may be added to the Point example by overriding an instance variable:
def current = Point {
override var x on replace { println( "Changed x to {x}" ) }
override var y on replace { println( "Changed y to {y}" ) }
x: 66.6
y: 33.3
}
current.x = 99.9;
This will print:
Changed x to 66.6 Changed y to 33.3 Changed x to 99.9
The instance variable initializer can be a unidirectionally or bidirectionally bound expression, as this object literal (which keeps its Point on a circle) demonstrates:
import java.lang.Math.*;
var angle = 0.0;
def onCircle = Point {
x: bind cos(angle)
y: bind sin(angle)
override function toString() : String { "Point({%4.1f x}, {%4.1f y})" }
}
println( onCircle );
angle = 0.5 * PI;
println( onCircle );
angle = PI;
println( onCircle );
angle = 1.5 * PI;
println( onCircle );
angle = 2 * PI;
println( onCircle );
The x instance variable of onCircle will be maintained as the cosine of the angle, while y will be maintained as the sine. See the Binding chapter for more information of bind. The toString() function (defined on Object) has been overridden in the object literal to provide a better output format. This is what is printed to the console:
Point( 1.0, 0.0) Point( 0.0, 1.0) Point(-1.0, 0.0) Point(-0.0, -1.0) Point( 1.0, -0.0)
The value of an object literal is the new instance. The type of an object literal is the class given in the qualifiedName.
The this expression is a reference to the current instance.
[To do: add examples, syntax diagram, description]
Where the two QUOTE tokens are matching single or double quote.
Like string literals, adjacent string expressions (and string literals) are automatically concatenated at compile time.
[To do: describe portable Formatter that handles the common subset]
Creates a sequence by explicitly listing the elements of the sequence.
Table 6.9. Explicit Sequence Expression Values
| Explicit Sequence Expression | Value | Discussion |
|---|---|---|
| ['One', 'Two', 'Buckle', 'My', 'Shoe'] | [ 'One', 'Two', 'Buckle', 'My', 'Shoe' ] | An explicit sequence of String |
| [4, 7, [9, 3], 2] | [ 4, 7, 9, 3, 2 ] | Sequences do not nest, so embedded sequences are flattenned |
| var x = 32; [x, 4, x] | [ 32, 4, 32 ] | The explicit sequence component are valueExpressions. |
| var seq = ['bop', 'a']; ['be', seq, 'lulu'] | [ 'be', 'bop', 'a', 'lulu' ] | Again, sequences flatten |
| var nada = null; ['be', nada, 'lulu'] | [ 'be', 'lulu' ] | null, is the absence of value, thus equivalent to the empty sequence, which just flattens away. |
Creates a sequence which is a range of Integer or Number values.
The three valueExpressions that give the beginning, ending and step of the sequence must either be of type Integer or Number. If any of these are of type Number, the rangeExpression is of type sequence of Number, otherwise it is of type sequence of Integer.
The step valueExpression if absent, defaults to one. The step may be negative. The values in the sequence are all value between the beginning valueExpression and the ending valueExpression where the values step by the step valueExpression. The beginning valueExpression is inclusive. The ending valueExpression is inclusive unless the ..< form is used.
Here are some range expressions, and their corresponding values:
Table 6.10. Range Expression Values
| Range Expression | Value | Discussion |
|---|---|---|
| [1..5] | [ 1, 2, 3, 4, 5 ] | No explicit step is provided, so the default of one is used. Beginning and ending valueExpressions are of Integer type so the sequence elements are of Integer type. |
| [1..<5] | [ 1, 2, 3, 4 ] | The less-than sign indicates one (inclusive) through five (exclusive). |
| [1 .. 5.0] | [ 1.0, 2.0, 3.0, 4.0, 5.0 ] | The ending valueExpression is of Number type so the sequence elements are of Number type. |
| [8.6 .. 12] | [ 8.6, 9.6, 10.6, 11.6 ] | 8.6, then 1 + 8.6, etc |
| [1..9 step 2] | [ 1, 3, 5, 7, 9 ] | Explicit step of two: 1, 2 + 1, etc |
| [100..90 step -3] | [ 100, 97, 94, 91 ] | Negative step, values are decreasing. |
| [0..1 step 0.25] | [ 0.0, 0.25, 0.5, 0.75, 1.0 ] | Fractional step |
| [0..<1 step 0.25] | [ 0.0, 0.25, 0.5, 0.75 ] | Exclusive of the ending. |
| [5..1] | [ ] | There are no values between five and one when stepping by one, the resulting sequence is empty. Since the beginning and ending values are literals, this can be detected by the compiler, which prints a warning. |
The beginning, ending and step need not be literal values, but can be arbitrary valueExpressions.
A block is a list of expressions. A block forms a scope.
The type of a block is the type of the final expression in the block. The value of a block is the value of the last expression in the block. For example:
println( {
var sum = 0;
var counter = 10;
while (counter > 0) {
sum += counter;
--counter;
}
"Sum is {sum}"
} )
The block printed by the println is
A function expression allows you to express a function definition as a value.
For example:
var func : function(:Integer):Integer;
func = function(n : Integer) { 1000 + n }
println( func(7) );
func = function(n : Integer) { n * n }
println( func(7) );
Here func is a variable declared to be of function type. func then
gets assigned a function which takes an Integer and adds one thousand to
it. The function stored in the variable can then be called, in this case
printing 1007. Then func is reassigned
to a new function definition which squares the incoming Integer; this
time, func(7) is 49.
Instance variable initializers are used to configure the initial state of an instance. With instance variables of function type, function expressions are used to configure actions for the instance.
This class builds a series of Strings based on an initial value and a next function:
class SeriesBuilder {
var initial : String;
var next : function(:String):String;
function series(count : Integer) : String[] {
var current = initial;
var result = [initial];
for (idx in [1..count]) {
current = next(current);
insert current into result;
}
result
}
}
def aba = SeriesBuilder {
initial: 'X'
next: function(curr : String) { "{curr}o{curr}" }
}
def shorten = SeriesBuilder {
initial: 'lambda'
next: function(curr : String) { curr.substring(1) }
}
def bop = SeriesBuilder {
initial: 'Lake'
next: function(curr : String) { ['Beach', 'Mountains', 'Desert'][curr.length() mod 3] }
}
println( aba.series(4) );
println( shorten.series(5) );
println( bop.series(5) );
Three very different sequences of Strings are produced given the three different initial value and next function pairs. The following is printed:
[ X, XoX, XoXoXoX, XoXoXoXoXoXoXoX, XoXoXoXoXoXoXoXoXoXoXoXoXoXoXoX ] [ lambda, ambda, mbda, bda, da, a ] [ Lake, Mountains, Beach, Desert, Beach, Desert ]