Type System

An overview of the type system.

Introduction

A type is a format for a value, which describes:

Table of Contents

Built-in Types

The following types are available for use in Prog, either built into the interpreter or defined in the standard library.

Abstract Types

An abstract type represents a concept alone, and consumes no memory in a statically-typed expression.

void

void describes the lack of a value. It is the type of an expression returning null. No type is convertible to void, so attempting to return a value from an expression in void context is a type error.

@null == void

any

any describes the lack of a type. There is no expression that returns a value of type any, but a value of any type is convertible to any. Generally, using any precludes static typing, because expressions involving any rely on RTTI.

@X == any;

type

type describes a type object. It is the type returned by the type-of operator (@). Using type does not necessarily preclude static typing, even if non-const types are used, because the compiler may be able to optimise the instantiation into a factory. For example:

param = "float";
data = null;
{
    result = void;

    if param == "float"
        result = float;
    elsif param == "int"
        result = int;

    @data = result;
};

May be optimised into something like:

param = "float";
data = null;
{
    if param == "float"
        @data = float;
    elsif param == "int"
        @data = int;
};

This works because result can only be assigned once, so after its assignment it can be considered constant for the duration of the local scope.

@@X == const type; # X is statically typed
@@X == type;       # X is dynamically typed

Numeric Types

Numeric types use a series of bits to represent numbers.

int

int:N describes an integer of at least N bits. If no integral type of a suitable size is available on the system, int:N is a type error. If N is not specified, it defaults to 32. Integers can be qualified with a signedness using Signedness Specifiers and a serialisation endianness using Endianness Specifiers.

The following aliases exist for common int sizes:

@3 == const int;

char

char describes an integer of at that is treated as a character in strings and by locale settings. A character has an intrinsic encoding specified by an encoding string created using the encoding string operator $e(). The encoding determines the size of the character; if no encoding is specified, the encoding is "unspecified" ($e()) and the char is at least 8 bits. See Encoding Specifiers.

@"c"             == const char;
@($e(UTF-8) "c") == const $e(UTF-8) char;

bool

bool describes an integer of at least one bit that is treated as a Boolean value, restricted to the values true (1) and false (0).

@true  == const bool;
@false == const bool;

real

real:N describes an IEEE floating-point number of at least N bits that is treated as a real (non-imaginary) number. If N is not specified, it defaults to 32.

@3.14   == const real;
@314e-2 == const real;

imag

imag:N describes an IEEE floating-point number of at least N bits that is treated as though multiplied by the imaginary unit.

@2i == const imag;

Tuple Types

Tuple types represent multiple values.

tuple

tuple:T represents any number of values of type T. If @T is tuple:type, the tuple is heterogenous: this does not preclude static typing, as long as the elements of the tuple are themselves statically typed.

@(1, 2, 3)       == const tuple : const int
@(1.0, 2.0, 3.0) == const tuple : const real
@("a", "b", "c") == const tuple : const char
@("a", 2, 3.0)   == const tuple : (const char, const int, const real)

A tuple can be open or closed. If it is open, the the comma operator (,) can be used to add further elements to the tuple. A tuple is created open. When the tuple is wrapped in parentheses, it becomes closed, and further uses of the comma operator wrap the tuple in another tuple. To insert the contents of a tuple in another tuple, use the dereference operator (*) to reopen it:

first = (2, 3, 4);
second = (1, *first, 5);
second == (1, 2, 3, 4, 5);

pair

A pair:T is a tuple that contains two elements of type T. If T is pair:type or tuple:type, the pair is heterogeneous. As with tuples, this does not preclude static typing. A pair is created with the pair operator (=>).

@(3 => 5)     == const pair : const int;
@("a" => 3.0) == const pair : (const char => const real)
              == const pair : (const char, const real)

complex

A complex:N represents a complex number consisting of either a real:N portion and an imag:N portion (i.e., Cartesian form) or a real:N angle and a real:N magnitude (i.e., polar form). complex is the result of most operations between real or int and imag.

@(2 + 3i)     == const complex
@(2.0 + 3.0i) == const complex

Iterative Types

Iterative types are abstract types that only exist during the evaluation of an expression, and decay into another type once they are fully evaluated.

each

Operations on a sequence casted to an each are performed on each element of the underlying sequence. each S decays into the type of S.

L = (1, 2, 3);
M = 2 * each L;
M == (2, 4, 6);

N = each L + each M;
N == (3, 6, 9);

each N /= 3;
N == (1, 2, 3);

all

Operations on a sequence casted to an all are performed simultaneously on all of the elements of the underlying sequence. X op all S decays into the type of the result of performing op on X and an element of S.

L = (1, 2, 3, 4);
sum = 0 + all L;
sum == 10;

prod = 1 * all L;
prod == 24;

reverse

Casting a sequence to a reverse produces the reverse of that sequence. If the sequence is statically typed, the reverse expression is also. reverse S decays into the type of S.

L = (1, 2, 3);
R = reverse L;
R == (3, 2, 1);

Type Specifiers

Type specifiers are operators that alter types to produce related types.

Write Specifiers

Write specifiers determine whether a value can be modified, that is, whether it can appear as the destination of an assignment. If the type is const, it is immutable. To remove the const qualification, use mutable. Variables are mutable by default, but literals are const.

Access Specifiers

View specifiers determine whether a value can be accessed, according to the object that comprises it and the scope of the expression attempting to access it. public allows access from any scope, protected allows access from scopes in derived types, and private allows access only from scopes in the type itself.

static Specifier

The static specifiers explicitly requires an expression to be computed at compile-time, or raise a type error if this is not possible. static is especially useful in templates, where expressions such as static if can be used to make assertions that are guaranteed to be tested at compile-time, thus requiring that the template be passed static parameters.

Signedness Specifiers

Signedness specifiers (signed and unsigned) indicate whether int is treated as signed (two's-complement) or unsigned. int is equivalent to signed int.

Endianness Specifiers

Endiannness specifiers (little_endian, big_endian) indicate how to serialise and deserialise a value of a Numeric Type using a binary mode stream. They do not affect how the value is laid out in memory and do not affect runtime performance. These need to be used only in code that interacts with binary streams. The default byte order is specified by the system and can be obtained from locale.

Set Specifiers

Set specifiers determine containment semantics of set and map: multi allows a set to store duplicate elements or a map key to store multiple values, and unsorted makes either container unordered using a hash function rather than predicate ordering. sorted can be used to create a priority container. stack and queue create stack and queue adaptors that uses the given container as the underlying type.

Encoding Specifiers

Encoding specifiers determine the character encoding for a char. If no encoding is specified, char uses the default encoding according to the current locale. A character is meaningless without an associated encoding: without it, it would just be an int, and you already have int for that.

$e(encoding)
$enc(encoding)

Language Specifiers

Language specifiers determine the language for a string. If no language is specified, string uses language-neutral ($lang()) as the default; this can be changed using locale to specify a different default language. A string that represents human-readable text should always have an associated language; following this rule makes localisation with Prog a breeze. See Locale.

$lang(language)

Standard Library Types

Standard library types are "built-in" types that are implemented internally or as Prog templates in terms of the other types.

Core

string

A string:E is a string of characters of encoding E. If E is unspecified, it defaults to $e(), the default encoding according to locale. See Quoting Operators.

regex

A regex:E is a string of characters of encoding E that is treated as a regular expression.

$r(pattern)
$regex(pattern)

range

A range:T is a range between two values of type T that are comparable with the less-than operator (<). Ranges are created with the unary relational operators (<, >, <=, >=, ==, and !=) or the range operators (.., ...). ranges can be unioned, intersected, and differenced with the bitwise operators (|, &, ^).

Containers

vector

A vector:T is a vector of values of type T. If T is any, the vector is heterogeneous and dynamically typed.

deque

A deque:T is a double-ended queue of values of type T. If T is any, the deque is heterogeneous and dynamically typed.

series

A series:T is a singly-linked list of values of type T. If T is any, the series is heterogeneous and dynamically typed.

list

A list:T is a doubly-linked list of values of type T. If T is any, the list is heterogeneous and dynamically typed.

set

A set:T is a simple sorted unique associative container of values of type T. If T is any, the set is heterogeneous and dynamically typed.

map

A map:(K,V) is a sorted unique associative container mapping keys of type K to values of type V. If either K or V is unspecified, they default to any. If either K or V is any, the map is heterogeneous and dynamically typed.