Skip to content

Pointer and Reference Types

Jiang has explicit syntax for owning heap pointers, non-owning references, raw pointers, many raw pointers, and slices. This page explains the type forms and basic operations. Resource movement and lifetime rules are covered in Ownership, Borrowing & Lifetimes.

  • T^: owning heap pointer.
  • T&: non-owning reference.
  • T*: single-object raw pointer for FFI / ABI / low-level code.
  • T[*]: many raw pointer, indexed by element.
  • T[]: slice reference with runtime length.

Only T^ expresses language-level ownership. Ownership transfer, automatic destruction, and lifetime constraints are covered separately.

Int value = 123;
Int^ owner = new Int(123);
Int[3]^ array_owner = new [1, 2, 3];
Int& ref = value$.ref();
Int* raw = value$.ptr();

The pointer suffix is attached to the type:

Int^ owner;
Int& ref;
Int* raw;
Int!^? maybe_owner;
Int?& maybe_ref;
Int^! owner_slot;

Within a layer, write ? before !.

T^ does not auto-dereference for assignment, initialization, or arithmetic value contexts. Use $.get() when you need the pointed-to value:

Int^ make_value();
Int^ owner = make_value();
_ inferred = make_value();
Int copied = make_value()$.get();
Int sum = make_value()$.get() + 1;

Member access is the exception: owner.member can pass through T^ to access the owned value’s member.

struct Box {
Int value;
}
Box^ box = new (Box { value: 42 });
Int n = box.value;

T& and T* use $.get() for explicit reads:

Int value = 41;
Int& ref = value$.ref();
Int copied = ref$.get();
Int* raw = value$.ptr();
Int raw_value = raw$.get();

Writing through a single-object raw pointer requires a mutable pointee:

Int! value = 0;
Int!* raw = value$.ptr();
raw$.set(42);

$ prevents receiver auto-dereference and enters the implicit operation layer. Operations such as $.get(), $.ref(), $.ptr(), $.move(), $.free(), and Type$.size() are covered separately: see Implicit Operation Layer.

T[*] is a raw pointer form for contiguous element access. It is indexed but has no length:

UInt8[*] bytes;
UInt8 first = bytes[0];
bytes[1] = 42;

Unlike C, T* is a single-object raw pointer and is not the type used for free pointer arithmetic. Use T[*] when code needs position-based access into contiguous memory. Use T[] for a length-bearing view.