-
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
Options object consumption is observably different in internal branches #2855
Comments
It seems unfortunate to have even more copying of options object just to support the custom calendars use case. Do we really need to copy all properties instead of just creating a new object which has a single (This extra overhead makes me sad, especially when compared to other proposals which micro-optimise to avoid a dozen or so assembly instructions.) |
Copying the own properties is only necessary if we need to pass the same options object to more than one user hook, which might mess with the object. In other words, regard any options object as poisoned after it's been exposed to user code. I don't think we should copy the own properties if not necessary. Besides, this is not a change that I think we should even be considering at this point. Changes must be targeted at the goal of addressing implementations' concerns about making the proposal smaller and less complex, which this does not. |
I believe the options snapshotting (taking all properties where necessary to support user code reading arbitrary properties, but otherwise partial is fine) should be done at user code boundaries, and only there. Picking on the example above w.l.o.g., it doesn't make sense for Temporal.ZonedDateTime.from and ToTemporalZonedDateTime to both treat options as foreign. The former should either ingest options before branching on "clone" vs. "create from scratch" <h1>Temporal.ZonedDateTime.from ( _item_ [ , _options_ ] )</h1>
<p>
This function performs the following steps when called:
</p>
<emu-alg>
- 1. Set _options_ to ? GetOptionsObject(_options_).
+ 1. Set _options_ to ? SnapshotOwnProperties(! GetOptionsObject(_options_), *null*).
1. If _item_ is an Object and _item_ has an [[InitializedTemporalZonedDateTime]] internal slot, then ToTemporalZonedDateTime (
_item_: an ECMAScript language value,
- optional _options_: an Object,
+ optional _resolvedOptions_: an Object,
): either a normal completion containing a Temporal.ZonedDateTime, or a throw completion
</h1>
<dl class="header">
<dt>description</dt>
<dd>
It returns its argument _item_ if it is already a Temporal.ZonedDateTime instance, converts _item_ to a new Temporal.ZonedDateTime instance if possible, and throws otherwise.
</dd>
</dl>
<emu-alg>
- 1. If _options_ is not present, set _options_ to *undefined*.
- 1. Let _resolvedOptions_ be ? SnapshotOwnProperties(! GetOptionsObject(_options_), *null*).
+ 1. If _resolvedOptions_ is not present, set _resolvedOptions_ to ! GetOptionsObject(*undefined*).
+ 1. Assert: _resolvedOptions_ is an ordinary extensible Object that is not directly observable from ECMAScript code and for which the value of the [[Prototype]] internal slot is null and every property is a configurable data property.
1. Let _offsetBehaviour_ be ~option~.
1. Let _matchBehaviour_ be ~match-exactly~. or else should defer completely to ToTemporalZonedDateTime with a signal that creation is mandatory <h1>Temporal.ZonedDateTime.from ( _item_ [ , _options_ ] )</h1>
<p>
This function performs the following steps when called:
</p>
<emu-alg>
- 1. Set _options_ to ? GetOptionsObject(_options_).
- 1. If _item_ is an Object and _item_ has an [[InitializedTemporalZonedDateTime]] internal slot, then
- 1. NOTE: The following steps read options and perform independent validation in alphabetical order (ToTemporalDisambiguation reads *"disambiguation"*, ToTemporalOffset reads *"offset"*, and ToTemporalOverflow reads *"overflow"*).
- 1. Perform ? GetTemporalDisambiguationOption(_options_).
- 1. Perform ? GetTemporalOffsetOption(_options_, *"reject"*).
- 1. Perform ? GetTemporalOverflowOption(_options_).
- 1. Return ! CreateTemporalZonedDateTime(_item_.[[Nanoseconds]], _item_.[[TimeZone]], _item_.[[Calendar]]).
1. Return ? ToTemporalZonedDateTime(_item_, _options_).
</emu-alg> ToTemporalZonedDateTime (
_item_: an ECMAScript language value,
- optional _options_: an Object,
+ optional _creationOptions_: an Object,
): either a normal completion containing a Temporal.ZonedDateTime, or a throw completion
</h1>
<dl class="header">
<dt>description</dt>
<dd>
- It returns its argument _item_ if it is already a Temporal.ZonedDateTime instance, converts _item_ to a new Temporal.ZonedDateTime instance if possible, and throws otherwise.
+ It returns its argument _item_ if it is already a Temporal.ZonedDateTime instance and _creationOptions_ is not present, converts _item_ to a new Temporal.ZonedDateTime instance if possible, and throws otherwise.
</dd>
</dl>
<emu-alg>
- 1. If _options_ is not present, set _options_ to *undefined*.
- 1. Let _resolvedOptions_ be ? SnapshotOwnProperties(! GetOptionsObject(_options_), *null*).
+ 1. NOTE: These added steps could be abstracted into their own operation.
+ 1. If _creationOptions_ is not present or _creationOptions_ is *undefined*, then
+ 1. Let _resolvedOptions_ be ! GetOptionsObject(*undefined*).
+ 1. Else,
+ 1. Let _resolvedOptions_ be ? SnapshotOwnProperties(? GetOptionsObject(_creationOptions_), *null*).
1. Let _offsetBehaviour_ be ~option~.
1. Let _matchBehaviour_ be ~match-exactly~.
1. If _item_ is an Object, then
1. If _item_ has an [[InitializedTemporalZonedDateTime]] internal slot, then
- 1. Return _item_.
+ 1. If _creationOptions_ is not present, return _item_.
+ 1. Return ! CreateTemporalZonedDateTime(_item_.[[Nanoseconds]], _item_.[[TimeZone]], _item_.[[Calendar]]). |
Then what's the point of Temporal.ZonedDateTime.from reading
As seen above, it actually does—the second approach in particular would unify exposed |
Sorry, but I just don't agree with that. This kind of minor adjustment is not appropriate anymore at this point, even if it results in a bit of a weird inconsistency. We agreed to fix showstopper bugs only, which this is not. Luckily, this becomes moot if we remove custom calendars and time zones. We won't have to snapshot own properties of any options object at all, because none of them will be passed to user methods. |
I believe literally nobody is claiming that epochMicroseconds support is a showstopper, and yet #2849 is still under consideration. And unlike simple removals, this kind of bug has the potential to hinder future improvements.
This I agree with. |
Since we approved removing custom calendars and time zones in the TC39 plenary of 2024-06-12, I think we have agreed that this no longer applies. In my branch implementing that removal, I've removed all of the offending uses of SnapshotOwnProperties and just read the relevant properties eagerly when processing the function's argument. (@gibson042 when I post that PR and you review it, please do check that we agree on how it should be implemented.) I think we can close this now. |
I haven't checked how recent or how widespread this is, but the current spec text exposes internal branching by how it consumes an options object in at least Temporal.PlainDate.from, Temporal.PlainDateTime.from, Temporal.PlainYearMonth.from, Temporal.PlainMonthDay.from, and Temporal.ZonedDateTime.from, e.g.
All of these functions should SnapshotOwnProperties up front, passing down an unobservable clone to later steps and deeper operations.
The text was updated successfully, but these errors were encountered: