Copies & references
When a value is copied, shared, or cloned.
On this page
Memory is managed for you: objects are freed once nothing uses them. What you choose is whether a value is shared or copied.
Assignment shares objects#
Class values, including String, Array and HashMap, are references. Assigning one or passing it to a function shares the same object:
class Counter {
value: int (0)
}
fn bump(counter: Counter) {
counter.value++
}
fn main() {
let a = Counter{}
let b = a
b.value++
bump(a)
println(a.value) // 2
}
Assigning a new object to b only changes what b refers to; a is untouched.
Values are copied#
Structs, numbers, bool, enums and fixed arrays such as [int x 3] are copied on assignment:
fn main() {
let a: [int x 3] = { 1, 2, 3 }
let b = a
b[0] = 99
println(a[0]) // 1
println(b[0]) // 99
}
A copied struct field that holds an object still refers to the same object.
Copy or clone an object#
| Expression | Result |
|---|---|
copy x |
a new object with the same property values; objects inside are shared |
clone x |
a new object, and everything it refers to copied too |
class Team {
name: String
members: Array[String] (.{})
}
fn main() {
let a = Team { name: "red" }
let b = copy a
let c = clone a
b.members.append("Ada")
println(a.members.length) // 1
println(c.members.length) // 0
let list = Array[int]{ 1, 2 }
let other = copy list
other.append(3)
println(list.length) // 2
}
Collections define their own copy: copy list is a new list with the same items. See Classes to control how your own class is copied.
A range copies, a view shares#
x[start .. length] copies part of a collection. &x[start .. length] is a view of the same elements:
fn main() {
let scores = Array[int]{ 10, 20, 30 }
let part = scores[1 .. 2]
let view = &scores[1 .. 2]
part[0] = 1
view[0] = 99
println(scores[1]) // 99
}
A view keeps the storage it was made from. After the array grows, the two may no longer see each other's changes.
Close resources yourself#
Freeing memory is automatic, but files, sockets and connections should be closed when you are done. defer runs the close when the function returns:
use valk.fs
fn main() {
fs.write("example.txt", "hello") ! return
defer fs.delete_file("example.txt") ! {}
let file = fs.stream("example.txt") ! return
defer file.close() ! {}
let buffer: [u8 x 16] = { 0... }
let length = file.read(&buffer) ! return
println(length) // 5
}
Do not rely on an object being collected at a particular time. A class's gc_free() finalizer is only a fallback; see Classes.
Related#
- Borrows & access: read-only and writable views.
- Sharing data between threads: what changes when data crosses threads.
- Arenas & links and Unsafe code for manual control.

