SlideShare a Scribd company logo
1 of 20
Download to read offline
Value Objects
Brendan Eich
brendan@mozilla.com
@BrendanEich
!

Ecma TC39 January 2014
Caveats & Pleas

• A review & update from July 2013 TC39 meeting	

• I’m looking for big picture and detailed feedback	

• The big picture matters most at this stage	

• There will be some TypeScript syntax/semantics!	

• Please hold your fire, illustrative & concrete but
could be changed based on other ES7 work	


• These slides are dense, please feel free to ask Qs	

• Not done yet, open issues & imperfections below
Value Objects

• int32, uint32!
• int64, uint64!
• int32x4, int32x8 (SIMD)	

• float32 (to/from Float32Array today)	

• float32x4, float32x8 (SIMD)	

• bignum	

• decimal (long-time TC39 goal: self-hosted extension)	

• rational	

• complex
Overloadable Operators

• | ^ &!
• ==!
• < <=!
• << >> >>>!
• + -!
• * / %!
• unary- unary+

boolean-test!! ~
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)
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 special
cases, e.g., 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 object: !
• Let p = v.[[Get]](@@ADD)	

• If p is not a Set, throw a TypeError	

• Let q = u.[[Get]](@@ADD_R)	

• If q is not a Set, throw a TypeError	

• Let r = p intersect q	

• If r.size != 1 throw a TypeError	

• Let f = r[0]; if f is not a function, throw	

• Evaluate f(v, u) and return the result
API Idea from CPH 2009
// NOTE: NOT PROPOSED FOR ES7	

!
function addPointAndNumber(a, b) {	
return Point(a.x + b, a.y + b);	
}	

!
Function.defineOperator('+', addPointAndNumber, Point, Number);	

!
function addNumberAndPoint(a, b) {	
return Point(a + b.x, a + b.y);	
}	

!
Function.defineOperator('+', addNumberAndPoint, Number, Point);	

!
function addPoints(a, b) {	
return Point(a.x + b.x, a.y + b.y);	
}	

!
Function.defineOperator('+', addPoints, Point, Point);
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#!

• We want a syntax extension mechanism, with
declarative not runtime API	


• This means new syntax for operator function
and suffix definition
Value Class Declaration
value class point2d {	
// no suffix	
// default typeof “point2d” (no overriding/spoofing)	

!
constructor(private x: int32, private y: int32) {	
// implicit Object.freeze(this) on return	
}	

!
// binary operators (note arrow shorthand for { return … })	
point2d + number (a, b) => point2d(a.x + b, a.y);	
number + point2d (a, b) => point2d(a + b.x, b.y);	
point2d + point2d (a, b) => point2d(a.x + b.x, a.y + b.y);	

!
point2d - number (a, b) => point2d(a.x - b, a.y);	
number - point2d (a, b) => point2d(a - b.x, b.y);	
point2d - point2d (a, b) => point2d(a.x - b.x, a.y - b.y);	

!
// more operators with private access elided	
}
Value Class Declaration, cont.
value class pixel {	 // CSS unit, 1/96th of an inch	
	
suffix “px”;	
typeof “CSS:pixel”;	// we allow a lot, but overriding throws	

!
constructor pixel(public twips: int32) {	
// implicit Object.freeze(this) on return	
}	

!
// unary operators (note arrow shorthand for { return … })	
+() => pixel(this.twips);	
-() => pixel(-this.twips);	
!!() => !!this.twips;	
~() => pixel(~this.twips);	
}	

!
value class point {	 // CSS unit, not Cartesian plane point!	
	
suffix “pt”;	
typeof “CSS:point”;	
// constructor and unary operators not shown…	
}
Binary Operator Declaration
value operators {	
// Here number, string, boolean are in scope, and new operator	
// syntax common to value class works.	

!
pixel + number (a, b)
number + pixel (a, b)
pixel + pixel (a, b)
pixel + point (a, b)
point + pixel (a, b)

=>
=>
=>
=>
=>

pixel(a.twips + b * 15);	
pixel(a * 15 + b.twips);	
pixel(a.twips + b.twips);	
pixel(a.twips + b.twips * 20);	
pixel(a.twips * 20 + b.twips);	

pixel - number (a, b)
number - pixel (a, b)
pixel - pixel (a, b)
pixel - point (a, b)
point - pixel (a, b)

=>
=>
=>
=>
=>

pixel(a.twips - b * 15);	
pixel(a * 15 - b.twips);	
pixel(a.twips - b.twips);	
pixel(a.twips - b.twips * 20);	
pixel(a.twips * 20 - b.twips);	

!

!
// etc… (note only public class members)	
}
Value Subclasses
value class point2d {	
constructor point2d(public x: int32, public y: int32) {	
// implicit Object.freeze(this) on return EXCEPT via super	
}	
// call this function f:	
point2d + point2d (a, b) => point2d(a.x + b.x, a.y + b.y);	
}	

!
value class point3d extends point2d {	
constructor point3d(x: int32, y: int32, public z: int32) {	
super(x, y);	
// implicit Object.freeze(this) on return once, here	
}	
// call this function g:	
point3d + point3d (a, b) => point3d(a.x+b.x, a.y+b.y, a.z+b.z);	
}	

!
// What does point3d(1, 0, 0) + point3d(0, 1, 0) do?	
{f, g} intersect {f, g} => {f, g}, ambiguity error!
Class Precedence via Prototype Depth
// When point2d’s declaration is evaluated:	
let f = point2d + point2d (a, b) => point2d(a.x + b.x, a.y + b.y);	
point2d.prototype.@@ADD = Set([[1, f]]);	
point2d.prototype.@@ADD_R = Set([[1, f]]);	

!
// When point3d’s declaration is evaluated:	
let g = point3d+point3d (a,b) => point3d(a.x+b.x,a.y+b.y,a.z+b.z);	
point3d.prototype.@@ADD = Set([[1, f], [2, g]]);	
point3d.prototype.@@ADD_R = Set([[1, f], [2, g]]);	

!
// Set notation, please! Here’s what we have at this moment:	
point2d.prototype.@@ADD: {[1, f]}	
point2d.prototype.@@ADD_R: {[1, f]}	
point3d.prototype.@@ADD: {[1, f], [2, g]}	
point3d.prototype.@@ADD_R: {[1, f], [2, g]}	

!
// What does point3d(1, 0, 0) + point3d(0, 1, 0) do?	
{[1,f], [2,g]} intersect {[1,f], [2,g]} => g, more specific wins
The (Other) Frame Problem
// P1: Primitives, e.g. strings, are wrapped via the corresponding	
// scoped constructor/converter function, e.g. String.	
String.prototype.len = function () { return this.length; }	

!
// Suppose otherFrame.str is “LOL”, the primitive string value:	
alert(otherFrame.str.len());	 	 	 	 // 3	

!
// Value objects are objects, that’s the price of extensibility.	
int64.prototype.digits = function () { … }	

!
alert(otherFrame.int64(42).digits())	 // throws, method missing	

!
// P2: As noted last time, cross-frame/realm binary ops fail:	
let three = 1L + otherFrame.int64(2);	 // throws, no such method	

!
//
//
//
//

Possible solutions:	
1. Live with it, frames/realms (should be) more isolated FTW	
2. Proxy as if across a membrane, isolation with mediation FTW	
3. Memoize aggressively (hash-cons); solves P2, not P1 in full
Healing the Old Wounds
// Primitives: built-in magic, not extensible, auto-wrap via scope	
// Reference Objects: user-extensible, conversions not operators	
// Value Objects: by-value semantics; multimethod dyadic operator,	
//
unary operator, suffix, and typeof extensibility	

!
// Idea: enable the JS hacker to bless primitives as value objects	
// and thereby opt into value object operator semantics.	

!
value
value
value
value

class
class
class
class

null;	 	
boolean;	
number;	
	
string;	
	

//
//
//
//

typeof null == “null”	
false != "", true != 1	
42 != "42", 1 != true	
"" != false, “42" != 42, [] + “" throws	

!
// ‘value class string;’ will require explicit .toString() calls!	

!
use value sanity;	 	
	 	 	 	 	 	 	 	

// all of the above, a shorthand; no way to	
// “undeclare”; upgrade your Realm!
Thanks / Q&A
Brendan Eich
brendan@mozilla.com
@BrendanEich
!

Ecma TC39 January 2014

More Related Content

What's hot

Types by Adform Research
Types by Adform ResearchTypes by Adform Research
Types by Adform Research
Vasil Remeniuk
 
Constructor and Destructor
Constructor and DestructorConstructor and Destructor
Constructor and Destructor
Kamal Acharya
 

What's hot (19)

Aspdot
AspdotAspdot
Aspdot
 
Dynamic Type Inference for Gradual Hindley–Milner Typing
Dynamic Type Inference for Gradual Hindley–Milner TypingDynamic Type Inference for Gradual Hindley–Milner Typing
Dynamic Type Inference for Gradual Hindley–Milner Typing
 
Mining Functional Patterns
Mining Functional PatternsMining Functional Patterns
Mining Functional Patterns
 
Monte Carlo C++
Monte Carlo C++Monte Carlo C++
Monte Carlo C++
 
Optionals by Matt Faluotico
Optionals by Matt FaluoticoOptionals by Matt Faluotico
Optionals by Matt Faluotico
 
Algebraic Thinking for Evolution of Pure Functional Domain Models
Algebraic Thinking for Evolution of Pure Functional Domain ModelsAlgebraic Thinking for Evolution of Pure Functional Domain Models
Algebraic Thinking for Evolution of Pure Functional Domain Models
 
Templates
TemplatesTemplates
Templates
 
Clojure intro
Clojure introClojure intro
Clojure intro
 
Constructors and Destructors
Constructors and DestructorsConstructors and Destructors
Constructors and Destructors
 
Overview of c (2)
Overview of c (2)Overview of c (2)
Overview of c (2)
 
Introducing: A Complete Algebra of Data
Introducing: A Complete Algebra of DataIntroducing: A Complete Algebra of Data
Introducing: A Complete Algebra of Data
 
Towards hasktorch 1.0
Towards hasktorch 1.0Towards hasktorch 1.0
Towards hasktorch 1.0
 
Constructor and destructor
Constructor  and  destructor Constructor  and  destructor
Constructor and destructor
 
Types by Adform Research
Types by Adform ResearchTypes by Adform Research
Types by Adform Research
 
Templates in c++
Templates in c++Templates in c++
Templates in c++
 
Constructors and Destructors
Constructors and DestructorsConstructors and Destructors
Constructors and Destructors
 
Introduction to programming with dependent types in Scala
Introduction to programming with dependent types in ScalaIntroduction to programming with dependent types in Scala
Introduction to programming with dependent types in Scala
 
Constructor and Destructor
Constructor and DestructorConstructor and Destructor
Constructor and Destructor
 
constructor & destructor in cpp
constructor & destructor in cppconstructor & destructor in cpp
constructor & destructor in cpp
 

Viewers also liked

Viewers also liked (20)

Mozilla Research Party Talk
Mozilla Research Party TalkMozilla Research Party Talk
Mozilla Research Party Talk
 
Containers in a File
Containers in a FileContainers in a File
Containers in a File
 
PFcache - LinuxCon 2015
PFcache - LinuxCon 2015PFcache - LinuxCon 2015
PFcache - LinuxCon 2015
 
Value Objects
Value ObjectsValue Objects
Value Objects
 
Values
ValuesValues
Values
 
Capitol js
Capitol jsCapitol js
Capitol js
 
Fluent15
Fluent15Fluent15
Fluent15
 
My dotJS Talk
My dotJS TalkMy dotJS Talk
My dotJS Talk
 
JSLOL
JSLOLJSLOL
JSLOL
 
Paren free
Paren freeParen free
Paren free
 
Taysom seminar
Taysom seminarTaysom seminar
Taysom seminar
 
Mozilla's NodeConf talk
Mozilla's NodeConf talkMozilla's NodeConf talk
Mozilla's NodeConf talk
 
dotJS 2015
dotJS 2015dotJS 2015
dotJS 2015
 
Always bet on JS - Finjs.io NYC 2016
Always bet on JS - Finjs.io NYC 2016Always bet on JS - Finjs.io NYC 2016
Always bet on JS - Finjs.io NYC 2016
 
Serializing Value Objects-Ara Hacopian
Serializing Value Objects-Ara HacopianSerializing Value Objects-Ara Hacopian
Serializing Value Objects-Ara Hacopian
 
Splash
SplashSplash
Splash
 
#pugMi - DDD - Value objects
#pugMi - DDD - Value objects#pugMi - DDD - Value objects
#pugMi - DDD - Value objects
 
Persisting Value Objects
Persisting Value ObjectsPersisting Value Objects
Persisting Value Objects
 
Txjs talk
Txjs talkTxjs talk
Txjs talk
 
A System Is Not a Tree
A System Is Not a TreeA System Is Not a Tree
A System Is Not a Tree
 

Similar to Value Objects, Full Throttle (to be updated for spring TC39 meetings)

Memory Management with Java and C++
Memory Management with Java and C++Memory Management with Java and C++
Memory Management with Java and C++
Mohammad Shaker
 
C++11: Feel the New Language
C++11: Feel the New LanguageC++11: Feel the New Language
C++11: Feel the New Language
mspline
 
Denis Lebedev, Swift
Denis  Lebedev, SwiftDenis  Lebedev, Swift
Denis Lebedev, Swift
Yandex
 

Similar to Value Objects, Full Throttle (to be updated for spring TC39 meetings) (20)

JavaScript in 2016 (Codemotion Rome)
JavaScript in 2016 (Codemotion Rome)JavaScript in 2016 (Codemotion Rome)
JavaScript in 2016 (Codemotion Rome)
 
JavaScript in 2016
JavaScript in 2016JavaScript in 2016
JavaScript in 2016
 
C++ process new
C++ process newC++ process new
C++ process new
 
Java/Scala Lab: Анатолий Кметюк - Scala SubScript: Алгебра для реактивного пр...
Java/Scala Lab: Анатолий Кметюк - Scala SubScript: Алгебра для реактивного пр...Java/Scala Lab: Анатолий Кметюк - Scala SubScript: Алгебра для реактивного пр...
Java/Scala Lab: Анатолий Кметюк - Scala SubScript: Алгебра для реактивного пр...
 
Return of c++
Return of c++Return of c++
Return of c++
 
Memory Management with Java and C++
Memory Management with Java and C++Memory Management with Java and C++
Memory Management with Java and C++
 
Introduction to C#
Introduction to C#Introduction to C#
Introduction to C#
 
C++11: Feel the New Language
C++11: Feel the New LanguageC++11: Feel the New Language
C++11: Feel the New Language
 
02 functions, variables, basic input and output of c++
02   functions, variables, basic input and output of c++02   functions, variables, basic input and output of c++
02 functions, variables, basic input and output of c++
 
The Present and Future of the Web Platform
The Present and Future of the Web PlatformThe Present and Future of the Web Platform
The Present and Future of the Web Platform
 
Replace OutputIterator and Extend Range
Replace OutputIterator and Extend RangeReplace OutputIterator and Extend Range
Replace OutputIterator and Extend Range
 
Angular2 for Beginners
Angular2 for BeginnersAngular2 for Beginners
Angular2 for Beginners
 
Denis Lebedev, Swift
Denis  Lebedev, SwiftDenis  Lebedev, Swift
Denis Lebedev, Swift
 
Object Oriented Programming using C++ - Part 4
Object Oriented Programming using C++ - Part 4Object Oriented Programming using C++ - Part 4
Object Oriented Programming using C++ - Part 4
 
Modern C++ Lunch and Learn
Modern C++ Lunch and LearnModern C++ Lunch and Learn
Modern C++ Lunch and Learn
 
The Present and The Future of Functional Programming in C++
The Present and The Future of Functional Programming in C++The Present and The Future of Functional Programming in C++
The Present and The Future of Functional Programming in C++
 
L10
L10L10
L10
 
Friend this-new&delete
Friend this-new&deleteFriend this-new&delete
Friend this-new&delete
 
Debugging and Profiling C++ Template Metaprograms
Debugging and Profiling C++ Template MetaprogramsDebugging and Profiling C++ Template Metaprograms
Debugging and Profiling C++ Template Metaprograms
 
Writing DSL with Applicative Functors
Writing DSL with Applicative FunctorsWriting DSL with Applicative Functors
Writing DSL with Applicative Functors
 

Recently uploaded

Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Victor Rentea
 
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Victor Rentea
 
Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native Applications
WSO2
 

Recently uploaded (20)

Ransomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdfRansomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdf
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Spring Boot vs Quarkus the ultimate battle - DevoxxUK
Spring Boot vs Quarkus the ultimate battle - DevoxxUKSpring Boot vs Quarkus the ultimate battle - DevoxxUK
Spring Boot vs Quarkus the ultimate battle - DevoxxUK
 
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
 
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
 
MS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectorsMS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectors
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
 
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ..."I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
 
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
 
Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native Applications
 
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
 
ICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesICT role in 21st century education and its challenges
ICT role in 21st century education and its challenges
 
Corporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptxCorporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptx
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...
 
FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of Terraform
 
AXA XL - Insurer Innovation Award Americas 2024
AXA XL - Insurer Innovation Award Americas 2024AXA XL - Insurer Innovation Award Americas 2024
AXA XL - Insurer Innovation Award Americas 2024
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 

Value Objects, Full Throttle (to be updated for spring TC39 meetings)

  • 2. Caveats & Pleas • A review & update from July 2013 TC39 meeting • I’m looking for big picture and detailed feedback • The big picture matters most at this stage • There will be some TypeScript syntax/semantics! • Please hold your fire, illustrative & concrete but could be changed based on other ES7 work • These slides are dense, please feel free to ask Qs • Not done yet, open issues & imperfections below
  • 3. Value Objects • int32, uint32! • int64, uint64! • int32x4, int32x8 (SIMD) • float32 (to/from Float32Array today) • float32x4, float32x8 (SIMD) • bignum • decimal (long-time TC39 goal: self-hosted extension) • rational • complex
  • 4. Overloadable Operators • | ^ &! • ==! • < <=! • << >> >>>! • + -! • * / %! • unary- unary+ boolean-test!! ~
  • 5. 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)
  • 6. 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 special cases, e.g., unordered values (NaNs)
  • 7. 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
  • 8. 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
  • 9. 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]
  • 10. Binary Operator Example • For v + u with either a value object: ! • Let p = v.[[Get]](@@ADD) • If p is not a Set, throw a TypeError • Let q = u.[[Get]](@@ADD_R) • If q is not a Set, throw a TypeError • Let r = p intersect q • If r.size != 1 throw a TypeError • Let f = r[0]; if f is not a function, throw • Evaluate f(v, u) and return the result
  • 11. API Idea from CPH 2009 // NOTE: NOT PROPOSED FOR ES7 ! function addPointAndNumber(a, b) { return Point(a.x + b, a.y + b); } ! Function.defineOperator('+', addPointAndNumber, Point, Number); ! function addNumberAndPoint(a, b) { return Point(a + b.x, a + b.y); } ! Function.defineOperator('+', addNumberAndPoint, Number, Point); ! function addPoints(a, b) { return Point(a.x + b.x, a.y + b.y); } ! Function.defineOperator('+', addPoints, Point, Point);
  • 12. 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#! • We want a syntax extension mechanism, with declarative not runtime API • This means new syntax for operator function and suffix definition
  • 13. Value Class Declaration value class point2d { // no suffix // default typeof “point2d” (no overriding/spoofing) ! constructor(private x: int32, private y: int32) { // implicit Object.freeze(this) on return } ! // binary operators (note arrow shorthand for { return … }) point2d + number (a, b) => point2d(a.x + b, a.y); number + point2d (a, b) => point2d(a + b.x, b.y); point2d + point2d (a, b) => point2d(a.x + b.x, a.y + b.y); ! point2d - number (a, b) => point2d(a.x - b, a.y); number - point2d (a, b) => point2d(a - b.x, b.y); point2d - point2d (a, b) => point2d(a.x - b.x, a.y - b.y); ! // more operators with private access elided }
  • 14. Value Class Declaration, cont. value class pixel { // CSS unit, 1/96th of an inch suffix “px”; typeof “CSS:pixel”; // we allow a lot, but overriding throws ! constructor pixel(public twips: int32) { // implicit Object.freeze(this) on return } ! // unary operators (note arrow shorthand for { return … }) +() => pixel(this.twips); -() => pixel(-this.twips); !!() => !!this.twips; ~() => pixel(~this.twips); } ! value class point { // CSS unit, not Cartesian plane point! suffix “pt”; typeof “CSS:point”; // constructor and unary operators not shown… }
  • 15. Binary Operator Declaration value operators { // Here number, string, boolean are in scope, and new operator // syntax common to value class works. ! pixel + number (a, b) number + pixel (a, b) pixel + pixel (a, b) pixel + point (a, b) point + pixel (a, b) => => => => => pixel(a.twips + b * 15); pixel(a * 15 + b.twips); pixel(a.twips + b.twips); pixel(a.twips + b.twips * 20); pixel(a.twips * 20 + b.twips); pixel - number (a, b) number - pixel (a, b) pixel - pixel (a, b) pixel - point (a, b) point - pixel (a, b) => => => => => pixel(a.twips - b * 15); pixel(a * 15 - b.twips); pixel(a.twips - b.twips); pixel(a.twips - b.twips * 20); pixel(a.twips * 20 - b.twips); ! ! // etc… (note only public class members) }
  • 16. Value Subclasses value class point2d { constructor point2d(public x: int32, public y: int32) { // implicit Object.freeze(this) on return EXCEPT via super } // call this function f: point2d + point2d (a, b) => point2d(a.x + b.x, a.y + b.y); } ! value class point3d extends point2d { constructor point3d(x: int32, y: int32, public z: int32) { super(x, y); // implicit Object.freeze(this) on return once, here } // call this function g: point3d + point3d (a, b) => point3d(a.x+b.x, a.y+b.y, a.z+b.z); } ! // What does point3d(1, 0, 0) + point3d(0, 1, 0) do? {f, g} intersect {f, g} => {f, g}, ambiguity error!
  • 17. Class Precedence via Prototype Depth // When point2d’s declaration is evaluated: let f = point2d + point2d (a, b) => point2d(a.x + b.x, a.y + b.y); point2d.prototype.@@ADD = Set([[1, f]]); point2d.prototype.@@ADD_R = Set([[1, f]]); ! // When point3d’s declaration is evaluated: let g = point3d+point3d (a,b) => point3d(a.x+b.x,a.y+b.y,a.z+b.z); point3d.prototype.@@ADD = Set([[1, f], [2, g]]); point3d.prototype.@@ADD_R = Set([[1, f], [2, g]]); ! // Set notation, please! Here’s what we have at this moment: point2d.prototype.@@ADD: {[1, f]} point2d.prototype.@@ADD_R: {[1, f]} point3d.prototype.@@ADD: {[1, f], [2, g]} point3d.prototype.@@ADD_R: {[1, f], [2, g]} ! // What does point3d(1, 0, 0) + point3d(0, 1, 0) do? {[1,f], [2,g]} intersect {[1,f], [2,g]} => g, more specific wins
  • 18. The (Other) Frame Problem // P1: Primitives, e.g. strings, are wrapped via the corresponding // scoped constructor/converter function, e.g. String. String.prototype.len = function () { return this.length; } ! // Suppose otherFrame.str is “LOL”, the primitive string value: alert(otherFrame.str.len()); // 3 ! // Value objects are objects, that’s the price of extensibility. int64.prototype.digits = function () { … } ! alert(otherFrame.int64(42).digits()) // throws, method missing ! // P2: As noted last time, cross-frame/realm binary ops fail: let three = 1L + otherFrame.int64(2); // throws, no such method ! // // // // Possible solutions: 1. Live with it, frames/realms (should be) more isolated FTW 2. Proxy as if across a membrane, isolation with mediation FTW 3. Memoize aggressively (hash-cons); solves P2, not P1 in full
  • 19. Healing the Old Wounds // Primitives: built-in magic, not extensible, auto-wrap via scope // Reference Objects: user-extensible, conversions not operators // Value Objects: by-value semantics; multimethod dyadic operator, // unary operator, suffix, and typeof extensibility ! // Idea: enable the JS hacker to bless primitives as value objects // and thereby opt into value object operator semantics. ! value value value value class class class class null; boolean; number; string; // // // // typeof null == “null” false != "", true != 1 42 != "42", 1 != true "" != false, “42" != 42, [] + “" throws ! // ‘value class string;’ will require explicit .toString() calls! ! use value sanity; // all of the above, a shorthand; no way to // “undeclare”; upgrade your Realm!
  • 20. Thanks / Q&A Brendan Eich brendan@mozilla.com @BrendanEich ! Ecma TC39 January 2014