Upload
brendan-eich
View
2.221
Download
0
Embed Size (px)
Citation preview
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
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
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 suffix to constructor name
• Reflect.defineSuffix(‘L’, Int64)
• or literalSuffixTable.L(‘0’) h/t @littledan
• or use imported names only? h/t @sebmarkbåge
Overloadable Operators
•| ^ &
•==
•< <=
•<< >> >>>
•+ -
•* / %
•unary- unary+ boolean-test!! ~
• ISSUES: lost invariants in spite of overloadable subset
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)
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)
Strict Equality Operators
• The strict equality operators, === and !==, cannot be overloaded
• They work on frozen-by-definition value objects via a structural recursive strict equality test (beware, NaN !== NaN)
• Same-object-reference remains a fast-path optimization
Why Not Double Dispatch?
• Left-first 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
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 the V8 team)
• Background reading: [Chambers 1992]
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
Reflect 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
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?
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 finding intersection not a singleton, breaks tie by maximum prototype depth: (2, addBB) > (1, addAA)