Skip to content

List.keep_if_try allocates once per kept item #12680

Open

Description

@Anton-4-bot

List.keep_if_try and List.keep_if_try! (src/build/roc/Builtin.roc) still build their result with List.concat($out, [item]):

keep_if_try = |list, predicate| {
	var $out = []
	for item in list {
		if predicate(item)? {
			$out = List.concat($out, [item])
		}
	}
	Ok($out)
}

Each kept item allocates a one-item list, and $out grows by reallocating. This is the same problem #12644 reported for List.keep_if, drop_if, keep_oks and keep_errs, which #12645 fixes.

Possible fix, following #12645:

  • Unique list: compact in place with list_swap_unsafe and finish with List.drop_last, as keep_if does. Stopping early on Err must still release the whole list correctly.
  • Shared list: copy the kept items into one List.with_capacity(len) buffer with list_append_unsafe, and return the input unchanged when every item is kept.

At minimum, replacing the concat with one List.with_capacity(list.len()) buffer and list_append_unsafe (as map_try does) would cut this to one allocation.

Issue authored by Claude Opus 5.5.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions