Sage’s type system is built on structural type equality, meaning that two types are equal if they have the same structure. This allows for more flexible type definitions, and makes it easier to work with complex data structures.
Primitive Types#
The following are the primitive types in Sage:
Int: an integer, the word size of the target architecture. If you’re compiling to a 64-bit target,Intis 64 bits.Cell: a raw word-sized value, used for reinterpreting memory. To reinterpret aFloatas anInt, you can cast it to aCellfirst:5.0 as Cell as Int.Float: a floating point number, the word size of the target architecture. This is adoublefor 64-bit targets.Bool: a boolean value, eitherTrueorFalse.Char: a word-sized character.[T * N]: an array ofNelements of typeT.&T: an immutable pointer to a value of typeT.&mut T: a mutable pointer to a value of typeT.fun(T1, T2, ..., Tn) -> T: a function that takes arguments of typesT1,T2, …,Tnand returns a value of typeT.
Pointers#
To get a pointer of a value, you can use the & operator. To get a mutable pointer, you can use the &mut operator.
let a = 5;
let p: &Int = &a;
let mut b = 6;
let p2 = &mut b;
println(*p);
*p2 = 1000;
println(*p2);
5
1000
If you take a mutable reference of an immutable value, the compiler will throw an error.
let a = 5;
let p: &mut Int = &mut a;
2 │ let p: &mut Int = &mut a;LIR error: invalid refer expression &mut a
Algebraic Data Types#
Sage supports algebraic data types, which are a way of defining complex data structures. These types are defined using the type, struct, and enum keywords, and can be parameterized with other types.
Structs#
Structs are a way of defining a collection of named fields. They are defined using the struct keyword.
struct Point {
x: Int,
y: Int,
}
let p: Point = { x=5, y=6 };
println(p);
{x=5, y=6}
Enums#
Enums are a way of defining a type that can be one of several variants. They are defined using the enum keyword.
enum Option<T> {
Some(T),
Nothing,
}
let o = Option<Int> of Some(5);
match o {
of Some(val) => println("there is a value: ", val),
of Nothing => println("there is no value")
}
there is a value: 5
Type Aliases#
Type aliases are a way of defining a new name for an existing type. They are defined using the type keyword.
type Point = { x: Int, y: Int };
let p: Point = { x=5, y=6 };
println(p);
{x=5, y=6}
Type Parameters#
Types can be parameterized with other types. This allows for more flexible type definitions.
type Pair<T, U> = { first: T, second: U };
let p: Pair<Int, Char> = { first=5, second='a' };
println(p);
{first=5, second=‘a’}
Const-Generics#
Sage supports const-generics, which are a way of defining types that are parameterized by constants.
struct Matrix<Elem, const Rows: Int, const Cols: Int> {
data: [[Elem * Cols] * Rows],
}
let m: Matrix<Int, 2, 2> = { data=[[1, 2], [3, 4]] };
println(m);
{data=[[1, 2], [3, 4]]}