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 
  } 
}