DriftScript
Documentation

Rationale

Why records have no methods

The decision that makes hot reload possible, and what it takes away.

Why do records have no methods?

Because a method is a function whose identity is bound to the value it hangs off, and replacing one means finding every value. Hot reload is the feature this language exists for, so the thing that would make it hard was removed rather than worked around.

How the replacement works instead

A caller holds a module and reaches functions through it, so swapping one is a single assignment into a record every caller already reads through, and nothing has to be found. The cost is one property lookup per call, which is why a per-frame caller may hoist the function out of its loop, and why doing so is a choice rather than something the runtime forces: hoisting is exactly what breaks reload for that call site.

// A value the page keeps, and a function the page replaces while it keeps it.
//
// `ticks` counts how many times `advance` has run since the page loaded. Edit the body below and
// the count carries on from where it was: the code is replaced, the state it was working on is
// not. That is what hot reload means here, and it is the reason records have no methods.

data Pulse {
    ticks: u32 = 0
    value: f32 = 0
}

fn advance(pulse: mut Pulse, dt: f32) {
    pulse.ticks = pulse.ticks +| 1
    pulse.value = pulse.value + dt
}
Edit the body. The count does not restart.

The second thing it buys

Behaviour outside the record is what lets the compiler tell a read from a write, because the write goes through a parameter that had to be declared mut. A method mutating its own receiver would make that analysis a special case on the first day.

What it costs

Discoverability. There is no autocomplete after a dot that tells you what a Door can do, and finding the functions that take one is a search rather than a keystroke. That is a real loss for somebody learning an unfamiliar codebase, and the language server closes only part of it.