
Statements
Overview
Fan code is written as a series of statements just like Java or C#. However unlike Java/C#, Fan statements are not required to be terminated with a semicolon. A Fan statement may be terminated one of three ways:
- newline
- semicolon
- end of block
}
curly brace
By convention a simple newline is the preferred mechanism for separating statements. A semicolon is only used when placing multiple statements on the same line. For example these are all valid Fan statements:
if (authenticated) { sendToHomePage return true } if (authenticated) { sendToHomePage(); return true; } if (authenticated) { sendToHomePage; return true }
The first version is the preferred syntax. The third version exhibits good mojo too if it is compact enough to keep the code readable.
The Fan grammar is not perfectly unambiguous without using semicolons. So on occasion you will run into a situation when the compiler complains and you might need to stick in a semicolon - but in practice this rarely happens.
Expression Statements
The most common type of statement is a stand alone expression. The following expressions are considered valid statements:
- Any assignment expression including the increment/decrement operators
- Method calls (or chains of method calls)
- With block
Return Statement
The return
statement is used to exit a method:
// if Void method: return // if non-Void method: return <expr>
If the enclosing method is Void
, then return
simply returns control back to the code which called the method. If the enclosing method is non-void, then the return
statement includes the expression used to return a result object to the caller.
Local Variables
Local variables may be declared using the following syntax:
// syntax <type> <identifier> := <init> // example Str name := "Jack Shephard"
Fan supports type inference for local variables, which allows you to omit the type signature. If the type signature is omitted, then the variable is typed according to the initializer expression. In the example above the right hand side resolves to a Str
, so we could rewrite the statement above as:
name := "Jack Shephard"
Fan convention encourages use of type inference when possible. However if the right hand side expression resolves to an ambiguous type, then you will need to specify the variable's type signature. The most common case when type inference doesn't work is when you need to initialize a local variable to null
.
Fan uses the :=
operator for local variable initialization rather than the standard =
assignment operator. The primary purpose of the :=
syntax is to distinguish normal assignments from local declarations. This syntax captures programmer intent better and enables the compiler to catch typos like a misspelled local.
Fan does not support the comma operator to declare multiple local variables like Java or C#. In practice though most locals will be declared using type inference.
If a local variable is not explicitly assigned an initial value, then it implicitly defaults to null
(just like fields). This is also a little different than Java or C# which require definite assignment.
If Statements
Fan supports if
and else
using the Java/C# syntax:
if (<cond>) <block> if (<cond>) <block> else <block> if (<cond>) <block> else if (<cond>) <block> else <block>
The if
condition must evaluate to a sys::Bool
expression. The block can be a single statement or a block of multiple statements delineated by {
}
curly braces.
Loop Statement
Fan supports while
and for
loops using familiar Java and C# syntax. Although you'll find when writing Fan that most looping is actually done using closures.
While Statement
Fan supports while
loops using Java/C# syntax:
// syntax while (<cond>) <block> // example while (p != null) p = p.next
The while
loop executes its block until its condition evaluations to false
. The while
condition must evaluate to a sys::Bool
expression. The block can be a single statement or a block of multiple statements delineated by {
}
curly braces.
Fan doesn't currently support do
while
loops.
For Statement
Fan supports for
loops using Java/C# syntax:
// syntax for (<init>; <cond>; <update>) <block> // example for (i:=0; i<10; ++i) echo(i)
The for
condition must evaluate to a sys::Bool
expression. The block can be a single statement or a block of multiple statements delineated by {
}
curly braces. All three expressions of the for
loop are optional. If the cond expression is omitted, it defaults to true
. The init expression is executed once on loop entry and the update expression after each run of the loop. The for
loop runs until the condition evaluates to false
.
Like Java/C# the init expression of the for
loop can be a local variable declaration which defines a local scoped only within the for
loop. Unlike Java/C# the comma operator is not supported in the init and update expressions.
Break Statement
The break
statement is used with both the for
and while
loops to break out of the loop. For example:
for (i:=0; i<10; ++i) { if (i == 3) break echo(i) } echo("done") // prints 0 1 2 done
The break
statement always applies to the inner-most loop. Fan does not support labeled breaks
.
Continue Statement
The continue
statement is used with both the for
and while
loops to jump back to the top of the loop. For example:
for (i:=0; i<4; ++i) { if (i == 2) continue echo(i) } echo("done") // prints 0 1 3 done
The continue
statement always applies to the inner-most loop. Fan does not support labeled continues
.
Switch Statement
Fan supports a switch
statement used to execute a block of code by matching the value of a expression against a list of case labels. The syntax is very similar to Java/C#:
switch (<cond>) { case <label1>: <block1> case <label2>: <block2> ... default: <defaultBlock> }
The condition expression is matched against all the case labels. If a match is found, then it executes the statements in that case's block. If no matches are found then the optional default
block is executed. Unlike the if
, for
, and while
statements, the case blocks are not wrapped with {
}
curly braces.
Fan's switch
statement allows the condition and case expressions to be any valid expressions. So you can switch on strings or types too. When the condition evaluates to an sys::Int
or sys::Enum
and the case
labels evaluate to constants, then the switch
is compiled into the tableswitch
opcode. Otherwise the switch
statement matches the case
labels using an equality check via the sys::Obj.equals
method. For example:
// tableswitch switch (weekday) { case Weekday.sat: case Weekday.sun: return "it's the weekend baby!" default: return "back to work!" } // equality switch switch (method.upper) { case "GET": serviceGet case "POST": servicePost default: methodNotSupported }
In Fan the switch
statement doesn't require a break
to end a block of code for a given case like Java or C#. You cannot fall-through from one case block to the next case block. However you can group multiple case labels together like we did with Weekday.sat
and Weekday.sun
in the example above.
Exception Handling
Fan supports throw
and try
statements with a syntax very similar to Java and C#. These statements are discussed separately in the exception handling chapter.