Brian Terlson (BT), Dmitry Lomov (DL), Waldemar Horwat (WH), Allen Wirfs-Brock (AWB), John Neumann (JN), Rick Waldron (RW), Eric Ferraiuolo (EF), Jafar Husain (JH), Jeff Morrison (JM), Mark Honenberg (MH), Caridy Patiño (CP), Sebastian Markbåge (SM), István Sebestyén (IS), Erik Arvidsson (EA), Brendan Eich (BE), Mark S. Miller (MM), Sam Tobin-Hochstadt (STH), Domenic Denicola (DD), Peter Jensen (PJ), John McCutchan (JMC), Paul Leathers (PL), Eric Toth (ET), Abhijith Chatra (AC), Jaswanth Sreeram (JS), Yehuda Katz (YK), Dave Herman (DH), Brendan Eich (BE),
(Allen Wirfs-Brock)
https://github.com/rwaldron/tc39-notes/blob/master/es6/2014-07/ecma-262-6-optout1.pdf
AWB: This is the opt-out period: Aug. 11, 2014 - Oct. 11, 2014
Final opt-out window: March 16, 2015 - May 18, 2015
Read the policy, speak with István Sebestyén for further information.
The opt-out version of the spec is: ECMA-262 6th Edition, revision 26, document: tc39/2014/031
(Mark Miller, Allen Wirfs-Brock, Dmitry Lomov, Tom Van Cutsem. Based on Claude Pache proposal )
https://github.com/rwaldron/tc39-notes/blob/master/es6/2014-07/instantiation-reform.pdf
AWB: Currently:
new Foo(arg)
Foo[[Construct]](arg)
::=let obj = Foo[@@create]()
foo.call(obj, arg)
The actual constructor method typically does all of the initialization and setup on the instance object.
Issues:
(DOM centric)
DH: Do we have concrete examples of this problem?
JM: Dealing with legacy code where you want to subclass from legacy constructors, need to set up state, this
uninitialized
AWB: Gives Date
example, where [[DateValue]]
isn't setup until super()
DH: The initialization of the internal field cannot happen until the super constructor is called to create that field.
YK: This is caused by the @@create not accepting the constructor arguments.
AWB: Yes. Propose: Remove @@create, replace it with @@new, which will make the arguments available to
YK: When you subclass, it's normal to call super and pass the arguments.
AWB: @@create is a property of the constructor, not the instance.
Creating a subclass, you may want to do something with the arguments before passing to super
JM: or adjust some state on the subclass instance before calling super
AWB: There is a complication that built-ins have: different behaviour when new
'ed or call
'ed
No internal distinguishing mechanism. No way to indicate that a constructor was called or newed.
YK: Don't think we need to be concerned with handling
AWB: A subclass will create a "call" up to the super
Explanation of current spec handling.
JM: Issues: were we called, or newed. One deals with intermediary state initialization.
AWB: The issue is coupling between state and the instance. Do we agree that there's a problem?
(no one says no)
JM: There are scenarios where a subclass wants to initialize state before calling super()
YK: It seems like a feature, not a bug
WH: What are you calling the intermediary state
YK: The fact that you can observe the creation There has to be brand check
DH: The simplest way of saying is that all need brand checks.
YK: Can do: foo.call(any)
and there is obviously a check there.
AWB: Internal slots are initialized in an atomic unit,
YK:
DL: TypedArrays missing creation information
AWB: You can move all the logic [to @@create or @@new or something akin], but you've just created another constructor
WH: Why not do everything from @@create in the constructor
DL/AWB: Jason Orendorff's proposal.
DH: (not-quite-right summary of Jason's proposal)
AWB: One way: reify [[Construct]] to the user
DH: When new Foo(args)
, calls Foo[@@new](args)
... ?
DL: Just pass the args to @@create
and change @@create
to @@new
NM: But then the subtype must have same signature
AWB: 2 viable options for ES6
Bring back to constructor with atomic invocation. I'm for this approach and it's reasonable for ES6
(Mark presenting...)
MM:
Goals
Subclass exotics Avoid un (or partially) initialized exotics
ES5 compat (aside from "rcvr") ES6 class compat (aside from @@create) Reliable test for "am i called as a constructor?" Support base-creates-proxy scenario
class Derived extends Base {
constructor() {
// TDZ this, on "new Derived..." etc.
super(...otherArgs); // this = what super returns
// this is initialized.
}
}
//
function Base(...otherArgs) {
// implicit this = Object.create(mostDerived.prototype, {});
}
AWB: The super()
call is calling the super class constructor as a constructor when new Derived()
—that's important.
WH: When constructor() is called as a function, super is called as a function too?
MM: Yes
WH: What causes the TDZ to appear? The statically visible presence of a super call in the body of the constructor?
AWB: Yes
WH: What if the super call is inside an arrow function?
BE: If Derived
called without new
?
AWB: super()
is called a non-constructor.
WH: super cannot appear in a nested function?
AWB: they can appear, but... (trails off)
JM: A related use case is being able to set up stuff on the instance before calling super()
AWB: Show me code that does that, to make sure we don't break that.
BE: code that doesn't actually use super() won't break, and there is no such code yet
MM: Base is an example of a function that doesn't have a super call (because it can't). On entry, before user code, implicit init this of fresh newly created object. This is a difference from ES5. The "mostDerived" prototype ...?
AWB: this actually isn't a difference from ES5, because there is no super() in ES5
MM: you are correct
MM: how do people feel?
JM: It's not an issue with ES5 -> ES6 legacy, it's an issue with ES6 class designs that evolve over time
YK: my concern is the pedagogy of this approach.
MM: the pedagogy is as shown in this slide.
DH: No! It cannot be taught this way.
BE: let's just let Mark present.
MM:
From Claude Pache
F.[[Construct]](args, rcvr)
**Modifications to Claude's proposal **
F.[[Construct]](args, rcvr)
super()
, but not super.foo()
YK: What about subclass constructors that don't include a call to super()
.
AWB: Throw when new
'ed
Agreement.
JM: I still have issues with state initialization
YK: Issues
BE: Concern about setting properties on the instance before super()
JM: Code patterns exist, they won't just go away.
AWB: Can get around it with super.constructor()
BE: Lose the static analysis of super(
(right paren intentionall omitted)
MM:
[[Call]] Traps
F(...args) -> F.[[Call]](undefined, args)
Derive.[[Call]](const this, args)
super(...other) -> super.special_name(...other)
WH: What is the special name?
MM/AWB/DD: (to Waldemar) This is the ES6 spec
WH: Explain?
AWB: methods that ref super are bound to an object where the super ref takes place. that binding is the current inst. two bound values object where look up starts and the method name.
MM:
[[Construct]] Traps
new F(...args) -> F.[[Construct]](args, F)
Base.[[Construct]](rcvr, args)
entry -> const this = [[Create]](rcvr.prototype)
Derive.[[Construct]](args, rcvr)
entry -> TDZ this
super(...other) -> const this = super.[[Construct]](other, rcvr)
Remaining Requirements
Am I called as a constructor?
What is the original's constructor's prototype?
How do I provide alternate instance to the subclasses?
Am I called as a constructor?
function F(...other) {
let constructing = false;
try { this; } catch(_) { constructing = true; }
super(..);
}
Base instantiates proxy scenario
function Base(...other) {
return new Proxy(... this.prototype ...);
}
Kill two birds with "new"
function Date() {
let now = $$GetSystemTime();
if (new*) {
let obj = Object.create(new*.prototype);
// obj@now = now; // private "now" state
return obj;
} else {
return ToTimeString(now);
}
}
MM: Proposing a new special form (shown as new*
above) whose value is the most derived otherwise undefined.
The test being: reliably check if I am called as a constructor.
WH: Unless the most derived receiver is falsy. Is there a way to create such a thing?
AWB: Yes, you can invoke the reflection trap and specify a falsy value for the receiver.
MM: Modified the above example to:
if (new* !== void 0) ...
AWB: We could fix this by throwing if reflection is used to invoke a constructor with undefined as the receiver.
Reflection and Proxies
Reflect.construct(F, args, rcvr)
(throw on undefined)construct: function(target, args, rcvr)
YK: How does this work in ES5 classes?
AWB:
YK: Is conditional super a hazard?
MM: Yeah
AWB: New power, new complexity
YK: Exposing something that was implicit into the main path. Calling super in a constructor conditionally?
EA: Bug, can be fixed
AWB: (re: Date example) Where it shows Object.create...
DL/AWB: If you conditionally forgot to call super()
, [[Construct]] will have to check at exit and throw.
YK: With @@create you had to know what you were doing. With this you could tread on weird cases without knowing it.
BE: Lets park that discussion for now.
DL: The sign that TypedArray is giving us is a sign of what user code might do as well so they will have the same issue.
AWB: Better direction. Don't go another decade where implementations can have private slots, but user code cannot.
MM: The direction I've presented is what I prefer. What I'm actually proposing is that we allow Allen to be the champion and work out the details remaining. Objection?
None.
BE: No objection, but I want to make sure Allen works with YK, JM and Boris Zbarsky
(This did not gain final consensus, as follow up was necessary)
... On to JM objections
JM: Start with a class never meant to be subclassed. Later you want to re-use aspects of this class, but need a way to hook in to the subclass this
before super()
class.
DH: eg. an initialize
method that just sets up properties and state
AWB: If it's just state that it doesn't need to know about, it doesn't matter? If it's state that does need to know about, what the channel? Seems very tenuous at best
JM: An example, we want to re-write some of the dom before calling the parent constructor.
DL: How is dom related?
WH: Are you unable to munge parameters to constructor?
AWB: Consider a scenario where the DOM mutation is contained in a method of the super class that must be invoked, for side effect, with no dep on object instance state, but is an instance-side method. The way around is to access your prototype or original prototype and invoke the method on the instance
Discussion of legacy scenarios and validity.
AWB: More of a refactoring issue
YK/JM: Agreement that we need more real world cases.
MM: Need a very concrete example, showing: the code written that wasn't intended for subclassing and the newer code that's attempting to subclass.
YK: There are issues created by memoization
Discussion re: subclassing in general.
MM: Need to do the concrete example exercise, and before the end of this meeting.
AWB: The fallback is that we just keep what we have.
DD: Worried about @@create, that it won't be possible to subclass because there is negative feedback
MM: Break on this discussion until JM has adequate examples.
(Peter Jensen and John McCutchan)
https://github.com/rwaldron/tc39-notes/blob/master/es6/2014-07/simd-128-tc39.pdf
Other slides: https://peterjensen.github.io/html5-simd/html5-simd.html#/
JMC: (introducing SIMD, Single Instruction Multiple Data)
Slide presentation
Proposing a Fixed 128-bit vector type as close to the metal while remaining portable
Scales with other forms of parallelism
WH: Why fixed 128, given that x86 SIMD is now up to 512-bit vectors?
DH: Plenty of real world use cases for this, video codecs, crypto, etc.
STH: Wider widths?
JMC: Yes.
AWB: Works with IBM PowerPC?
JMC: Yes, overlapping instruction sets.
Proposing, specifically:
float32x4, 4 IEE-754 32-bit floating point numbers int32x4, 4 32-bit signed integers float64x2, 2 IEE-754 64-bit floating point numbers
Float32x4Array, array of float32x4 Int32x4Array, array of int32x4 Float64x2Array, array of float64x2
Object Hierarchy
SIMD -> int32x4 -> add, sub, ... -> float32x4 -> add, sub, ... -> float64x2 -> add, sub, ...
DH: Introduce new value types, but does not depend on user created value types
JMC: Examples...
var a = SIMD.float32x4(1.0, 2.0, 3.0, 4.0);
var b = SIMD.float32x4.zero();
MM: Why is zero() a function instead of a constant?
JMC: It could be a constant.
... additional examples. See Slides.
STH: How much of the difference is SIMD and single precision?
JMC: I don't have numbers, but would say SIMD
MM: Do SIMD instructions preserve denormals or flush?
JMC: ARM flush to zero. SSE you can select
Inner Loop
JMC: All high level JS can be stripped down in the JIT
Shuffling
(copy from slide)
JMC: Compiles down to a single instruction
WH: There are 256 of those constants defined?
JMC: Yes.
Branching
(copy from slide)
WH: What data type used to represent that?
JMC: int32x4
WH: Any kind of 4-bit data type for the mask?
Q about displayed data on slide
WH: Is select
bitwise?
JMC: Yes
WH: Cool. It's data type agnostic and lets you slice into smaller bit slices.
WH: Also, those of us who do NaN-coding will need to beware, because this can both view and manufacture arbitrary NaN's.
How does VM optimize for SIMD
(copy from slide)
**Firefox implementation Status
(see slide)
Chrome/v8 implementation status
(see slide)
YK: is Chrome interested in these patches?
JMC/PJ: They want confirmation from TC39
DL: This is v8, not chrome. v8 team is fairly conservative.
Emscripten Implementation Status
(see slide)
JMC: Much of these operations are used in real world platforms written in C++
V8 SSE Benchmarks (Early 2014)
(see slide)
MM: How can you get faster than 4x faster with 4-way SIMD?
DH: Float 32
SpiderMonkey SSE Benchmarks (Early 2014)
(see slide)
Dart VM NEON Benchmarks (Early 2014)
(see slide)
MM: Why are the relative speed ups across the vms are so different?
JMC: Different output from different code
Why Fixed Width and not Variable Width Vectors
(see slides, 1 & 2)
STH: A problem bigger than variable width vectors. If we wanted 256 bit widths, on 128 bit vector platforms, observable differences.
JMC:
WH: Why is intel building hardware with 128 bit vectors
-- Dmitry Lomov (DL) will fill in details of discussion here.
JMC: this will expose differences hardware
JMC: no implicit conversions, 1 +
WH: It's bad that you can do -
JMC: like asm.js, have to be clear about what types you're operating on.
YK: Don't have to make the ergonomics good
JMC: Don't have to, they never will be.
Planned Features 1
SIMD and value objects/types
Additional data types (int8x16 and int16x8)
AWB: The top bullet has a lot deps, but the bottom not, are these near term?
JMC: Yes
WH: Why not int64x2?
JMC: Support is not universal
MM:
Unsigned integers don't fall in the second?
WH: Why not unsigned integers?
JMC: Not widely used
WH: uint32 perhaps, but uint16 and uint8 are heavily used in graphics to represent pixel values.
JMC: tried, issues encountered
MM: What's being saved, given the already exposed information?
JMC: time, complexity, etc.
AWB: How would you specify "slow", "fast", etc.
DH: Leave it undefined. "High recommended if supported, etc"
AWB: worried about gaming.
DH: same
Planned Features 2
(see slide)
DH: Risk:
YK: The only reason to do the check is if you know you have a faster scalar implementation for systems without the SIMD feature; path of least resistance is to use polyfill and do no check at all. So maybe risk is not so great.
WH: Flip side also could be an issue: Web site has code for the optimized case which is not present on common platforms, somebody changes it and doesn't test it properly, it later breaks on optimized implementations, so browsers don't want to set the optimized flag.
JMC: (confirmed awareness of gaming)
BE: Some won't fake for fear of the performance cliff. See WebGL precedents.
Discussion re: risk, generally: some risks worth taking.
WH: instead of boolean, maybe a value that indicates speed level?
AWB: Application could do a mini benchmark as a test?
Stage 1 Ready?
(see slide)
AWB: Sounds like it is ready for stage 1. Can it be its own independent standard?
WH: It creates new primitive data types. Don't want specs outside creating new types
AWB: Do you expect every runtime to implement this?
JMC: Yes. They will run to implement this!
BE: Some embedded systems have trouble ith regex and unicode, it's expect that there will be "code commerce" among distinct device classes' embedded runtimes.
MM: We need a general framework for new value types
AWB: Without the value types, it's fairly clear cut.
MM: Preserving reference identity makes it prohibitively expensive
DD: Per the ES7 model, the feature can progress without being in another spec.
Discussion of the spec process.
STH: Back to MM statement, what does typeof have to do with reference identity?
MM: (example of using a weakmap)
AWB/DH: (clarification of coupling and timing issue)
DH: Needs to be the same semantics as value types, if we ship this sooner and learn that we made a wrong call, then we have to deal with deciding whether or not we apply the mistake or break with SIMD.
(Allen Wirfs-Brock)
https://github.com/rwaldron/tc39-notes/blob/master/es6/2014-07/parameter-scoping-7-14.pdf
Current spec, Controversial:
function(x) {
var x;
let x; // early error
}
function(x) {
let x; // early error <--------
}
try {
} catch(x) {
let x; // early error <--------
}
AWB: Andreas wants consistent handling
DH: The mental model is that let is block-bound,
DH: var
is "I assert there is a binding in this scope, but that can be re-asserted as much as I want". let
is "I have one unique declaration, I don't allow redeclaration".
YK: If you say var x = 42
half way down the function, you can use the original parameter x
until that point. With TDZ, if you had let x = 42
half way down, you couldn't mean anything with x
DD: (points about let and const protecting from mistakes)
BE: (channeling Andreas) Worried that there will errors when you want to shadow.
DH/YK: The shadowing is meaningless.
MM: I was indifferent, but side with Dave's points about refactoring
STH: Generating code via macros, introduces non-local restrictions that could break
DH: Just have a notion of parameter bindings and block bindings, distinct from the surface syntax, and latter can't shadow former; easy workaround for code generators is to add an extra pair of { }
.
MM: (example of user blindly changing var
to let
)
STH: This isn't a language issue, it's a non-semantics preserving change.
DL: (on behalf of Andreas)
For Do-Expressions:
() => {} = () => do {}
DH: Doesn't hold b/c left is statement body, right is expression body, not equivalent.
AWB: (revisting decisions about duplicate declarations in same contour)
AWB: Need to ensure that lexical declarations are disjoint sets, there spec mechanics there.
STH: Proposing
RW: The refactoring hazard only exists for the one time the code is run after the change from var
to let
and the refactorer is shown the early error and immediately knows to fix the bug. Removing these errors is unfortunate
YK: It's not clear what the program does when there is no early error.
RW: What is Sam's position?
STH: Why do we have these errors? What do we gain from them?
RW: Arguably, JavaScript could use some degree of "nannying" if it has positive results.
MM: No way to explain that function declaration initializes the parameter?
BE: It doesn't. Andreas just wants let
to behave like var
re: redeclaration
MM: Strict programming should be understandable in terms of lexical scope.
BE: Good argument, but not sure it depends on strict.
MM: In sloppy mode, functions are crap as well.
STH: He's just trying explain the semantics of let
, w/r to block scope alone.
MM: A var-less
strict program should be understandable in terms of lexical scope.
BE: var
is huge turd that should be recalled into some lesser demon's bowels.
(Allen Wirfs-Brock)
AWB: There are a lot of TC members and non-members concerned that this was not a wise decision and that we should revisit. Included link to Andy Wingo
RW: if I had been here at the last meeting I would've objected to the removal, but as I told Dave offline, I trust him and his plans for syntax unification. I just wanted to see progress in that regard.
BE: I want to say: I was the champion for years, but letting go. I want to see the comprehensions laziness addressed.
DH: I did this exercise, the sudoku solver in:
https://github.com/dherman/sudoku
JH: I'd like to know if there are objections still, to deferral
AWB: Objecting to the late removal of a complete feature.
RW: Same objection, reached independantly, but again I trust Dave to see through the syntax unification.
DH: First, laziness is not a problem; you just need a way to construct a lazy sequence either from an eager value (array.lazy()
) or from whole cloth (lazyRange(0, 1000)
).
DH: Second, the fact that comprehensions only do a subset of operations you want means you end up mixing code styles (comprehensions + methods), and it gets syntactically awkward.
DH: When I did the exercise with three styles, I found the generalized comprehensions nicer but no comprehensions at all nicest.
BE: The affordance of generator expressions and comprehensions is that you don't have to write a call
DH: (Gives walk through of solver.linq.js, solver.pythonic.js)
DH: I said last time that we need an Iterator.prototype object and we agreed to defer since it probably wouldn't break code, but we forgot that hurts polyfills that want to patch the prototype with upcoming standard methods. So we should add the empty prototype object in ES6.
WH: In expressions such as foo.lazy().map(...function1...).every(...function2...), what shuts down (i.e. calls the return method of) the foo.lazy() generator?
DH: The call to every will shut down the generator if it reaches its decision early.
DD: The minimal Iterator.prototype is empty, but available. The long term is a constructor Iterator with blessed apis.
DH: Confirm
BE: An actual Iterator is means Duck typing isn't the preferred way, just create a real Iterator
MM: Using an actual functional style, the function names you're using are
BE: The oop style prevails, desired chaining API, adapter full of goodies.
Discussion of generators and observables
WH: How would you represent a 2-d comprehension like (for (x of xs) for (y of ys) if (x % y) x+y)?
xs.flatMap(x => ys.filter(y => x % y).map(y => x+y))
WH: OK. A bit less pretty than the comprehension in this case, but acceptable.
MM: after seeing this code I will never use comprehensions
YK: raises arms in triumphant vindication
BE: who will own explaining to Andy Wingo and es-discuss?
DH: I will
BE: "You keep what you kill" - Richard P. Riddick
(Erik Arvidsson , Brendan Eich)
EA: We're using ToObject in spread and all other iterable forms. Should we do the same for destructuring?
// Should allow:
let [first, ...rest] = "foo";
first; // "f"
rest; // ["o", "o"]
STH: ToObject breaks pattern matching because you couldn't match on a number.
YK: But we agreed to a future irrefutible matching, which would be the basis of pattern matching.
DH: Array vs. Object cannot have the same semantics here in what we want from pattern matching
EA: Uses iterator
DH: Not even self-evident that pattern matching syntax will work in JS
YK: (to Sam) Do you think it will it should fail for strings to destructure?
More discussion of pattern matching.
DH, BE: match must mean a different pattern language, ships have sailed for destructuring and implicit ToObject
(Dave Herman)
request slides
DH: (recapping the last meeting and the findings of the breakout group; and the fall out)
DH:
Resolution
(need slides)
Module Context 1
Existing systems provide contextual metadata:
What is the dynamic analog of relative import?
import helper from "./helper";
Module Context 2
this
this
binding is a context objectDD: How is this different from adding global variables, eg. Reflect
STH: The difference is that the value depends on where it is; unlike Reflect
, which is the same thing.
DH: We should use this
in top level of a module
AWB: what does that mean? this
at the top level of a module?
DH:
Module Context 2
this.import("./helper").then(...);
this.filename
(This is where platforms can put its host properties and objects)
eval
Reflect.global
BT: indirect eval?
DH: Will give you the global object
DD: object to relying on this
outside of a method
RW: Workers already to the above
MM: We can't even poison this
for ES6
YK: if you says it's module context, you have to say how it got that value
DH: No new scoping rules. This construct just implicitly binds something.
AWB:
import filename from this;
// which basically: import filename from here;
DD: Like this for relative
DH: Completely amenable to this
YK:
import * as me from here;
me.import; // `me` is the context object
"Then, during the Third Reconciliation of the Last of the Meketrex Supplicants, they chose a new form for him, that of a giant Sloar! Many Shubs and Zulls knew what it was to be roasted in the depths of a Sloar that day, I can tell you!" ―Vinz Clortho[src]