diff --git a/text/0000-add-skip-copy-option-to-tracked-collections.md b/text/0000-add-skip-copy-option-to-tracked-collections.md new file mode 100644 index 0000000000..21037d55f7 --- /dev/null +++ b/text/0000-add-skip-copy-option-to-tracked-collections.md @@ -0,0 +1,95 @@ +--- +stage: accepted +start-date: 2025-08-13T14:00:00.000Z +release-date: # In format YYYY-MM-DDT00:00:00.000Z +release-versions: +teams: + - framework +prs: + accepted: # Fill this in with the URL for the Proposal RFC PR +project-link: +suite: +--- + + + + + +# Add a `skipCopy` option to tracked-collections + +## Summary + +Add an option for all tracked-collections (like `trackedArray`, `trackedMap` and `trackedObject`) so that their constructors don't perform a copy of the passed-in collection. + +## Motivation + +That would allow users who know what they're doing to skip a potentially expensive copy of a big collection. + +## Detailed design + +The classes that implement the tracked-collections have an `options` argument. We can add an option to it to skip copying the collection argument that is passed. + +The naming is of course the biggest issue. One might argue that it's good to have "unsafe" in the name because that really is unsafe - if the original collection is modified and it is not copied - that change will not be reflected in the template which might be confusing for the user. On the other hand, this is somewhat "obvious" so naming it "unsafe" might prevent people from using it and therefore skipping on potential (big) performance gains. + +Example names: + +```ts +trackedArray(original, { copy: false }); +trackedArray(original, { copySource: false }); +trackedArray(original, { copyUpstream: false }); + +trackedArray(original, { avoidCopy: true }); +trackedArray(original, { skipCopy: true }); +trackedArray(original, { noCopy: true }); +``` + +There is a [PR](https://github.com/glimmerjs/glimmer-vm/pull/1767) in the Glimmer VM repo for an implementation in `trackedArray`. + +## How we teach this + +We add it to the documentation. And also to the TypeScript types (which is already done in the PR above). + +Example text for the documentation: + +By default, calling `trackedArray` (and any other tracked-collection constructor) copies the given argument. That is, the following code: + +```ts +let original = [123]; +let arr = trackedArray(original); +original[0]++; // `arr[0]` is *unchanged* +``` + +Will **not** modify the tracked array. + +That could be expensive when a big array is passed. For these cases, there is a second argument with options that can be passed to `trackedArray`: + +```ts +let original = [123]; +let arr = trackedArray(original, { skipCopy: true }); +``` + +Note that this could be dangerous! If the array is modified via its untracked reference (`original` in the example) - that change won't be handled by the tracking mechanism and templates won't redraw. + +## Drawbacks + +Potential confusion in people why their templates are not modified when the original collection is modified. + +## Alternatives + +I don't think there are. For the best performance, no copy should be made. + +## Unresolved questions + +None.