Skip to content
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

Editorial: GetOption reform #493

Merged
merged 2 commits into from
Jan 12, 2021
Merged

Conversation

ptomato
Copy link
Contributor

@ptomato ptomato commented Aug 3, 2020

Discussion: #480

spec/datetimeformat.html Outdated Show resolved Hide resolved
1. Else,
1. If Type(_options_) is not Object,
1. Throw a *TypeError* exception.
1. Let _options_ be ObjectCreate(_options_).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'm kind of confused why ObjectCreate is/was used here - does the spec mutate the options object?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was trying to preserve the previous behaviour, so I don't know the answer to this; maybe because the subsequent Gets would otherwise be observable?

Copy link
Contributor

@gibson042 gibson042 Aug 5, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ToDateTimeOptions does indeed perform some writes, and the consequences are unnecessarily weird.

let observing = true;
const wrappers = new Set();
const options = new Proxy({}, {
  get(target, prop, receiver){
    if(observing) console.log("get:", prop, (
      receiver === options ?
        "@options" :
      Object.getPrototypeOf(receiver) === options ?
        "@wrapper" + [...wrappers.add(receiver)].indexOf(receiver) :
      receiver
    ));
    let val = target[prop];
    Reflect.defineProperty(target, prop, {
      enumerable: true,
      get(){ return val },
      set(v){
        if (observing) console.log("set:", prop, v, (
          this === options ?
            "@options" :
          Object.getPrototypeOf(this) === options ?
            "@wrapper" + [...wrappers.add(this)].indexOf(this) :
          this
        ));
        val = v;
        return true;
      }
    });
    return val;
  }
});

new Intl.DateTimeFormat(undefined, options);
/* =>
get: weekday @wrapper0
get: year @wrapper0
get: month @wrapper0
get: day @wrapper0
get: hour @wrapper0
get: minute @wrapper0
get: second @wrapper0
get: fractionalSecondDigits @wrapper0
get: localeMatcher @wrapper0
get: calendar @wrapper0
get: numberingSystem @wrapper0
get: hour12 @wrapper0
get: hourCycle @wrapper0
get: timeZone @wrapper0
get: dateStyle @wrapper0
get: timeStyle @wrapper0
get: weekday @wrapper0
get: era @wrapper0
get: hour @wrapper0
get: minute @wrapper0
get: second @wrapper0
get: timeZoneName @wrapper0
get: fractionalSecondDigits @wrapper0
get: formatMatcher @wrapper0
*/

observing = false;
[...wrappers].forEach((wrapper, i) => {
  console.log("wrapper" + i + ":", wrapper, Object.getPrototypeOf(wrapper));
});

// => wrapper0: {year: "numeric", month: "numeric", day: "numeric"} Proxy {…}

If we're making normative changes, I'd like to remove observable internal objects and multiple reads of the same properties.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In that case, shouldn’t the object be cloned before it’s written to, instead of making an inheriting object? (something that’s observable via proxies, and a very weird thing imo to have be observable)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Long-overdue issue: #706

@leobalter
Copy link
Member

I understand the goal for consistency, but I'm slightly concern about the potential breaking changes.

If a normative change is proposed where we limit a feature we've had before, I'd like to see Test262 reflecting these in details because we need to understand the possible outcomes for a potential breaking change. With these tests I can also ask implementers if they are good with the proposed change.

Probably the easiest outcome would be a different abstract for Temporal.

@ptomato
Copy link
Contributor Author

ptomato commented Aug 27, 2020

I've updated this with the suggestions in #480. It now does not change any observable behaviour.

If desired, subsequent normative changes could be made:

  • In InitializeCollator: change to GetOptionsObject.
  • In ToDateTimeOptions: get rid of the weird ObjectCreate(_options_) behaviour mentioned above, and use either CoerceOptionsToObject or GetOptionsObject. (This is now untouched in this PR.)
  • In the Intl.Locale constructor: change to GetOptionsObject.
  • In SupportedLocales: change to GetOptionsObject.
  • In InitializeNumberFormat: change to GetOptionsObject.
  • In InitializePluralRules: change to GetOptionsObject.
  • In InitializeRelativeTimeFormat: change to GetOptionsObject.

(Edit 2021-01-08: renamed abstract operations)

@@ -304,6 +301,36 @@ <h1>SupportedLocales ( _availableLocales_, _requestedLocales_, _options_ )</h1>
</emu-alg>
</emu-clause>

<emu-clause id="sec-normalizeoptionsobject" aoid="NormalizeOptionsObject">
<h1>NormalizeOptionsObject ( _options_ )</h1>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only in 262, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I put it in here initially as per #480 (comment)

spec/negotiation.html Outdated Show resolved Hide resolved
spec/numberformat.html Outdated Show resolved Hide resolved
spec/locale.html Outdated Show resolved Hide resolved
@sffc sffc changed the title GetOption reform Editorial: GetOption reform Oct 8, 2020
Copy link
Contributor

@gibson042 gibson042 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The changes look good, but I think some naming and descriptions could be a little better.

spec/negotiation.html Outdated Show resolved Hide resolved
spec/negotiation.html Outdated Show resolved Hide resolved
spec/negotiation.html Outdated Show resolved Hide resolved
spec/negotiation.html Outdated Show resolved Hide resolved
@leobalter
Copy link
Member

I'm in agreement with @gibson042's suggestions.

@ptomato please let me know if you're interesting in updating this. As those are minor edits, I can do it from here before merging.

Thanks!

@ptomato
Copy link
Contributor Author

ptomato commented Jan 5, 2021

Thanks for the reviews. I didn't get to update this before my vacation but I intend to do it sometime this week or next, if that timeline works for you.

@leobalter
Copy link
Member

No problem, my goal is to have those things done by January to get a good cut for the 2021 Edition.

ptomato and others added 2 commits January 8, 2021 10:54
In order to later be able to move GetOption into ECMA-262 in sync with
Temporal, we add GetOptionsObject and CoerceOptionsToObject as abstract
operations.

GetOptionsObject and GetOption are intended to be moved into ECMA-262 at
the same time, while CoerceOptionsToObject is intended to stay in
ECMA-402. CoerceOptionsToObject describes the somewhat unexpected boxing
behaviour when passing a primitive as the options parameter in a formatter
constructor. This behaviour may need to be preserved for web-compatibility
reasons, but new Intl objects going forward should use the
GetOptionsObject behaviour.
@ptomato
Copy link
Contributor Author

ptomato commented Jan 8, 2021

Updated.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants