Syntax Overview
Fly has a rather minimalistic syntax, but without getting obscure or hard to read. For instance, keywords to identify classes, namespaces and function does not exist, because the structure of a class makes it clear what is meant.
A simple example
Below is a couple of tiny Fly classes:
org.test.Calculator
{
add(a: int, b: int): int
{
return a + b;
}
muldiv(a: int, b: int, c: int): int
{
# Instead of an explicit return, we can set the return value directly:
muldiv = a * b;
muldiv = muldiv / c;
}
}
SomeClass : SomeParent
{
use std.io;
# Fields are actually instance variables with get/set functions
# you can replace later on, e.g if you want to compute the value
# instead of just returning the field variable.
someField: int;
# Constructor
new()
{
}
# An overloaded constructor
new(x: int)
{
someField = x;
}
# A void function
init()
{
# An inner function. Note that we use the function assignment
# syntax instead of using the return statement, which is useful
# if the function builds the return value in steps.
inner(x: int): int
{
inner = x*2;
if (inner > 10)
{
inner = 10;
}
}
someField = 10;
z: int;
y: int = 4;
# Here we use type inference; no explicit type after ':'
x:= inner(z) * y + z;
stdout.print(x);
}
}
There are several points worth noting:
- The namespace and class is defined at once; "org.test.Calculator" denotes a class Calculator in the org.test namespace. Note that namespaces are optional.
- Functions can be nested. The nested functions can be called by the outer function, or returned and passed as an argument (forming a closure)
- Functions can be overloaded. The overloading of SomeClass's new function is an example.
- A colon denotes type annotation. This can be combined with value assignment; for instance, "a: int = 8;".
- Every variable has a default value; e.g. 'z' will be zero in the example.
- Type inference is accomplished by leaving out the typer after the colon, e.g. ":=". The type of the right-hand side expression is used as the type of the left-hand side. Note that := is not an operator; rather the : operator lacks a type and is followed by the assignment operator. Hence ":=" and ": =" means the same thing.
- Fields are actually an instance variable and two functions; a getter and a setter. You can replace the generated implementation of either if you want to.
Functions, lambda expressions and closures
Fly supports the usual member functions as found in C++, Java and C#, as well as nested functions. In addition, function are values, which means they can be assigned to variables and fields, passed as arguments (to form higher-order functions) and returned from other functions.
To form a closure, the lambda operator \ is used.
{
outer(num1: int): (int):int
{
inner(num2: int): int
{
return num1 * num2;
}
return \inner;
# The above could also have been written:
# return \(num2: int):int { return num1*num2; }
}
}
You can also call inner functions directly:
{
outer (someFloat: float): int
{
triple (num: int): int
{
return num * 3;
}
return triple(5) + someFloat;
}
}
Anonymous classes
You can create anonymous classes with fields in an ad-hoc manner by providing the definition, but without a name.
This can be used to implement multiple return values with a concise syntax:
{
multiret.res = 222;
multiret.res2 = 222.333f;
}
test()
{
val := multiret();
val.res = 2;
val.res2 = 3f;
}