proposal-record-tuple
proposal-record-tuple copied to clipboard
Expand support for R&T across the existing methods that accepts objects and arrays
I didn't add support for:
Reflect.*, since they already disallow primitives even if it would make sense to use them (e.g.Reflect.get("str", 0)).- Proxy handler (
new Proxy(target, #{})), since it's meant to contain functions so a record would only work as an empty handler. - ~~
JSON.stringify's replacer array, just to avoid conflicts with https://github.com/tc39/proposal-record-tuple/pull/257: I'll do it in a separate PR in the future~~ EDIT: done. There are also a bunch of bugs in the current JSON implementation, where we pass R/T to AOs that expects objects.
Closes #107
This PR should be reviewed commit-by-commit. Most algorithms in the misc-updates.html file are copied from the existing spec (except for InitializeTypedArrayFromTuple and UnwrapIteratorResult): focus on the <ins> and <del> tags.
Do you think that these should be valid?
new Map([ #{ 0: "x", 1: "y", length: 2 } ]);
new Map([ #{ 0: "x", 1: "y", length: 1 } ]);
fn.apply(thisArg, #{ 0: "x", 1: "y", length: 2 });
Do you think that these should be valid?
new Map([ #{ 0: "x", 1: "y", length: 2 } ]); new Map([ #{ 0: "x", 1: "y", length: 1 } ]); fn.apply(thisArg, #{ 0: "x", 1: "y", length: 2 });
AddEntriesFromIterable doesn't currently require a length so I'm not sure a check should be added now.
Since we're adding support for tuple, and these already support array like objects, why not add array like records support as well?
Most places only accept an arraylike, or only an iterable; Array.from is one of the only ones that accepts both. new Map only accepts an iterable - being arraylike is irrelevant. Map and Set should not accept Records, since they're not iterables.
AddEntriesFromIterable only cares about the entries of the iterable being an object with a 0 and 1 property.
d. If Type(nextItem) is not Object, then
i. Let error be ThrowCompletion(a newly created TypeError object).
ii. Return ? IteratorClose(iteratorRecord, error).
e. Let k be Get(nextItem, "0").
f. IfAbruptCloseIterator(k, iteratorRecord).
g. Let v be Get(nextItem, "1").
h. IfAbruptCloseIterator(v, iteratorRecord).
@mhofman ah, i see what you mean. yes, that's true, it seems reasonable for either Tuples or Records to be the entry objects in Map/Set/Object.fromEntries.
In case we want to do it as part of this PR. We could also expand RelationalExpression prop in val to also accept Records and Tuples. Right now non-objects throw a type error.
This could be useful in TypeScript where in is a common pattern for 'type-guards'.
in should definitely work on primitives that are conceptual containers.
I don't think IsConcatSpreadable should treat tuples as arrays. IsConcatSpreadable is a hook for things that are much more array-like, such as NodeLists in HTML.
IsConcatSpreadableis a hook for things that are much more array-like
Isn't tuple array-like?
It is 100% arraylike; i fail to see why it wouldn’t qualify.
I don't think
IsConcatSpreadableshould treat tuples as arrays.IsConcatSpreadableis a hook for things that are much more array-like, such as NodeLists in HTML.
Hi @michaelficarra , would you be able to expand on this? What would your expectation be for the following:
let a = ['a1', 'a2'];
let b = #['b1', 'b2'];
a.concat(a); // ['a1', 'a2', 'a1', 'a2'];
a.concat(b); // ?
b.concat(a); // ?
b.concat(b); // ?
It is 100% arraylike; i fail to see why it wouldn’t qualify.
Yes array-like in that it has a numeric length and numeric indices, but not meeting the bar for concat. Notice that general array-likes like { length: 0 } and arguments objects do not get spread by concat.
What would your expectation be for the following:
let a = ['a1', 'a2'];
let b = #['b1', 'b2'];
a.concat(a); // ['a1', 'a2', 'a1', 'a2']
a.concat(b); // ['a1', 'a2', #['b1', 'b2']]
b.concat(a); // whatever you like
b.concat(b); // #['b1', 'b2', 'b1', 'b2'];
I agree that concat doesn’t spread all arraylikes - but Tuple is far closer to an array than most arraylikes, as a conceptual and iterable List, with list operations on its prototype.
I agree that concat doesn’t spread all arraylikes
This is far too weak of a statement. It spreads no array-likes. It is meant to only spread arrays. For historical HTML integration reasons, we had to add the isConcatSpreadable hook, but concat spreading should never be expanded further.
Yes, it only spreads Arrays and NodeLists, but Tuples are also built-in list-like collections. Why wouldn’t we want to expand it further? Array concat’s flattening behavior is immensely idiomatic and useful.
Array concat’s flattening behavior is immensely idiomatic and useful.
I'd argue that concat spreading is more-often-than-not a footgun. This is why the usage pattern of a.concat([b]) came to be: fear that b may be spread.
That’s also why a.concat(b) is so common - the hope that if a list, it will be spread, and if not, not. Because spreading syntax also spreads strings, prior to flat existing, concat was the only way to do this, and as such it’s quite common to do so.
There are other places where we are treating Tuples more like Arrays than 'array-like'. Namely Array.prototype.flat and JSON.stringify. A general design philosophy of Tuples is to think of them like Arrays, rather than Array likes, this can be seen in their literal syntax sharing the [ ] style and Tuple.prototype being a subset of Array.prototype.
Additionally, Tuple has concat, which uses IsConcatSpreadable. #[a].concat(#[b]) is and must be #[a, b], and thus, [a].concat([#b]) must be [a, b] for consistency (and because that's the only thing that makes sense).
@ljharb Nothing requires Tuple's concat to use IsConcatSpreadable.
I think user expectations do. We added a bunch of methods to Array just so Arrays and Tuples would be consistent. If arrays can spread Arrays and NodeLists, Tuples must be able to as well, but the same logic.
If arrays can spread Arrays and NodeLists, Tuples must be able to as well, but the same logic.
Ehhh.... NodeLists contain non-primitives pretty much by definition. I am entirely OK with Tuple.prototype.concat rejecting empty NodeLists in addition to non-empty NodeLists (which it must anyway).