Coercions are automatically performed on numeric types when passing
arguments or return values to/from Java methods. In addition, implicit
truncating coercions are performed when converting Numbers to Integers.

In F3, the var
keyword introduces a new variable. You may specify the type of a
variable in its declaration, however in F3 that's optional. If you
don't specify the type, the F3 interpreter infers the variable's type
from its use. A variable declaration takes the form

var variableName : typeName[?,+,*] = initializer;

You may use one of the ?, +, or * operators to denote the cardinality of the variable, as follows:

Operator

Meaning

?

Optional (i.e, may be null)

+

One or more

*

Zero or more

Example:

var nums:Number* = [1,2,3];

This example declares a new variable named "nums" whose value is
defined to consist of zero or more instances of type "Number" and whose
initial value is [1,2,3].

The : typeName, [?,+,*], and = initializer portions of the declaration are optional, so the following is equivalent to the above:

var nums = [1,2,3];

Functions, Arrays, Expressions, and Operations

F3 functions represent a pure functional subset of the F3 programming language. The body of a function may only contain a series of variable declarations and a return statement. F3 also provides procedures (called operations, see below) which may contain any number of statements including conditional statements, looping statements, try/catch, etc.
The order in which the functions are given is not in general significant.
Here is a very simple example of a functional program

Arrays represent sequences of objects. In F3 arrays are not themselves
objects,
however, and do not nest. Expressions that produce nested arrays (as in
the initialization of "days" above) are automaticallly flattened, i.e:

days == ["Mon","Tue","Wed","Thur","Fri","Sat","Sun"]; // returns true

The size of an array may be determined with the F3 sizeof operator:

var n = sizeof days; // n = 7

There is a shorthand notation using ".." for arrays whose elements form
an arithmetic series. Here for example are definitions of the factorial
function, and of a number "result" which is the sum of the odd numbers
between 1 and 100

In F3 the [] operator also expresses selection (similar to its use in XPath). In this case, the expression contained in the []
is a boolean expression. Such an expression returns a new array
containing only those elements that satisfy the predicate contained in
the [].

As in XPath, within the predicate contained inside the [] operator, the context object may be accessed with the dot operator, for example:

The insert statement inserts the items returned by
evaluating Expression1 into the location indicated by remainder of the
statement as follows:

into

Expression2 must refer to an attribute or variable. If Expression2
refers to a single valued attribute then the effect of the insert is
the same as if the assignment operator were used.

If as first is specified, the insertion location is before the first element of the list indicated by Expression2. If as last is specified, the insertion location is after the last element of the list indicated by Expression2.
If neither as first nor as last is specified explicitly, then as last is used as the default.

Expression2 must be a selection expression over an attribute or variable. If before is specified, the insertion location is before the selected elements. If after is specified the insertion location is after the selected elements.

The first two forms remove all elements from a variable or attribute - which is equivalent to assigning [] or null to the variable or attribute. The latter two forms remove only those elements that match the predicate.

F3 supports list comprehensions as in functional languages like
Miranda and Haskell, but with a familiar syntax that should be easily
understood by Java programmers, namely the F3 select and foreach operators.

A list comprehension consists of one or more input lists, an optional
filter and a generator expression. Each source list is associated with
a variable. The result of the list comprehension is a new list which is
the result of applying the generator to the subset of the cartesian
product of the source lists' elements that satisfy the filter.

List comprehensions give a concise syntax for a rather general class of
iterations over lists.

Another simple example of a list comprehension is:

select n*n from n in [1..100]

This is a list containing (in order) the squares of all the numbers from
1 to 100. Note that "n" is a local variable of the
above expression.

The use of a filter is shown by the following definition of a function
which takes a number and returns a list of all its factors,

function factors(n) {
return select i from i in [1..n/2] where n % i == 0;
}

In F3, any sequence of characters (including whitespace) contained in french quotes <<>>
is treated as an identifier. This allows you to use F3 keywords (or
other normally illegal identifiers) as class, variable, function, or
attribute names, e.g.

var <<while>> = 100;

It also makes it possible to call Java methods whose names are the same as F3 keywords, for example:

By default the interval between the values is 1 but it's also possible to specify a different interval by including the next number in the sequence after number1 separated by a comma. For example, the following expression defines an array consisting of the odd numbers between 1 and 10:

F3 has a built-in String formatting operator (format as), which has the following syntax:

expr format as directive

The format as operator supports java.text.DecimalFormat, java.text.SimpleDateFormat, and java.util.Formatter formatting directives. If the formatting directive starts with %, then java.util.Formatter is used, otherwise if expr is of type Number then java.text.DecimalFormat is used, otherwise if expr is of type java.util.Date then java.text.SimpleDateFormat is used. The directive operand is syntactically an identifier, not an expression. This allows the content of directive to be statically checked for correctness at compile time.

The above example defines a new procedure called "substring" with
two arguments, the first named "s" of type "String", the second named
"n" of type "Number", returning type "String". In addition to the
assignment, delete, and insert statements mentioned above, the
following statements are possible inside the body of an operation :

Expression Statement

A primary expression may be used as a statement, for example:

System.out.println("Hello World!");

If Statement

The F3 if statement is like Java's except that curly
braces are always required around the then and else clauses, unless the
the else clause is another if statement.

The header of the F3 for statement uses the same syntax as the foreach
list comprehension operator. However, in this case the body of the
statement is executed for each element generated by the list
comprehension.

Examples:

for (i in [0..10]) {
System.out.println("i = {i}");
}
// print only the even numbers using a filter
for (i in [0..10] where i % 2 == 0) {
System.out.println("i = {i}");
}
// print only the odd numbers using a range expression
for (i in [1,3..10]) {
System.out.println("i = {i}");
}
// print the cartesian product
for (i in [0..10], j in [0..10]) {
System.out.println(i);
System.out.println(j);
}

Return Statement

The F3 return statement is like Java's:

Example:

operation add(x, y) {
return x + y;
}

Throw Statement

The F3 throw statement is like Java's. However, any object may be thrown, not just those that extend java.lang.Throwable.

The F3 do statement allows you to execute a block of
F3 code in a background thread while allowing the AWT Event Dispatch
Thread to continue processing events, thereby preventing the UI from
appearing to hang. Currently, this is implemented by using java.awt.EventQueue
to pump events while the background thread is executing. Normally, all
F3 code executes in the AWT Event Dispatch Thread. Only code contained
in the body of a do statement is allowed to execute in
another thread. Such code must only access Java objects (and those
objects must handle their own thread synchronization, if necessary).

In the above example, the green code which is executing in the EDT
appears to be blocked during the execution of the body of the do
statement (the red code). However, a new event dispatch loop is created
on the stack while waiting for the background thread to complete. As a
result, GUI events continue to be processed while the do statement is executing. Unfortunately,
this isn't a perfect solution, however, since it can cause multiple
event dispatch loops to build up on the stack - in the degenerate case
causing a stack overflow exception.

do later

The do statement has a second form (do later)
that allows for asynchronous execution of its body in the EDT rather
than synchronous execution in a background thread (providing the
functionality of java.awt.EventQueue.invokeLater) Here's an example:

The F3 syntax for specifying a class is the class keyword followed by the class name, optionally the extends
keyword and a comma separated list of the names of base classes, an
open curly brace, a list of attributes, functions, and operations that
each end in a semicolon, and a closing curly brace. Here is an example:

Attributes are declared using the attribute keyword followed by the attribute's name, a colon, the attribute's type, optionally a cardinality specification (? meaning optional, * meaning zero or more, or + meaning one or more), and an optional inverse
clause specifying a bidirectional relationship to another attribute in
the class of the attributes' type, and terminated with a semicolon.

If the inverse clause is present the F3 interpreter
will automatically perform updates (insert or delete or replace
depending on the kind of update and cardinalities of the attributes) on
the inverse attribute whenever the attribute's value is modified.

Multi-valued attributes (i.e. those declared with the * or + cardinality specifiers) are represented as arrays, and can be accessed via the [] operator and updated with the insert and delete operators.

Unlike Java methods, the bodies all F3 member operations and member
functions are defined outside of the class declaration, for example,
like this:

Parameter and return types are required in the declaration of
operations and functions in the class declaration but may be omitted in
their definitions.

Attribute Declarations

In F3, it's possible to declare initial values for attributes.
The initializers are evaluated in the order the attributes are
specified in the class declaration in the context of the newly created
object:

F3 objects may be allocated using a declarative syntax consisting of
the name of the class followed by a curly brace delimited list of
attribute initializers. Each initializer consists of the attribute name
followed by a colon, followed by an expression which defines its value
(but see below regarding F3's support for incremental evaluation in this context). Here is an example:

In F3, it's possible to declare local variables inside an object
literal. Such variables are only visible within the scope of the object
literal itself. In addition, a variable referring to the object being
initialized may be declared by using the var keyword as a pseudo-attribute, for example:

A trigger consists of a header and a body. The header specifies the type of event the trigger applies to. The body of the trigger
is a procedure that executes whenever the specified event occurs.
Inside the body you can use any of the statements available inside the
body of an operation. Triggers also behave like member
functions/operations, in that the context object is accessible inside
the body via the this keyword.

Creation Triggers

You can perform an action in the context of a newly created object by
specifying a creation "trigger", like this:

In the above example, "num" is the name of a variable that will contain
a reference to the element being inserted (you can name the variable
whatever you like). The context index of the variable (returned by the indexof operator) corresponds to the insertion point.

Delete Triggers

You can perform an action whenever an element is deleted from a
multi-valued attribute by specifying a delete trigger, like this:

In the above example, "num" is the name of a variable that will contain
a reference to the element being deleted (you can name the variable
whatever you like). The context index of the variable (returned by the indexof operator) corresponds to the deletion point.

Replace Triggers

You can perform an action whenever the value of a single-valued
attribute or an element of a multi-valued attribute is replaced, like
this:

In the above examples, "oldValue" and "newValue" are the names of
variables that contain references to the previous and current values of
the element being replaced (you can name the variables whatever you
like). The context index of the variable (returned by the indexof operator) corresponds to the ordinal position of the element being replaced.

In F3, attribute initializers can be specified to be lazily and/or incrementally evaluated with the
bind operator. Attributes initialized with bind
are akin to cells in a spreadsheet that contain formulas rather than
literal values. During the lifetime of the object containg the
attribute, whenever any of the objects referenced by the right hand
side of the initializer expression changes the left hand side (the
attribute's value) is automatically updated.
Here is an example:

In the above example, the b and c attributes of x2 are bound to the
b and c attributes of x1. This means that whenever x1's b or c
attribute is updated the b and c attributes of x2 will be
correspondingly updated. The difference between x2.b and x2.c is that
the former's value is immediately updated in its attribute initializer
whereas the latter's binding is not evaluated until its value is
accessed the first time.

Note: the body of a function is always incrementally evaluated without requiring the bind operator,
however the body of an operation is not. Unlike a function, inside an operation changes to local variables
do not trigger incremental evaluation. Incremental evaluation
is not performed inside the body of an operation except for expressions explicitly
prefixed by bind.

Nevertheless when you call an operation (or a Java
method) from an incremental evaluation context the call itself is
incrementally evaluated.
This means that if the values of any of the arguments to the call
change a new fresh call to that operation or method will be made and a
new value returned.

By contrast, function's are only called once and the result of the evaluation is incorporated into the callers evaluation tree.

Incremental evaluation is one of F3's main distinguishing features
that makes it possible to define complex dynamic GUI's declaratively.
The lazy evaluation feature is needed to handle recursive data
structures like trees and graphs.

In F3, the member functions and operations of a class are themselves
modeled as classes in which the target class, formal parameters, and
return value are represented as attributes. The name of the attribute
representing the target object is 'this'. The name of the attribute
representing the return value is 'return'. The attributes representing
the formal parameters have the same names as the formal parameters.

You obtain such reflected operations from the Class object.

Reflected F3 operations can be called like functions by passing the
target object as the first argument and any parameters as subsequent arguments,
e.g:

Currently, the bean properties and public fields of Java classes are
reflected as F3 attributes. However, Java methods are not reflected as
F3 operations. If you want to call a Java method reflectively you can
simply use the normal Java API's.

Note that, unlike Java, in F3 the class operator is
applied to an expression rather than to a type name. F3 supports the
following syntax to obtain the reflected class object from a type name:

Such named instances are globally accessible but must normally be
qualified with the class name. However, In the context of attribute
initializers and assignments the named instances of the expression's
type are introduced into the lexical scope (with weaker visibility than
variables and attributes) and may be referenced with their unqualified
names, for example:

Button {
mnemonic: P
text: "Press Me"
}

In the above example, since the mnemonic attribute of Button is of type KeyStroke, I can access the named value P with its unqualified name (elsewhere I would have to refer to it as P:KeyStroke).

The values of Java 1.5 enumerated types may be accessed with the same syntax, for example: