Type System Basics
Jiang types are read left to right, from the inner value outward. Each suffix wraps the type before it.
Primitive Types
Section titled “Primitive Types”Bool flag = true;Int count = -123;UInt size = 123;UInt8 byte = 255;Int16 small = -45;Float value = 12.3;Double precise = 132.54;Char ch = 'a';Int and UInt are pointer-sized integers. Use fixed-width types such as Int32 or UInt64 when ABI, file, or protocol layout needs an exact width.
() is the Unit type. It is a zero-size value and is also used for functions with no meaningful returned data.
String literals are UTF-8 byte sequences:
UInt8[_] bytes = "jiang";UInt8[] view = "jiang";Type Suffixes
Section titled “Type Suffixes”Suffixes farther to the right wrap a wider layer:
Int[2][3] matrix;Int?[2][3] nullable_items;Int?[2]?[3] nullable_rows;Common suffix forms:
| Syntax | Meaning |
|---|---|
T! | the current type layer is mutable |
T? | optional layer |
T^ | owning heap pointer |
T& | non-owning reference |
T* | single-object raw pointer |
T[] | slice reference |
T[*] | many raw pointer |
T[N] | fixed-size array |
T@E | errorable function return type |
Within one layer, ? must come before !: write Int?!, not Int!?, Int??, or Int!!.
Type Inference
Section titled “Type Inference”Use _ to infer the type from the initializer:
_ answer = 42;_ name = "Jiang";_ values = [1, 2, 3];Inference creates an immutable binding by default. Use _! for a mutable outer binding:
_! count = 0;count = count + 1;Inference preserves the expression’s natural type:
Int^ make_value();
_ owner = make_value(); // owner: Int^Int copied = make_value()$.get();Layered Mutability
Section titled “Layered Mutability”! applies to the current type layer:
Bool! flag = true;flag = false;
Int[3]! values = [1, 2, 3];values = [4, 5, 6];
Int![3]! mutable_items = [1, 2, 3];mutable_items[0] = 10;mutable_items = [4, 5, 6];For aggregate values, a member is writable only when that member’s own type is mutable.
struct User { Int id; Int! age;}
User user = User { id: 1, age: 18 }user.age = 19;// user.id = 2; // errorArrays and Slices
Section titled “Arrays and Slices”Array length is part of the type:
Int[3] values = [1, 2, 3];Int[_] inferred = [1, 2, 3];Nested arrays use repeated suffixes:
Int[2][3] matrix = [[1, 2], [3, 4], [5, 6]];T[] is a slice reference with runtime length:
Int[_] values = [1, 2, 3];Int[] view = values[..];Pointers and References
Section titled “Pointers and References”Int^ owner = new Int(42);Int value = owner$.get();owner$.free();T^, T&, and T* do not auto-dereference in ordinary value contexts. Use $.get() for explicit reads. Member access is the exception: owner.member can pass through T^:
Int value = 41;Int& ref = value$.ref();Int copied = ref$.get();
struct Box { Int value;}
Box^ box = new (Box { value: 42 });Int n = box.value;Optional
Section titled “Optional”T? means the value may be null:
Int? maybe = 42;Int? none = null;Use optional chaining, ??, or is some:
_ field = user?.name;Int value = maybe ?? 0;
if maybe is some payload { return payload;} else { return 0;}Errorable Returns
Section titled “Errorable Returns”T@E is used in function and method return position:
enum Err { bad = 1,}
Int@Err ok() { return 42;}
Int main() { return try ok() catch () => 0;}Use throw expr; to return the error side and try expr catch (...) => fallback to handle it.