String Performance in Reef
Reef strings are immutable: every concatenation allocates a new string and copies all characters from both operands. This is fine for one-off operations, but becomes a performance trap when done repeatedly in a loop.
The O(n²) Concatenation Trap
Consider building a large string by appending lines in a loop:
// BAD — O(n²) time and memory
mut result: string = ""
mut i: int = 0
while i < line_count
result = result + lines[i] + "\n" // copies ALL of result every iteration
i = i + 1
end while
Each iteration copies the entire accumulated string plus the new line into a
fresh allocation. For n lines of average length k, total work is
proportional to n² * k, so building a very large string one piece at a time
quickly gets slow. Use one of the approaches below instead.
Recommended Alternatives
str.join() — Best for combining an array of strings
import core.str
let result = str.join(lines, "\n")
join() pre-calculates the total length, makes one allocation, and copies
each part exactly once — O(n) time and space.
Use str.join() when you already have all parts in an array (or can collect
them first).
text.stringbuilder — Best for incremental / conditional building
import text.stringbuilder as sb
let builder = sb.sb_new()
mut i: int = 0
while i < line_count
if should_include(lines[i])
sb.sb_append(builder, lines[i])
sb.sb_append(builder, "\n")
end if
i = i + 1
end while
let result = sb.sb_build(builder)
StringBuilder collects parts and joins them in a single pass at the end.
Use it when you need to build a string incrementally with conditional logic.
io.buffer — Best for writing large output to a file
import io.buffer
import core.result
let w = result.unwrap_ok(buffer.open_buffered_writer("/path/to/output.txt"))
mut i: int = 0
while i < line_count
buffer.writer_write_line(w, lines[i])
i = i + 1
end while
buffer.writer_close(w)
(open_buffered_writer returns Result[BufferedWriter, Error] — unwrap it to
get the handle used below; see
035_ERROR_HANDLING.md for the
general pattern.)
BufferedWriter maintains an 8 KB internal buffer and flushes to disk
automatically. If your goal is to write to a file (not build an in-memory
string), this avoids allocating the full result entirely.
io.stream — Low-level streaming writes
import io.stream
import core.result
let s = result.unwrap_ok(stream.stream_open_write("/path/to/output.txt"))
mut i: int = 0
while i < line_count
stream.stream_write(s, lines[i])
stream.stream_write(s, "\n")
i = i + 1
end while
stream.stream_close(s)
(stream_open_write also returns a Result — same unwrap pattern as above.)
io.stream writes directly to the file descriptor without buffering.
Prefer io.buffer for many small writes; use io.stream when you are
already writing large chunks.
Quick Reference
| Scenario | API | Module |
|---|---|---|
| Join an array of strings | str.join() |
core.str |
| Build a string with conditional logic | sb_new / sb_append / sb_build |
text.stringbuilder |
| Write many lines to a file | open_buffered_writer |
io.buffer |
| Stream large chunks to a file | stream_open_write |
io.stream |
| Concatenate 2–3 strings once | concat() or + |
core.str |
Rule of thumb: If you see result = result + something inside a loop,
replace it with one of the APIs above.