proc main(): void {
mut Str[dyn] a = ["x", "y"]
b := a // a copy, as far as anyone can tell
append(a, "z")
echo b // ["x", "y"]
}proc main(): void {
mut Str[dyn] a = ["x", "y"]
mut Str[dyn] b = a // one storage, two names
append(b, "z")
echo a // ["x", "y", "z"]
b = ["replaced"] // rebinds b alone
echo a // still the three
}proc grow(vec: mut Str[dyn], tag: Str): void {
append(vec, tag)
}
proc main(): void {
mut Str[dyn] tags = ["bee"]
grow(tags, "hive")
echo tags // ["bee", "hive"]
}Every value in Hive behaves as a value. Binding a vector, a table, a map or a record to a second name never lets a write through one show up in the other — the compiler copies wherever it has to, deeply, and skips the copy only where it can prove nobody could tell. The exception is asked for: when both names are mut, mut b = a shares the storage, so writing through either reaches both, append included. Rebinding one of them, b = […], gives that name storage of its own and leaves the other holding what they shared. A scalar — a number, a Str, or a record of nothing but scalars — has no storage to share, so two mut names for one are simply two values.
A parameter is a copy the callee cannot change, unless it is declared name: mut T. That is the one place storage crosses a call on purpose: the callee writes through the caller's own variable, so the argument has to be a mut variable or a path into one, like grow(tags) or grow(box.items). Only a proc may declare one, which is the next slide.
A call started on a thread of its own with async is handed a copy of every argument instead, made before the thread starts, so the two sides never write the same storage.