The JSF TC39 Meeting Report — Nov 2016

The last TC39 Meeting was hosted by Facebook in Menlo Park, CA, USA. You can find the agenda here.

Before moving forward, I’d like to note that this report doesn’t follow the same order items are in the agenda or as items were discussed during the meeting. The order is subjective and reflects my personal highlights.

You can also find each meeting report is stored in the JSFoundation/Standards repo.

Diversity

We had a very important moment at this meeting. I have written about this in its own post that can be seen here: https://medium.com/@leobalter/how-can-we-promote-diversity-and-inclusion-in-tc39-61675326a731

Let’s talk about ES Modules and NodeJS again

We are finally moving forward to solve cross compatibility within ES Modules and Node’s CommonJS modules.

Dynamic Modules Reform

Caridy Patino is championing the — now on stage 1 — proposal for Dynamic Modules Reform. This proposal preserves the order of execution for dynamic modules. It is interesting that TC39 is going beyond ES modules and talking about this delicate compatibility when we might have both. In a near future we — developers —may use ES modules and be able to import not only other ES modules but those we already use with Node today.

The proposal itself is a great place for further reading.

Variation on Unambiguous JavaScript Grammar, or "use module"

As we discussed in the previous meetings, the Unambiguous JavaScript Grammar proposes a specific way to ensure module files are interpreted as modules. That’s an important issue when we need to solve crosscompability between Node CommonJS modules with ES modules.

This variation proposal from Dave Herman introduces a "use module" directive that can be used at the beginning of a file to let it be interpreted as a module, not a common script. It avoids leaking globals and preserves the module code is running on strict mode. There's also other concerns as evaluation time and order.

This variation eliminates the need for a module file that doesn’t import or export anything to include an empty export {} or import {} line. The best part is to know this string directive is only necessary on these cases. If you already have an import or export in your code, or even load it in your browser with a <script type="module">, you won't need the "use module" anymore.

One thing I really liked here is to know Dave Herman not only presented this proposal as an idea, but he implemented it on his own pet project, an experimental JavaScript parser written in Rust. A good way to tell something works is making it work, right?

Regardless how much I like this proposal, it found some resistance. It achieved Stage 1 for now, but there’s a long road ahead.

What changes from Stage 0 to 1?

Yehuda Katz published a great article about this first step up for a proposal. We can say it moved from an aspiration to experimentation on TC39.

import() is on stage 3

If you’re already involved with ES6, you might know of import and export for ES Modules. We are also about to experiment with import() in our browsers soon, even sooner than the regular ES Modules.

This proposal from Domenic Denicola aims to bring an async dynamic module loading syntactic form to JavaScript. The current ES Modules syntax are for static declarations, this basically means you can’t import something from a_variable_value. This example shows something I like from this new feature:

import(`./section-modules/${link.dataset.entryModule}.js`)
.then(...

As this finally reached stage 3, we can expect this feature to land in a browser soon. Implementing it was one of the motivations to step this proposal up.

Varius Oddities on Module Namespace Objects

Remove @@iterator

After this meeting we are finally removing the @@iterator property - a friendly visual form for Symbol.iterator - from Module Namespace objects. This issue might help with understanding the problems. As Domenic mentioned:

There is no other object in JS whose iterableness expresses a list of its keys.

Removing this feature will have iterations on Module Namespace object properties as it is today on regular JS objects.

non-configurable @@toStringTag

On the same way, the @@toStringTag property from Module Namespace objects are now non-configurable. This roughly means that you can't delete this property, but this is impossible anyway due to the nature of Module Namespace Objects.

[[SetPrototypeOf]] will return true if argument is null

Did you know that trying to set the prototype of a Module Namespace Object will always return false?

This is a bit of a deep change in the language, but you may be glad to know the internal [[SetPrototypeOf]] method of Module Namespace Objects will now return true if the argument is null. This behavior matches similar operations within other parts of the spec.

The best way to try it is using Reflect.setPrototypeOf.

Proposal rejected: include default export in export * from 'module'

Caridy Patino raised the question where export * from 'other_module' does not export the default exported value.

This syntax is a bit tricky, similar to the sentence above with several uses of export. The proposal aimed to export even the default anonymous export from another module.

Anyway, this feature is working as intended. If you really liked this idea, there are a few new ideas as in this issue where you can even find this nice workaround you may start using with the specs we have today:

export * from 'foo';
export { default } from 'foo';

You can go further and look at this new article from Dave Herman and Yehuda Katz.

Promise.try

Jordan Harband is trying his best to move his new proposal forward. He even tried to move it to Stage 2, but it advanced to Stage 1 for now.

As explained, a Promise.try(fn) would be a short path for new Promise(resolve => resolve(fn())) wrapping an instantly created Promise and starting a chain of then calls, differently than Promise.resolve.then().

Being on Stage 1, it’s an important moment to give feedback on this proposal. If your own experience with Promises says it’s a good new API or not, I’m sure Jordan will be very welcoming to your feedback.

More Promises

Promise.resolve

We had some discussion on Promise.resolve and its constructor check. To better understand, let's take a look at the spec:

25.4.4.5 Promise.resolve( x )
1. Let C be the this value.
2. If Type(C) is not Object, throw a TypeError exception.
3. If IsPromise(x) is true, then
a. Let xConstructor be ? Get(x, "constructor").
b. If SameValue(xConstructor, C) is true, return x.
...

Roughly saying, it means Promise.resolve returns x if x is already a Promise from the same constructor, checking if x.constructor is the this value. This allows checking for subclassing on Promise, but there's also a discussion where this might be a bad practice and if we want to keep it this way.

Before TC39 got to a consensus, even to define where we want Promise subclassing or not, the timebox we had available for this item expired. Hopefully this will be back in the next meeting and it’s a good moment for us to provide more feedback.

Promise#finally

Finally we discussed about moving Promise.prototype.finally to Stage 3, but this remained on Stage 2 for now.

This proposal adds a new api that is similar to jQuery’s deferred.always.

The central concern is regarding whether .finally() should call out an observable .then() as .catch() does.

Once again, subclassing became part of the game, along with the question if we want to pursue a brand checking mechanism, or if we should kill Promise subclassing or not.

RegExp

We’ve got some interesting proposals advancing related to RegExp.

the s (dotAll) flag on Stage 1

This proposal originally from Mathias Bynens and presented by Brian Terlson moved up to Stage 1.

It allows you to add an s flag in order to make dots (.) in your regexp match line terminator characters.

/foo.bar/.test('foo\nbar'); // false
/foo.bar/s.test('foo\nbar'); // true

Considering the current workaround for this is /foo[^]bar/.test('foo\nbar');, I'm looking forward to see this proposal jumping to Stage 4. This is hopefully achieving stage 4 in the next year.

lookBehind assertions on Stage 2

This is a proposal that jumped from 0 to 2 in the last meeting. This might be confusing, but it’s interesting to check the acceptance criteria for the stage 2 in the stage process document:

The committee expects the feature to be developed and eventually included in the standard

It also has at least a draft spec, which is the case of this proposal.

If you’re still wondering what is a lookBehind assertion, they are meant to ensure that the pattern contained within precedes the pattern following the assertion. lookBehind can be found in positive (?<=...) and negative (?<!...) forms.

In order to understand it better, the proposal — championed by Daniel Ehrenberg — has more details. You can also find a short version of it in the slides.

NaN Revisited

Do you know NaN is represented by a few specific values from IEEE754–2008? Those are bit representations for NaN, and there are more than one representation. Browsers use different representations and most of the time, more than one internally.

After ES6, with TypedArrays, these values became observable, mostly from the internal method SetValueInBuffer. Lets check this part:

If value is NaN, rawValue may be set to any implementation chosen IEEE 754–2008 binary32 format Not-a-Number encoding. An implementation must always choose the same encoding for each implementation distinguishable NaN value.

This means an implementation should keep those values consistent if they are assigned to a buffer. If an implementation uses many distinguishable NaN values, it should keep it the same way.

With the consensus, NaN values may not be kept anymore. That means they can be scrambled on SetValueInBuffer and their bit encodings might not be consistently observable anymore.

You can find way more information on this issue and these slides from Daniel Ehrenberg.

SharedArrayBuffer to Stage 3

Shu-Yu Guo gave a flawless presentation for the current state of SharedArrayBuffer.

This is a feature we might have landing for ES2017.

It deserves an entire article to explain it and how it works, for now it’s better to leave this MDN page here.

In a rough short version, this feature is great to improve memory usage with Buffers and multiple environment layers, i.e. Web Workers.

Private State to Stage 2

Private State, championed by Daniel Ehrenberg, is now on Stage 2. It is a nice addition to classes, but it is still in need of feedback before it moves on to Stage 3.

There a few things we’ll try but they can change in the process: they are gonna be hard private for now. Also, there is a pending discussion on the equals (=) operator but this discussion is gonna be decided along the public fields proposal. At least, the committee decided not to prefix private states with private.

There’s also an interesting new research for it: uses of static private and private methods to be investigated.

64bit Int to Stage 1

Brendan Eich advanced his proposal for 64bit Integers using the Int64 and Uint64 forms to stage 1. It was about time.

This will introduce a new numeric type represented by integers in the 64bit range. There’s a ongoing discussion to add them with the following syntactic forms:

Int64(0) === 0L
Uint64(0) === 0UL

It’s time for feedback and research for this feature.

Conclusion

I can say this meeting was one of my favorites, mostly because we are finally addressing our issue on diversity and inclusion and I hope we can go forward working on it.

It was also a good one for modules and promises, and even other small but not less important features as the Intl.Segmenter moving to Stage 2 and consensus to tweak ArrayIterator for detached TypedArrays.

I’m still looking forward to see Public Fields and Object properties rest and spread in the next meetings. Those are features I’m seeing everyday on WebApps and it’s gonna be great to have them as stable features.

What is your most anticipated feature?