The DAW port stores audio channels as plain lists. Clip rendering slices the trimmed sample range out of the source buffer on every cache miss (ab_slice in src/daw/audio_buf.eigs — a per-sample loop), and arr_move_track hand-rolls insert-at (ds_list_insert in src/core/util.eigs). Both are textbook C-loop shapes; in-language they dominate the profile for buffer-sized lists (a 10-second clip at 44.1 kHz is 441k elements per channel).
xs is [10, 20, 40]
list_insert_at of [xs, 2, 30] # xs is [10, 20, 30, 40]; returns xs
list_insert_at of [xs, 0, 5] # prepend
list_insert_at of [xs, len of xs, 99] # append (index == length is valid)
list_slice of [[1, 2, 3, 4, 5], 1, 4] # [2, 3, 4] — new list, [start, end)
list_slice of [[1, 2], 5, 9] # [] — clamped, never raises
Summary
The C-backed list mutation set has a gap on both sides:
list_remove_at of [list, i]exists; its duallist_insert_at of [list, i, v](shift tail up, insert ati) does not. Reordering anything (tracks in a DAW, items in any editor) is remove-at + insert-at; today the insert half is a hand-rolled append-and-shift loop at interpreter speed.copy_into of [dest, src, offset]copies into a list; there is nolist_slice of [list, start, end]to copy a range out. lib/list.eigs can compose it astake of [drop of [xs, start], end - start], but that's two full copies through the interpreter, anddropcopies the tail even when the slice is tiny.Motivation (consumer: InauguralSystems/DeslanStudios)
The DAW port stores audio channels as plain lists. Clip rendering slices the trimmed sample range out of the source buffer on every cache miss (
ab_sliceinsrc/daw/audio_buf.eigs— a per-sample loop), andarr_move_trackhand-rolls insert-at (ds_list_insertinsrc/core/util.eigs). Both are textbook C-loop shapes; in-language they dominate the profile for buffer-sized lists (a 10-second clip at 44.1 kHz is 441k elements per channel).What to add
Suggested contracts, following the neighbors' conventions:
list_insert_at: mutates and returns the list (likelist_remove_at); out-of-range index clamps to[0, len](or no-op likelist_remove_at— either, as long as it's documented).list_slice: returns a new list; indices clamp;start >= endgives[]; negative indices count from the end likeget_at/set_at(or are rejected — whichever matches the negative-index policy owners prefer).Definition of done
src/builtins.c+ rows in docs/BUILTINS.md → Lists.Environment
82ab2ae.