•5 likes•6,782 views

Report

Share

Download to read offline

Updated from Value Objects talks to separate Operators and Literals from Value Types as championed by Niko Matsakis and now Daniel Ehrenberg.

Follow

- 1. Operators and Literals Brendan Eich brendan.eich@gmail.com @BrendanEich Ecma TC39 May 2015
- 2. Value Types Review • Int64, Uint64 (note capitalized names) • Int32x4, Int32x8, etc. (SIMD) • Float32 (to/from Float32Array today) • Float32x4, Float32x8 (SIMD) • Bignum • Decimal (long-time TC39 goal for IBM: self-hosted) • Complex • Rational
- 3. Value Types Review, 2 var ColorType = ValueType(Symbol(“Color"), // or Symbol.for? {r: Uint8, g: Uint8, b: Uint8, a: Uint8}); ColorType.prototype.average = function() { return (this.r + this.g + this.b) / 3; }; var color = ColorType({r: 22, g: 44, b: 66, a: 88}); color.average() // yields 44 assert(typeof color == “color”); // un-capitalized! // ISSUE: some web JS hardcodes known typeof results
- 4. Literal Syntax • Int64(0) ==> 0L // as in C# • Uint64(0) ==> 0UL // as in C# • Float32(0) ==> 0f // as in C# • Bignum(0) ==> 0n // avoid i/I • Decimal(0) ==> 0m // or M, C/F# • Lexically transpose, e.g., 0L into L(0) • Sanity: map short sufﬁx to constructor name • Reflect.defineSuffix(‘L’, Int64) • or literalSuffixTable.L(‘0’) h/t @littledan • or use imported names only? h/t @sebmarkbåge
- 5. Overloadable Operators •| ^ & •== •< <= •<< >> >>> •+ - •* / % •unary- unary+ boolean-test!! ~ • ISSUES: lost invariants in spite of overloadable subset
- 6. Preserving Boolean Algebra • != and ! are not overloadable, to preserve identities including • X ? A : B <=> !X ? B : A • !(X && Y) <=> !X || !Y • !(X || Y) <=> !X && !Y • X != Y <=> !(X == Y) • ISSUE: implicit-!!(x) vs. !(!x)
- 7. Preserving Relational Relations • > and >= are derived from < and <= as follows: • A > B <=> B < A • A >= B <=> B <= A • We provide <= in addition to < rather than derive A <= B from !(B < A) in order to allow the <= overloading to match the same value object’s == semantics • And for unordered values (NaNs)
- 8. Strict Equality Operators • The strict equality operators, === and !==, cannot be overloaded • They work on frozen-by-deﬁnition value objects via a structural recursive strict equality test (beware, NaN !== NaN) • Same-object-reference remains a fast-path optimization
- 9. Why Not Double Dispatch? • Left-ﬁrst asymmetry (v value, n number): • v + n ==> v.add(n) • n + v ==> v.radd(n) • Anti-modular: exhaustive other-operand type enumeration required in operator method bodies • Consequent loss of compositionality: Complex and Rational cannot be composed to make Ratplex without modifying source or wrapping in proxies
- 10. Cacheable Multimethods • Proposed in 2009 by Christian Plesner Hansen (Google) in es-discuss • Avoids double-dispatch drawbacks from last slide: binary operators implemented by 2-ary functions for each pair of types • Supports Polymorphic Inline Cache (PIC) optimizations (Christian was on theV8 team) • Background reading: [Chambers 1992]
- 11. Binary Operator Example • For v + u with either a value type instance: • Let p = v.[[Get]](@@ADD) • If p is not an OperatorSet, throw a TypeError • Let q = u.[[Get]](@@ADD_R) • If q is not an OperatorSet, throw a TypeError • Let r = p.join(q) (r an Array) • If r.length != 1 throw a TypeError • Let f = r[0]; if f is not a function, throw • Evaluate f(v, u) and return the result
- 12. Reﬂect API Example function addPointAndNumber(a, b) { return Point(a.x + b, a.y + b); } Reflect.defineOperator('+', addPointAndNumber, Point, Number); function addNumberAndPoint(a, b) { return Point(a + b.x, a + b.y); } Reflect.defineOperator('+', addNumberAndPoint, Number, Point); function addPoints(a, b) { return Point(a.x + b.x, a.y + b.y); } Reflect.defineOperator('+', addPoints, Point, Point); // NB: Calling defineOperator with 3 args defines unary operator
- 13. Subclassing Problem • Given class A and class B extends A, • Reflect.defineOperator(‘+’, addAA, A, A); • Reflect.defineOperator(‘+', addBB, B, B); • a1 + a2 must select addAA • a1 + b2 and b1 + a2 must select addAA • b1 + b2 must select addBB not addAA • How should OperatorSet implement this?
- 14. Subclassing Solution • OperatorSet stores (depth, method) pairs • Reflect.defineOperator(‘+', addBB, B, B); copies B’s initial @@ADD and @@ADD_R operator- sets from A’s @@ADD and @@ADD_R sets • OperatorSet.join, on ﬁnding intersection not a singleton, breaks tie by maximum prototype depth: (2, addBB) > (1, addAA)