XO0908: an element counted up and down each iteration
Reported by xo vet --cost, which builds the program and reads what the compiler did. A named function that only reads a parameter borrows it, so passing it a list element costs nothing. A function value (a closure, a fn parameter) borrows its arguments too (decision 0337), except one whose type is the function’s result type (or one of a tuple result’s: an accumulator, a var closure’s value), which it takes so the body can update it in place: each element passed there is counted up before the call and down after, atomically when the collection is shared across threads. Call a named function that only reads the element, return another type, or hoist the call out of the loop. The prelude’s map, filter, find, any, all, and fold hand every element to their function value the same way, so xs.map(fn(u: User) -> User { ... }) over elements holding heap memory is noted at the call, and xs.any(fn(u) { u.name == n }) is not; a for loop over the list borrows its elements (decision 0186).
Example
fn total(xs: List[Str], f: fn(Str) -> Str) -> Int {
var t = 0
for x in xs {
t += f(x).len()
}
t
}Fix
fn width(s: Str) -> Int {
s.len()
}
fn total(xs: List[Str]) -> Int {
var t = 0
for x in xs {
t += width(x)
}
t
}Run xo explain XO0908 for this text in a terminal, or see
section 10.6 of the specification.