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,Int
is 64 bits.Cell
: a raw word-sized value, used for reinterpreting memory. To reinterpret aFloat
as anInt
, you can cast it to aCell
first:5.0 as Cell as Int
.Float
: a floating point number, the word size of the target architecture. This is adouble
for 64-bit targets.Bool
: a boolean value, eitherTrue
orFalse
.Char
: a word-sized character.[T * N]
: an array ofN
elements 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
, …,Tn
and 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]]}