Types

The types Antril has built in - integers and floating-point numbers of 8 to 256 bits, bool, characters, str and String<T>, any, arrays, nullable types, tuples, function types, pointers and references.

Last updated 10 min read Edit on GitHub

On this page

Every value in Antril has a type known when the program compiles. This page describes the types the language has built in. Types a program declares (classes, values, records, interfaces, enums) are in Declarations; generic types in Generics.

Type Kind
bool, the integers, the floats Primitive values
str, String<T> Text: a class
any The root of every class
void No value
T[], T[,], T[N] Arrays
T? Nullable types
(T1, T2, …) Tuples
func<…> : R, func*<…> : R Function types
T*, void* Pointers (unsafe code)
&T, &mut T References

Value types and reference types

A value type holds its value directly: assigning it or passing it copies it. The primitives, enums, tuples and the value and record value types a program declares are value types.

A reference type lives on the heap, and variables hold a reference to it: assigning a variable makes both refer to the same object. Classes, str, arrays and any are reference types.

A variable of a value type that is not assigned starts at zero. A variable of a reference type must be assigned before it is used, unless its type is nullable.

Primitive types

Type Size Values Library type
bool 1 byte true, false System.Boolean
i8 1 byte −128 … 127 System.Int8
i16 2 bytes −32 768 … 32 767 System.Int16
i32 4 bytes −2³¹ … 2³¹−1 System.Int32
i64 8 bytes −2⁶³ … 2⁶³−1 System.Int64
i128 16 bytes −2¹²⁷ … 2¹²⁷−1 System.Int128
i256 32 bytes −2²⁵⁵ … 2²⁵⁵−1 System.Int256
u8 1 byte 0 … 255 System.UInt8
u16 2 bytes 0 … 65 535 System.UInt16
u32 4 bytes 0 … 2³²−1 System.UInt32
u64 8 bytes 0 … 2⁶⁴−1 System.UInt64
u128 16 bytes 0 … 2¹²⁸−1 System.UInt128
u256 32 bytes 0 … 2²⁵⁶−1 System.UInt256
iptr, uptr a pointer (8 bytes on 64-bit targets) signed, unsigned (none: they have no library members)
f16 2 bytes IEEE half precision System.Float16
f32 4 bytes IEEE single precision System.Float32
f64 8 bytes IEEE double precision System.Float64
f128 16 bytes IEEE quadruple precision (34 digits) System.Float128
f256 32 bytes IEEE octuple precision (72 digits) System.Float256

Each primitive keyword names a value of the standard library, so the members of that type can be used through either name: Int32.MaxValue or i32.MaxValue, Int32.Parse("42"), x.ToString().

AntrilRun
import System;

Main()
{
	Console.WriteLine(i8.MinValue + " " + u16.MaxValue);
	Console.WriteLine(i256.MaxValue);
	f128 third = 1f128 / 3f128;
	Console.WriteLine(third);
	Console.WriteLine(Int32.Parse("41") + 1);
	Console.WriteLine(sizeof(u256));
}
Terminal
larva run
-128 65535
57896044618658097711785492504343953926634992332820282019728792003956564819967
0.3333333333333333333333333333333333
42
32
Members Of
MinValue, MaxValue (constants) every number type
Epsilon, NaN, PositiveInfinity, NegativeInfinity (constants) the floats
Zero, One (and NegativeOne for signed types) every number type, as static properties
Parse(text), ToString(), Hash(), Equals(other), CompareTo(other) every number type

Integer arithmetic wraps around on overflow (i32.MaxValue + 1 is i32.MinValue) unless it is in a checked block or expression, which throws OverflowError (see Statements). Integer division by zero stops the program with larva panic: division by zero and exit code 101.

Characters

Antril has no character type. A character literal such as 'A' is the number of its Unicode code point, of the integer type expected where it goes (u16 when none is). System.Char has functions on code points: Char.IsDigit('7'), Char.IsLetter(c), Char.ToUpper(c). See Lexical structure.

Text: str and String

str is System.String<u8>: immutable text in UTF-8. A string literal is a str.

String<T> is generic over the size of its code units, T : [u8, u16, u32]: String<u8> (UTF-8, which is str), String<u16> (UTF-16) and String<u32> (UTF-32). ToUtf16() gives the UTF-16 form of a str; String<u16> is how text crosses to C functions that take wide strings (see Interop).

A string's Length and indexes count code units, not characters. A loop over a string gives its units:

AntrilRun
import System;

Main()
{
	str word = "año";
	Console.WriteLine(word.Length);
	loop (u8 unit in word)
		Console.Write(unit + " ");
	Console.WriteLine();
	Console.WriteLine(word.ToUtf16().Length);
}
Terminal
larva run
4
97 195 177 111 
3

== compares strings by content, and + joins a string with another string, a number or any object (shown with its ToString()). The members of str (Substring, IndexOf, Split, Replace, Trim, ToUpper…) are listed in the standard library.

Warning

Not yet available: Console.WriteLine of a String<u16> does not print its text correctly. Convert it to str first.

any

any is System.Any, the root of every class: every object is an any, and any has ToString(), Equals(other), Hash() and GetType().

A value of a value type, a function or a pointer stored in an any is boxed: copied into an object. A cast gets it back, and is tests what it holds:

Antril
any boxed = 5;
i32 back = (i32)boxed;
if (boxed is i32 n)
	Console.WriteLine(n * 2);

void

void is the type of "no value". A function with no result type returns void; it cannot be the type of a variable, a field or a parameter. void* is an untyped pointer.

Arrays

Type What it is
T[] An array: a fixed number of elements, on the heap.
T[,], T[,,] … A rectangular array of 2 to 8 dimensions.
T[][] An array of arrays (each row its own length).
T[N] An inline array of N elements kept inside a value or class, as a fixed field (see Memory).
AntrilRun
import System;

Main()
{
	i32[] zeros = new i32[4];
	str?[] names = new str?[2];
	i32[] some = [1, 2, 3];
	i32[,] grid = new i32[2, 3];
	grid[1, 2] = 7;
	i32[][] rows = [[1, 2], [3]];
	Console.WriteLine(zeros.Length + " " + names.Length + " " + some[2]);
	Console.WriteLine(grid.Length + " " + grid.Rank + " " + grid.GetLength(1) + " " + grid[1, 2]);
	Console.WriteLine(rows[1].Length);
}
Terminal
larva run
4 2 3
6 2 3 7
1
  • Length is the number of elements; Rank the number of dimensions and GetLength(d) the length of one (from 0).
  • A new array starts zeroed, so its element type needs a zero value: numbers, bool, enums, values, or a nullable type. new str[3] is error AN2022; write new str?[3] or use a literal.
  • An array literal [a, b, c] takes its type from where it goes; a nested literal fills a rectangular array (i32[,] m = [[1, 2], [3, 4]];).
  • Indexes are checked: an index out of range stops the program with larva panic: index 3 out of bounds for length 1 and exit code 101.
  • Type suffixes read from left to right: i32[,][] is an array of rectangular arrays, i32[]? a nullable array.
  • An array is a reference type: assigning it shares it (see Memory).

Warning

Not yet available: a filler value for a new array, new str[3](""). Fill it with a loop, or use a List<T>.

Nullable types

A type without ? never holds null. T? can hold a T or null, for any type: str?, Person?, i32?, i32[]?.

AntrilRun
import System;

Main()
{
	str? name = null;
	Console.WriteLine(name ?? "nobody");
	Console.WriteLine(name?.Length ?? -1);

	i32? count = null;
	Console.WriteLine(count.HasValue);
	count = 7;
	Console.WriteLine(count.Value + 1);
	if (count is i32 n)
		Console.WriteLine(n * 2);
}
Terminal
larva run
nobody
-1
false
8
14
  • A member of a nullable value cannot be used until it is checked: name.Length is error AN2040. Test it with is, ?., ?? or a comparison with null.
  • A nullable value type has HasValue and Value; reading Value when there is none stops the program.
  • Operators of the underlying type do not apply to the nullable one: count + 1 with i32? count is error AN2078. Use count.Value or count ?? 0.
  • A T converts to T? by itself. The other way needs a check: x is T y, x ?? fallback, or x.Value.

Tuples

(T1, T2, …) is a tuple type of two or more elements: System.ValueTuple<T1, T2, …>. (a, b, …) makes one, and its elements are Item1, Item2…

Antril
(i32, str) pair = (1, "one");
pair.Item1 = 2;                      // the elements can change
(i64, f64) wide = (3, 4);            // each element takes the type it goes to
(str?, i32) maybe = (null, 1);       // null needs a type to go to

Tuples are records: == compares them element by element, they print as (1, one), and they work as dictionary keys. ToTuple() gives a System.Tuple<…>, a class whose elements cannot change. One to sixteen elements are declared in System.Core; larger tuples are made from a variadic template.

A tuple that holds objects, such as (i32, str), cannot be the type argument of a generic type (List<(i32, str)>). Tuples of numbers and plain values can: Dictionary<(i32, i32), str>.

Function types

func<A, B> : R is the type of a function value that takes an A and a B and returns an R. func : R takes nothing; without : R it returns nothing (func<str>, func). Lambdas, free functions, static methods and object.Method are function values. See Functions.

func*<A> : R is the address of a function with the C calling convention, for interop. Its parameters and result are numbers, bool, pointers and other func* (AN1057). See Interop.

Pointers

In unsafe code, T* is the address of a T: a number, an enum, a value without objects, or another pointer. void* is an address of anything. See Memory.

References

&T is a shared reference to a T and &mut T an exclusive one. They need the borrow checker (borrowcheck: warn or enforce). See Memory.

Static classes

A static class has no values: it cannot be the type of a variable, a field, a parameter, a result, an element, a type argument, a default(T) or a cast (AN1105). Use its members through its name: Console.WriteLine(…).

Was this page helpful?

No address is stored; your user name is, if you are signed in.

Esc