ECMAScript 6: TC39 meetings, March–November 2013

[2014-01-17] esnext, tc39, dev, javascript
(Ad, please don’t block)
TC39 [1] is the committe that currently plans ECMAScript 6 (code-named ECMAScript.next), the next version of the JavaScript language standard. In this blog post, I’m summarizing the highlights of several meetings that they had in 2013, in March, May, July, September and November. Previous blog posts summarized prior meetings.

This post is made possible by Rick Waldron’s excellent notes of the meetings.

March

  • Adobe joins TC39 (announcement).
  • Iterator protocol: TC39 decided on an iteration protocol for ECMAScript 6, which is described in [2].
  • new Date(dateObj) creates a clone of dateObj.
  • Two new array methods proposed by Rick Waldron:
    • Array.prototype.find(predicate, thisArg?)
    • Array.prototype.findIndex(predicate, thisArg?)

May

(All highlights subsumed by more recent explanations below.)

July

  • Maps can optionally be initialized via an iterable [2] of [key,value] pairs.
  • Two new array methods that help WebGL:
  • The maximum length of arrays has been expanded to 253−1.
  • Support for safe integers [3] via
  • Number.prototype.clz() counts the leading zero bits of an unsigned 32 bit integer [4]. Useful, e.g., for audio decoding.
  • Calling constructors as functions (omitting new) is deprecated. If a constructor creates new instances even if it is called as a function then that can break subclassing, if sub-constructors can’t use it for setting up instance properties (longer explanation: [5]). Therefore: classes throw when called as functions, as do the built-in constructors Map, Set, WeakMap, WeakSet. Note that the call() method still works, as it is needed for subclassing.
  • Value objects: An ECMAScript edition after ECMAScript 6 will probably enable user-defined “value objects”, which are compared by value (comparing the contents, as is done for primitives) and not by reference (comparing identities, as is done for objects). That means that we will effectively be able to create new primitive types, including custom literals and dynamically dispatched polymorphic operators. Possibly even more important than that is that JavaScript will come with several built-in value object constructors. A few candidates:
    • int64 (literals: 123L) for usigned 64 bit integers
    • float32 (literals: 1.23f) for 32 bit floating point numbers
    • int32x4 for SIMD [6]
    • bignum (literals: 1.23n) for arbitrary precision floating point numbers
    Details: “JS Responsibilities” (slide 5+) by Brendan Eich.

September

  • @@unscopables: This special property allows one to hide own properties from the with statement. This mechanism became necessary, because old code with with statements broke when TC39 tried to add methods to Array.prototype. So see why this happened, look at the following code:
        function f(arr) {
            var values = []; (1)
            with (arr) {
                ...
                values.push(...); // (2)
                ...
            }
        }
    
    If you add a method values to Array.prototype then the above code breaks, because values in line (2) does not refer to values in line (1), anymore. Hence, all new array methods are hidden from with in ECMAScript 6, via:
        Array.prototype[Symbol.unscopables] = [
            'find', 'findIndex',
            'fill', 'copyWithin',
            'entries', 'keys', 'values'
        ];
    
  • Math.fround() converts a 64 bit double to a 32 bit float and enables floats in asm.js [7].
  • Line terminators in template strings: CR, LF, and CRLF are normalized to LF, which should help with cross-platform code.
  • Tail call optimization: is something that most functional languages do; the last function call in a function whose return value isn’t used is executed as a jump. That means that many kinds of recursion don’t grow the stack anymore and become viable ways of implementing loops. ECMAScript 6 will perform tail call optimization, but only in strict mode (which doesn’t have func.arguments).
  • Symbols: are a new type for unique IDs in ECMAScript 6. Characteristics:
    • A new primitive type with the usual wrapper objects.
    • typeof mysym === 'symbol'
    • Symbol() creates a symbol, new Symbol() throws an exception (to avoid confusion).
    • Implicit conversion to string throws an exception. Rationale: you want to use symbols as unique property keys and implicit conversion to string would be a major source of bugs.
    • new Symbol() throws an exception. That prevents people from accidentally using wrapper objects (which have no use other than as a provider of methods).
    • You can retrieve the symbols that are keys of own properties via Object.getOwnPropertySymbols(). Object.getOwnPropertyNames() only returns string-valued property keys.
    • Object.assign() [8] copies all enumerable own properties, independently of whether their keys are symbols or strings.
    • A cross-realm registry for symbols means that they can be used across all frames etc. of an engine (see November meeting for details).
    Originally, there were plans for providing private properties via symbols, but those plans were canceled, at least for ECMAScript 6. That is, properties whose keys are symbols are always public.
  • The current specification process has several problems:
    • Large editions drive the schedule. That means that once it has been decided that an edition comprises a given set of features then mature features may be unnecessarily delayed in order for other features to be finished. On the other hand, less mature features are under pressure to finalize.
    • Informal process for accepting features. Acceptance of a feature for an edition occurs before details are sorted out and there is no formal way of tracking the maturity of a feature. That makes scheduling unpredictable.
    • The burden of spec writing is on the editor of an edition (a constrained resource).
    Solution:
    • Release a revision every two years. That is, the schedule is now driven by dates instead of by editions.
    • The formal stage of maturity (explained below) at a cut-off date determines whether or not a feature is included in an edition.
    • The maturity stages of a feature are:
      • Proposal: describe problem and solution
      • Working Draft: detailed solution, initial spec
      • Candidate Draft: must be validated by implementations
      • Last Call Draft: final spec (written by the designer of a feature)
    More information: “TC-39 Process Proposal” by Rafael Weinstein and Dmitry Lomov.
  • Destructuring: does not throw an exception if an expected property is missing, but still throws if a sub-pattern does not match.
        { foo: { bar: x } } = { }; // exception
        { foo: x }          = { }; // x = undefined
        { foo: x = 123 }    = { }; // x = 123
    
  • Promises: will be part of ECMAScript 6. They are already used in several browser APIs. Three examples: ServiceWorker, Streams and Web MIDI.
  • Object.observe(): Work on this feature is ongoing, it will probably be part of ECMAScript 7 (which will be released much more quickly than ECMAScript 6).
  • Data parallelism (originally River Trail, now ParallelJS [9]): Ongoing work, making steady progress.

November

  • ES6 status: Cut from ES6 are
    • refutable matching. Matching is mostly irrefutable (does not throw an exception if a property is missing), as demonstrated above.
    • binary data
    • regular expression lookbehind
    • Object.mixin() (Object.assign [8] is in)
    Will be in ES6: promises, tail call optimization.
  • Cross-realm registry for symbols: A “meta-global” registry will allow symbols to cross realms. That means that you can use a symbol from the current frame to retrieve a property value of an object from a different frame. The registry API looks as follows.
    • sym = Symbol.for(keyStr) returns a symbol from the registry if an entry for keyStr already exists, creates a new symbol and adds it to the registry if there is no such entry.
    • keyStr = Symbol.keyFor(aSymbol) returns the key under which a symbol is registered. Useful for tasks such as serialization.
  • Function.prototype.toMethod(homeObject, methodName?)
    transfers a method to a different object. This functionality is necessary because with super-references [10], a method is tied relatively closely to the object that owns it (its home object). A method’s home object is stored in a property of that method. Therefore, toMethod creates a new function object whose internal property [[Code]] has the same value as in this, but whose properties [[HomeObject]] and, possibly, [[MethodName]] have different values.
  • Custom comparators for Map keys and Set elements have been deferred. They determine what keys or elements are considered equal and have been deferred, because ensuring that they are efficient enough is difficult.
  • Modules are mostly done now, consult [11] for details.

References

  1. A JavaScript glossary: ECMAScript, TC39, etc.
  2. Iterators and generators in ECMAScript 6
  3. Safe integers in JavaScript
  4. Integers and shift operators in JavaScript
  5. Subclassing builtins in ECMAScript 6
  6. JavaScript gains support for SIMD
  7. asm.js: closing the gap between JavaScript and native
  8. ECMAScript 6: merging objects via Object.assign()
  9. ParallelJS: data parallelism for JavaScript
  10. A closer look at super-references in JavaScript and ECMAScript 6
  11. ECMAScript 6 modules: the future is now