Features · Typesafe
Typesafe
Program code is completely type safe, with a simple type system supporting native types, data records,
tagged unions, and generics. The collection module then provides us with types like
Optional and Array.
Native Types
A small set of built-in native types are provided.
Numbers
Whole numbers use Maths.Integer and fractional numbers use Maths.Real.
// A real and an integer
LET Maths.Real pi = 3.14
LET Maths.Integer count = 42
// Display each one
Ui.Content.Real pi
Ui.Content.Integer count
Maths.Real called pi holding 3.14 and a Maths.Integer called count holding 42.Text
Textual values use Text.
// A text value
LET Text greeting = "Hello"
// Display it
Ui.Content.Text greeting
Text value called greeting holding "Hello".Data Records
Definition
A record TYPE defines a group of FIELDs,
giving each FIELD a name within that record.
// Define a Point record
TYPE Point
FIELD Maths.Real x
FIELD Maths.Real y
// Define a Circle record, centred on a point
TYPE Circle
FIELD Point centre
FIELD Maths.Real radius
x and y value, and a circle with a point centre and a radius.Construction
Variables can be constructed using a data record — name the type and supply its fields in order.
// Create a point
LET Point myPoint = Point 3.0 4.0
// Create a circle centred on that point
LET Circle myCircle = Circle myPoint 5.0
x = 3.0, y = 4.0, then a circle centred on it with radius 5.0.Usage
Fields of a data record variable can be accessed via their names.
// Display the x coordinate of the circle's centre
Ui.Content.Real myCircle.centre.x
x field and displays the coordinate.Tagged Unions
Definition
A union TYPE is a closed set of variants, so a value is
exactly one of them at a time.
// Define a Shape union
TYPE Shape
OPTION Text text
OPTION Circle circle
Shape with variants called text and circle.Construction
Variables can be constructed by naming a variant and supplying its value.
// Create a shape
LET Shape myShape = Shape.text "Hello"
Shape called myShape holding a Text value containing "Hello".Usage
Reading a variant produces an Optional — it is present only when the value is that
variant — so the result must be checked before use.
// Display as text if the shape is a text shape
Collection.Optional.If myShape.text
INPUT Text text
Ui.Content.Text text
// Display as a circle if the shape is a circle shape
Collection.Optional.If myShape.circle
INPUT Circle circle
Ui.Content.Image
Graphics.Shape.Circle circle.centre.x circle.centre.y circle.radius
Generics
Program supports generics in both type definitions and functions. A name in parentheses after the
type or function name is a generic parameter — a placeholder standing in for a type the caller
chooses. A generic record is written TYPE TypeName(GenericName) and a generic function
FUNCTION FnName(GenericName), and the placeholder is then usable anywhere a type is in
that definition.
// Define a generic record and a function that uses it
TYPE Entry(Value)
FIELD Text label
FIELD Value content
FUNCTION Entry(Value) WithContent(Value)
INPUT Entry(Value) entry
INPUT Value content
= Entry entry.label content
Here WithContent takes an Entry(Value) record and one Value, and
returns a new Entry with the same label but the given content. Whatever type
Value is bound to, the record's field and the argument are guaranteed to be the same
type — the substitution is checked, not assumed.
Any number of generic types can be provided, separating them by space:
// Define a record with two generic types
TYPE Pair(Left Right)
FIELD Left first
FIELD Right second
Optionals
There is no bare null that slips through unchecked. A value that may be missing is an
Optional — itself a union of present and absent — so the absence is
in the type and the compiler makes you account for it. Because it is a real type, it even nests:
an optional of an optional is a distinct, meaningful thing.
Construction
An Collection.Optional(Circle) is built by naming the present variant with a
value, or the absent variant with none.
// A circle that is present
LET Collection.Optional(Circle) presentCircle = Collection.Optional.present myCircle
// A circle that is absent
LET Collection.Optional(Circle) absentCircle = Collection.Optional.absent
myCircle, the other holds nothing.Usage
A function takes an optional circle and displays it — the Collection.Optional.If body
runs only when a circle is present, so the absent case is handled by drawing nothing at all.
// Function draws a circle if it is present
FUNCTION ShowCircle
INPUT Collection.Optional(Circle) maybeCircle
// Check if the circle is present
Collection.Optional.If maybeCircle
INPUT Circle circle
Ui.Content.Image
Graphics.Shape.Circle circle.centre.x circle.centre.y circle.radius
// Call it for each — the present circle draws, the absent one draws nothing
ShowCircle presentCircle
ShowCircle absentCircle
Carried to every target
The same types map onto each target's own type system: a record becomes a struct or
class, a union becomes a sum type — a Swift enum, a Rust enum,
a Dart sealed class — and a built-in maps to the native primitive. So the
generated code is type-safe in its own right, checked by that
language's compiler too, not only at the Program layer.