Values copy. Pointers share. Exactly one owner disposes. The floor traps misuse.
Mica has no lifetimes and no & references. Ownership and aliasing are answered
independently, which is what lets the common case go unannotated.
Defaults follow data flow
The rule fits in one sentence: returns give ownership, parameters borrow it.
| Position | Data flow | Default | Marked exception |
|---|---|---|---|
| Parameter | in | borrows | owning pointer T |
| Return value | out | owns | alias pointer T |
| Field or element | rests | owns | alias pointer T |
| Local variable | rests | owns, flow-tracked | — |
Each default is the overwhelmingly common intent for that position, so an annotation appears only where the intent is genuinely unusual — and there it carries real information rather than satisfying the compiler.
This is not an idiosyncratic choice. Languages that lack a lifetime calculus — C++, Swift, Ada, Pascal — are unanimous on it: borrow-default parameters, explicit transfer. Mica takes the same position deliberately.
The borrow default has one consequence worth stating for dynamic arrays: the
address of an element is a lend, never a binding. Inc(address a[i]) and
every hand-to-a-call use stay exactly as they read, but storing that address —
view := address a[i] — is refused, and so is lending it to the one call that
cannot survive it: a callee that grows the same array. A dynamic array’s
backing moves when it grows; a stored pointer would keep naming memory the
array has left behind, and writes through it would stop meeting writes through
the element while both answers still look plausible.
Values are values
A variable holds a value. Assignment produces an independent value; passing an argument produces an independent value. There is no reference type that silently turns one name into two, and no need to know a type’s secret aliasing behaviour to read a line of code.
When you want sharing you write a pointer, and that intent is visible where the declaration is.
The two costs usually attributed to value semantics do not materialise. Passing
a large value to a procedure that only reads it, or updates it in place, is
zero-copy — the parameter borrows through a pointer, the way const& became the
C++ idiom and var parameters were always the Pascal one. Results are
constructed directly in their destination rather than copied into it, so
multiplying two matrices or accumulating a vector runs without incidental
copies.