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
A 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
A 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
Two data records: a point with an 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
Constructs a point at 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
Reads the centre's 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
A tagged union called 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"
Constructs a 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
If it is text, displays it as content text; if it is a circle, displays a content image of that circle.

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
Two optional circles of the same type: one holds 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
If the optional is present, displays it as a content image; if it is absent, displays nothing.

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.