-
Notifications
You must be signed in to change notification settings - Fork 156
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Normative: Always use CopyDataProperties for object copy/merge #2245
Normative: Always use CopyDataProperties for object copy/merge #2245
Conversation
Codecov Report
@@ Coverage Diff @@
## main #2245 +/- ##
==========================================
- Coverage 94.75% 94.69% -0.07%
==========================================
Files 20 20
Lines 10991 11056 +65
Branches 1962 1965 +3
==========================================
+ Hits 10415 10469 +54
- Misses 531 542 +11
Partials 45 45
Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here. |
63180c3
to
c7993f1
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the thorough work, no bugs found in any case! However, I'm lukewarm on this normative change, personally... I'm certainly not opposed to it but I'm wondering if there is a particular motivation we can give to the plenary when we present it? I get the appeal of reusing CopyDataProperties, but I don't get supporting symbol keys on an object for which Temporal never cares about any symbol keys; maybe I'm missing something. (For example, I think this way is just as likely to lead to implementation divergence if implementations are using built-in JS, because the temptation to use the now-incorrect spread syntax seems likely.)
The editorial changes are all fine in my opinion. Would you mind splitting them out into a separate PR, so that the PR we present in July can be as small as possible? I can merge the editorial PR if you like, or you can hereby consider it already reviewed.
@@ -83,6 +83,7 @@ | |||
"full-icu": "^1.4.0", | |||
"nyc": "^15.1.0", | |||
"rollup": "^2.68.0", | |||
"rollup-plugin-node-polyfills": "^0.2.1", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the plugin needed for? Does CopyDataProperties depend on it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think call-bind was breaking without it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oof, does rollup break things just like webpack 5, by not automatically polyfilling node builtins?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, that seems about right. You should be able to observe the problem if you checkout this PR, remove the rollup-plugin-node-polyfills dependency, and run npm install && npm run build
(maybe followed by npm test && npm run test262
; I don't remember if the issue manifested at build time).
polyfill/lib/ecmascript.mjs
Outdated
}); | ||
|
||
var enumerable = $isEnumerable(from, nextKey) || ( | ||
// this is to handle string keys being non-enumerable in older engines |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not overly concerned about handling this case in the online playground... we already require that the browser supports WeakMap, for example. I feel we can leave this support to other polyfills more intended for that use case in production.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, but it was copied from es-abstract/2020/CopyDataProperties.js and is unrelated to the CopyDataProperties changes being introduced. I've opened tc39/ecma262#2796 with the hopes of making this override unnecessary.
Done: #2295 (please review and/or merge because I can't do so unilaterally).
The main goal is maximum consistency in how object-copy works, within ECMA-262 and especially within Temporal. I prefer using the existing CopyDataProperties operation to avoid further debate, but if there's strong opposition then I would be willing to compromise on excluding symbol-keyed properties—however, it's worth noting that object spread and rest include them1 and that custom calendars and/or time zones might benefit from their preservation just as they benefit from preservation of string-keyed properties that are not used by any built-in operation. Footnotes
|
da0596e
to
7690d06
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, let's plan to present this in July, then. I'll mark it as draft awaiting that.
I think it will need another rebase though.
7690d06
to
41296b6
Compare
Done. Also, I am concerned about cases in which options-object properties are read multiple times, which happens when CopyDataProperties is preceded by GetDifferenceSettings (as in Difference operations) and in AddDurationToOrSubtractDurationFromPlainYearMonth (where the original object is sent to CalendarDateAdd but a null-object copy is sent to CalendarYearMonthFromFields). But I'm not sure how to address that, since Get can look into the prototype chain while CopyDataProperties does not (making the difference observable when a relevant property exists but not on the object itself). |
…erties This is normative because the latter includes Symbol-keyed properties while the former does not.
This tests some of the normative changes in tc39/proposal-temporal#2245, which achieved consensus in the July 2022 TC39 meeting, specifically as they apply to places where the MergeLargestUnitOperation was called. Due to the use of the pre-existing spec operation CopyDataProperties, the order of observable property operations has changed from a batch of [[GetOwnProperty]] followed by a batch of [[Get]], to a series of interleaved [[GetOwnProperty]]/[[Get]] pairs. This previously wasn't tested because TemporalHelpers.propertyBagObserver didn't track [[GetOwnProperty]] operations, but now it does.
This tests the normative changes in tc39/proposal-temporal#2245, which achieved consensus in the July 2022 TC39 meeting, specifically as they apply to the Temporal.Calendar.prototype.mergeFields method. Due to the use of the pre-existing spec operation CopyDataProperties, now symbol keys are merged into the return value, and the order of observable property operations has changed from a batch of [[GetOwnProperty]] followed by a batch of [[Get]], to a series of interleaved [[GetOwnProperty]]/[[Get]] pairs.
41296b6
to
8657e06
Compare
8657e06
to
229adc6
Compare
This tests some of the normative changes in tc39/proposal-temporal#2245, which achieved consensus in the July 2022 TC39 meeting, specifically as they apply to places where the MergeLargestUnitOperation was called. Due to the use of the pre-existing spec operation CopyDataProperties, the order of observable property operations has changed from a batch of [[GetOwnProperty]] followed by a batch of [[Get]], to a series of interleaved [[GetOwnProperty]]/[[Get]] pairs. This previously wasn't tested because TemporalHelpers.propertyBagObserver didn't track [[GetOwnProperty]] operations, but now it does.
This tests the normative changes in tc39/proposal-temporal#2245, which achieved consensus in the July 2022 TC39 meeting, specifically as they apply to the Temporal.Calendar.prototype.mergeFields method. Due to the use of the pre-existing spec operation CopyDataProperties, now symbol keys are merged into the return value, and the order of observable property operations has changed from a batch of [[GetOwnProperty]] followed by a batch of [[Get]], to a series of interleaved [[GetOwnProperty]]/[[Get]] pairs.
I've rebased this and written tests for it, which are in tc39/test262#3691. Since it reached consensus at the July 2022 TC39 meeting and doesn't invalidate any current tests, I'm going to go ahead and merge it now. |
This tests some of the normative changes in tc39/proposal-temporal#2245, which achieved consensus in the July 2022 TC39 meeting, specifically as they apply to places where the MergeLargestUnitOperation was called. Due to the use of the pre-existing spec operation CopyDataProperties, the order of observable property operations has changed from a batch of [[GetOwnProperty]] followed by a batch of [[Get]], to a series of interleaved [[GetOwnProperty]]/[[Get]] pairs. This previously wasn't tested because TemporalHelpers.propertyBagObserver didn't track [[GetOwnProperty]] operations, but now it does.
This tests the normative changes in tc39/proposal-temporal#2245, which achieved consensus in the July 2022 TC39 meeting, specifically as they apply to the Temporal.Calendar.prototype.mergeFields method. Due to the use of the pre-existing spec operation CopyDataProperties, now symbol keys are merged into the return value, and the order of observable property operations has changed from a batch of [[GetOwnProperty]] followed by a batch of [[Get]], to a series of interleaved [[GetOwnProperty]]/[[Get]] pairs.
This tests some of the normative changes in tc39/proposal-temporal#2245, which achieved consensus in the July 2022 TC39 meeting, specifically as they apply to places where the MergeLargestUnitOperation was called. Due to the use of the pre-existing spec operation CopyDataProperties, the order of observable property operations has changed from a batch of [[GetOwnProperty]] followed by a batch of [[Get]], to a series of interleaved [[GetOwnProperty]]/[[Get]] pairs. This previously wasn't tested because TemporalHelpers.propertyBagObserver didn't track [[GetOwnProperty]] operations, but now it does.
This tests the normative changes in tc39/proposal-temporal#2245, which achieved consensus in the July 2022 TC39 meeting, specifically as they apply to the Temporal.Calendar.prototype.mergeFields method. Due to the use of the pre-existing spec operation CopyDataProperties, now symbol keys are merged into the return value, and the order of observable property operations has changed from a batch of [[GetOwnProperty]] followed by a batch of [[Get]], to a series of interleaved [[GetOwnProperty]]/[[Get]] pairs.
This tests some of the normative changes in tc39/proposal-temporal#2245, which achieved consensus in the July 2022 TC39 meeting, specifically as they apply to places where the MergeLargestUnitOperation was called. Due to the use of the pre-existing spec operation CopyDataProperties, the order of observable property operations has changed from a batch of [[GetOwnProperty]] followed by a batch of [[Get]], to a series of interleaved [[GetOwnProperty]]/[[Get]] pairs. This previously wasn't tested because TemporalHelpers.propertyBagObserver didn't track [[GetOwnProperty]] operations, but now it does.
This tests the normative changes in tc39/proposal-temporal#2245, which achieved consensus in the July 2022 TC39 meeting, specifically as they apply to the Temporal.Calendar.prototype.mergeFields method. Due to the use of the pre-existing spec operation CopyDataProperties, now symbol keys are merged into the return value, and the order of observable property operations has changed from a batch of [[GetOwnProperty]] followed by a batch of [[Get]], to a series of interleaved [[GetOwnProperty]]/[[Get]] pairs.
<rant> Remember to clean up and/or squash commits before merging! There's several extra commits in this PR that ideally wouldn't have been in main. Other than the inherent value of keeping the repo tidy, this PR contains commits that make a change and revert the change later in the same PR. Porting these commits has been painful. :-(
</rant> |
The first three commits are editorial cleanup, while the rest include technically normative changes (albeit minor).
This stemmed from the surprising observation that AddDurationToOrSubtractDurationFromPlainYearMonth uses
key+value
enumeration to clone options, while MergeLargestUnitOption and ECMA-402 Temporal.Calendar.prototype.mergeFields and DefaultMergeFields usekey
enumeration followed by a for-each loop that Gets each source property in analogous copy/merge steps (and DefaultMergeFields in particular has further out-of-order steps related to overriding "month" and "monthCode" properties). The difference between the two is observable by ECMAScript code.This seems unnecessarily convoluted and confusing, and very likely to result in unintentional implementation divergence. It would be simpler and more comprehensible to always read all properties and all values from source objects in any copy/merge operation, which is what this PR proposes. But because that order is observable (
key
enumeration followed by the for-each Get calls is a sequence of [[GetOwnProperty]]s followed by a sequence of [[Get]]s, whilekey+value
enumeration is a sequence of [[GetOwnProperty]] + [[Get]] pairs) and so is inclusion of Symbol-valued keys, the change is normative, even though it will not affect expected normal code. That is also true even of the slightly more substantial changes in DefaultMergeFields, and actually improves the behavior AFAICT—Temporal.Calendar.from("iso8601").mergeFields({year: 2022, month: 5, day: 31}, {year: undefined, month: undefined, day: undefined})
will now produce{year: 2022, month: 5, day: 31}
rather than{year: 2022, day: 31}
(which is missing "month" because per the current algorithm its undefined value in additionalFields suppresses copy from there, while its mere presence suppresses copy from fields).