module References {
// REFERENCE TYPE BASICS
// By default, all types are non-reference, meaning they are allocated on the stack
// or embedded directly into other data structures.
// A type can be annotated with ref, which makes it a reference type. A reference
// is stored as a pointer to the value instead of the value. Even though the type
// is referenced using a pointer, this detail does not affect the syntax, e.g. there are no
// special syntax to interact with the type - it's the same as if it was not a reference.
// a non reference type (the default)
struct Point {
x : int;
y : int;
}
struct Circle {
origin: Point; // Point is embedded since it's not a reference type
radius : int;
}
fn test1() {
let p = Point(1, 2); // Point is on the stack
let c = Circle(Point(1, 2), 3) // Circle and it's embedded point are on the stack
}
// a reference type (indicated with ref)
ref struct Line {
pt1 : Point; // Point is embedded since it's not a reference type
pt2 : Point;
}
// When a type is marked as a reference type, it MAY be allocated on the heap, it may
// be allocated on the stack, or it may point to constant data - it's up to the compiler
// to decide.
fn test2() {
// line may be stack allocated or heap allocated
let line = Line(Point(1, 2), Point(3, 4));
}
// The choice about heap or stack allocating will depend, among other things, on whether
// any code aliases the value. Also there is a definable threshold for how large of
// reference objects will be allocated on the stack.
// THERE IS NO `NULL`
// Although reference types are pointers, there is no null value as in other languages.
// Use Optional values for the case where the value may not be present. The none value
// is used to signal the absence of a value.
// define a linked list node
ref struct Node {
value : int;
next : Node?; // next is marked optional using ?
}
// a method that searches for a node given a value
Node.find_node(head : Node?, value : int) : Node? => {
if (head == none) {
return none;
}
if (head!.value == value) {
return head;
}
return Node.find_node(head!.next)
}
fn test3() {
let head = Node(1, Node(2, Node(3)));
let found = Node.find_node(head, 3); // look up node
}
}