Soul & Identity

Toka's Hat Principle introduces a strict, clear distinction between a pointer's Handle (its syntactic container) and its Soul (its underlying data). Mastering this separation is essential to understanding Toka's memory management model.


Handle vs. Soul

Every pointer identifier in Toka possesses two distinct aspects in syntax and memory:

  • Handle (The Hat): An identifier prefixed with its pointer sigil (^p, *p, ~p). It represents the physical pointer container in memory—the slot holding the target memory address.
  • Soul (The Data): An identifier written without its sigil (p). It represents the underlying data/resource being pointed to.
fn handle_soul_example() {
    auto ^p# = new Point(x=10, y=20)
    p.x = 30
    auto sum = p.x + p.y
    println("sum: {}", sum)
}

In the example above, ^p# is the mutable unique handle, while p.x directly accesses the field of the underlying Point soul.


Ergonomic Implicit Dereferencing

Toka completely eliminates the visual clutter of traditional dereferencing operators (such as C's *p / p-> or Rust's *p).

Whenever you need to read, write, or access fields of the data behind a pointer, you simply operate directly on its Soul (the identifier without its sigil). The Toka compiler automatically resolves this to a dereference operation under the hood with zero runtime overhead:

fn implicit_deref_example() {
    unsafe {
        auto *p# = alloc i32
        p = 100
        auto val = p
        println("val: {}", val)
    }
}

This implicit dereferencing brings a clean, script-like syntax to high-performance systems programming, drastically increasing code readability.


Identity: The Address-Of Operator *expr

To retrieve the raw, physical memory address of a local variable or resource, Toka provides the unary *expr syntax. This returns a raw pointer *T pointing to the variable's location:

fn address_of_example() {
    auto a# = 42
    auto *raw_ptr = *a
    println("addr: {}", raw_ptr)
}

[!NOTE] The Hat sigil (like ^ or ~) does not mean "address of". Sigils are strictly type specifiers for pointer handles, whereas *expr is the runtime operator to extract a memory address.


References and the Borrow Pointer &

A Borrow Pointer (&) is a reference that allows safe, temporary, and compiler-checked access to a Soul without taking ownership of it.

Clean Local Variable Borrowing

When borrowing a standard, non-member local variable, no parentheses are needed. Simply prefix the soul with & to create a borrow pointer:

auto x = 42
auto &y = &x // y is a borrow pointer pointing directly to the soul of x

The Member Access Chain Borrow Ambiguity

When attempting to borrow a specific field within a struct or shape (a member access chain), writing &pt.x is syntactically ambiguous. It is unclear whether you want to borrow the entire member chain &(pt.x) or access the member x on a borrowed pointer (&pt).x.

To ensure clarity and type safety, the Toka compiler rejects &pt.x with a compile error and requires one of two clear and legal options:

  1. Option A (Standard Parentheses): Explicitly wrap the member chain in parentheses: &(pt.x).
  2. Option B (Hat-Terminal Morphology): Place the & borrow sigil directly before the terminal field name: pt.&x.

pt.&x is an intuitive form, allowing the borrow operation to integrate directly into the member access chain.

fn borrow_example() {
    auto x = 42
    auto &y = &x // Clean local variable borrow, no parentheses needed!
    
    auto pt = Point(x = 10, y = 20)
    
    // Member borrow Path A: standard parentheses
    auto &rx1 = &(pt.x)
    
    // Member borrow Path B: Hat-Terminal Morphology (Toka's signature aesthetic)
    auto &rx2 = pt.&x
    
    println("y: {}, rx1: {}, rx2: {}", y, rx1, rx2)
}