Keywords · TYPE

TYPE

A TYPE defines the shape that a piece of data can take.

Format

The grammar of a single TYPE line:

TYPE ::= "TYPE" identifier
identifier ::= letter { letter | digit }
A TYPE keyword is followed by the name of the type being declared; its fields, options or native bodies follow as indented lines.

Usage

A TYPE keyword can live inside MODULE, TYPE, and FUNCTION keywords, or at the Root.

Inside a MODULE

Declares a type whose full name is prefixed by the enclosing module.

MODULE Geometry
  TYPE Point
    FIELD Maths.Real x
    FIELD Maths.Real y
A Point record declared inside the Geometry module.

Inside a module the module name becomes part of the type's full name, so this Point is the type Geometry.Point.

Inside a TYPE

Nests a type under another type acting as a pseudo-module.

TYPE Shape
  TYPE Point
    FIELD Maths.Real x
    FIELD Maths.Real y
A Point nested under Shape, purely for naming.

The outer type acts as a pseudo-module: Point is nested under its dotted name as an independent type, not a member.

Inside a FUNCTION

Nests a type under a function acting as a pseudo-module.

FUNCTION Maths.Real Distance
  TYPE Point
    FIELD Maths.Real x
    FIELD Maths.Real y
A Point declared under the Distance function.

The function acts as a pseudo-module; the type is nested under its dotted name, independent of the function's own logic.

At the Root

Declares a free type, named directly with no prefix.

TYPE Point
  FIELD Maths.Real x
  FIELD Maths.Real y
A standalone Point record at the Root.

With no enclosing declaration, the type is named directly and lives at the Root.

Can Contain

A type's members are either FIELD lines or OPTION lines — never a mix of the two; that is what makes a type a record or a union. Alongside them it may carry NATIVE lines and nested declarations as a pseudo-module (listed below).

Containing a FIELD

A named, typed member of a record. The order of the fields is the order of the constructor's arguments, so Point 0.0 0.0 fills x then y, and reading somePoint.x is a reactive, reversible projection. A type that holds fields is a record.

TYPE Point
  FIELD Maths.Real x
  FIELD Maths.Real y
Two fields make Point a record; their order is the constructor’s.

Containing an OPTION

A named variant of a union, carrying a payload type. The option name is both a constructor (Shape.circle x) and a reactive projection (value.circle) that yields an Optional of the payload. A type that holds options is a union.

TYPE Shape
  OPTION Circle circle
  OPTION Rect rect
Two options make Shape a union of variants.

Containing a NATIVE

A per-platform native representation of the type, one line per target — the host type the renderer uses for that language. A type may be all NATIVE lines when it is an opaque platform type (a native map or array, say), or pair them with fields or options that serve as the Program fallback where a target has no native line.

TYPE Instant
  NATIVE js "Date"
A per-platform native representation of the type.

Containing a MODULE

A nested module under the type's dotted name — the type acting as a pseudo-module, since a type is so often the centre of a module. Pure naming convenience.

TYPE Colour
  MODULE RGB
A module nested under the type’s dotted name, Colour.RGB.

Containing a TYPE

Another type under this type's dotted name, acting as a pseudo-module. Pure naming convenience — an independent type, not a method.

TYPE Text
  TYPE Span
    FIELD Maths.Integer start
Another type under this type’s dotted name, Text.Span.

Containing a FUNCTION

A function under the type's dotted name, the type acting as a pseudo-module. It is completely independent and not a method: Text.Append does not belong to a Text value or receive one implicitly — it merely shares the Text prefix for tidy naming and takes whatever it operates on as a normal parameter.

TYPE Text
  FUNCTION Text Append
    INPUT Text head
    INPUT Text tail
    = head
A function under the type’s dotted name, Text.Append — not a method.

Containing a LET

A named constant under the type's dotted name, the type acting as a pseudo-module — a fixed value bound with a constant expression and reached through the type's name (as Colour.RGB.Black). A declaration, not a field or a method.

TYPE Colour.RGB
  LET Colour.RGB Black = Colour.RGB 0.0 0.0 0.0
A constant under the type’s dotted name, reached as Colour.RGB.Black.

Targets

The same two examples, rendered to each target. A record becomes the target's idiomatic struct or class; a union becomes its idiomatic sum type, one variant per option. The surface keyword is one, but the compiled form still distinguishes the two — a record is a ["D", …] node in the canonical JSON, a union a ["U", …].

A record type

JavaScript

class Point {
  constructor(x, y) { this.x = x; this.y = y; }
}

TypeScript

class Point {
  constructor(public x: number, public y: number) {}
}

Dart

final class Point {
  final double x;
  final double y;
  Point(this.x, this.y);
}

Swift

public struct Point {
  public let x: Double
  public let y: Double
  public init(_ x: Double, _ y: Double) { self.x = x; self.y = y }
}

Go

type Point struct {
  x float64
  y float64
}

Rust

struct Point {
  x: f64,
  y: f64,
}

Zig

const Point = struct {
  x: f64,
  y: f64,
};

JSON

["D", "Point", [], [
  ["P", "x", "Maths.Real"],
  ["P", "y", "Maths.Real"]
]]

A union type

JavaScript

// a tagged value: { tag: "circle" | "rect", value }
class Shape {
  constructor(tag, value) { this.tag = tag; this.value = value; }
  static circle(value) { return new Shape("circle", value); }
  static rect(value)   { return new Shape("rect", value); }
}
// value.circle projects reactively: (s.tag === "circle" ? s.value : null)

TypeScript

type Shape =
  | { tag: "circle"; value: Circle }
  | { tag: "rect";   value: Rect };

const Shape = {
  circle: (value: Circle): Shape => ({ tag: "circle", value }),
  rect:   (value: Rect):   Shape => ({ tag: "rect",   value }),
};

Dart

sealed class Shape {}
final class ShapeCircle extends Shape { final Circle value; ShapeCircle(this.value); }
final class ShapeRect   extends Shape { final Rect   value; ShapeRect(this.value); }

Swift

public enum Shape {
  case circle(Circle)
  case rect(Rect)
}

Go

type Shape struct {
  tag   string
  value any
}
func Shape_circle(v Circle) Shape { return Shape{"circle", v} }
func Shape_rect(v Rect) Shape     { return Shape{"rect", v} }

Rust

enum Shape {
  Circle(Circle),
  Rect(Rect),
}

Zig

const Shape = union(enum) {
  circle: Circle,
  rect: Rect,
};

JSON

["U", "Shape", [], [
  ["P", "circle", "Circle"],
  ["P", "rect", "Rect"]
]]

Related

A record is every FIELD at once; a union is exactly one OPTION of several — the two are duals, and a field or an option may itself carry another type. A record is built by calling its type name positionally (Point 0.0 0.0) and read with reactive value.field access; a union is built with the option name as constructor (Shape.circle x) and read with reactive value.option projection, which yields an Optional — itself just the built-in union with some and none options. A type may be given a native representation per platform with NATIVE lines, and a recursive union that holds a collection of itself is the model behind the JSON value type in Code.Language.Json. Back to the language.