Slide 1

Slide 1 text

Fake operator overloading Axel Rauschmayer rauschma.de 2012-05-31

Slide 2

Slide 2 text

[intro] conversion plus calls strbuilder point wat end What to expect var p = new Point(); p._ = new Point(1,2) + new Point(3,4) + new Point(5,6); p._ = new Point(1,2) * new Point(3,4) * new Point(5,6); Credit: Tobias Schneider (def.js) Axel Rauschmayer (rauschma.de) Fake operator overloading 2012-05-31 2 / 37

Slide 3

Slide 3 text

[intro] conversion plus calls strbuilder point wat end Overview Converting to primitive The plus operator (+) Triggering function/method calls via + Implementing StringBuilder Implementing Point WAT Conclusion Axel Rauschmayer (rauschma.de) Fake operator overloading 2012-05-31 3 / 37

Slide 4

Slide 4 text

[intro] conversion plus calls strbuilder point wat end Primitives versus objects The following values are primitives: Booleans Numbers Strings undefined null All other values are objects. Axel Rauschmayer (rauschma.de) Fake operator overloading 2012-05-31 4 / 37

Slide 5

Slide 5 text

[intro] conversion plus calls strbuilder point wat end Applying operators to objects JavaScript operators always work with primitive values. obj1 op obj2 Convert obj1 and obj2 to primitives. Compute the result. Axel Rauschmayer (rauschma.de) Fake operator overloading 2012-05-31 5 / 37

Slide 6

Slide 6 text

Converting to primitive The plus operator (+) Triggering function/method calls via + Implementing StringBuilder Implementing Point WAT Conclusion

Slide 7

Slide 7 text

intro [conversion] plus calls strbuilder point wat end ToPrimitive(): converting values to primitives ToPrimitive(value, PreferredType?) PreferredType is Number: If value is primitive, return it as is. Otherwise, value is object. Call value.valueOf(). If primitive, return. Call value.toString(). If primitive, return. Otherwise, throw a TypeError. PreferredType is String: swap steps 2 and 3. Axel Rauschmayer (rauschma.de) Fake operator overloading 2012-05-31 7 / 37

Slide 8

Slide 8 text

intro [conversion] plus calls strbuilder point wat end ToNumber(): converting values to numbers Convert primitive: Argument Result undefined NaN null +0 boolean value true is converted to 1, false is converted to +0 number value no conversion necessary string value parse number ("324" becomes 324) Convert object: call ToPrimitive(obj, Number), convert result to number. Axel Rauschmayer (rauschma.de) Fake operator overloading 2012-05-31 8 / 37

Slide 9

Slide 9 text

intro [conversion] plus calls strbuilder point wat end ToString(): converting values to strings Convert primitive: Argument Result undefined "undefined" null "null" boolean value either "true" or "false" number value the number as a string, e.g. "1.765" string value no conversion necessary Convert object: call ToPrimitive(obj, String), convert result to string. Axel Rauschmayer (rauschma.de) Fake operator overloading 2012-05-31 9 / 37

Slide 10

Slide 10 text

intro [conversion] plus calls strbuilder point wat end Trying out conversion var obj = { valueOf: function () { console.log("valueOf"); return {}; // not primitive }, toString: function () { console.log("toString"); return {}; // not primitive } } Axel Rauschmayer (rauschma.de) Fake operator overloading 2012-05-31 10 / 37

Slide 11

Slide 11 text

intro [conversion] plus calls strbuilder point wat end Trying out conversion: interaction > Number(obj) valueOf toString TypeError: Cannot convert object to primitive value > String(obj) toString valueOf TypeError: Cannot convert object to primitive value Axel Rauschmayer (rauschma.de) Fake operator overloading 2012-05-31 11 / 37

Slide 12

Slide 12 text

Converting to primitive The plus operator (+) Triggering function/method calls via + Implementing StringBuilder Implementing Point WAT Conclusion

Slide 13

Slide 13 text

intro conversion [plus] calls strbuilder point wat end The plus operator (+) value1 + value2 Evaluation: Convert value1 and value2 via ToPrimitive(Number). Either one is string: convert both to string, concatenate. Otherwise: convert both to number, add. Axel Rauschmayer (rauschma.de) Fake operator overloading 2012-05-31 13 / 37

Slide 14

Slide 14 text

intro conversion [plus] calls strbuilder point wat end Trying out + var obj = { valueOf: function () { console.log("valueOf"); return {}; // not primitive }, toString: function () { console.log("toString"); return 123; // primitive } } Axel Rauschmayer (rauschma.de) Fake operator overloading 2012-05-31 14 / 37

Slide 15

Slide 15 text

intro conversion [plus] calls strbuilder point wat end Trying out +: interaction > 3 + obj valueOf toString 126 > "3" + obj valueOf toString '3123' Axel Rauschmayer (rauschma.de) Fake operator overloading 2012-05-31 15 / 37

Slide 16

Slide 16 text

Converting to primitive The plus operator (+) Triggering function/method calls via + Implementing StringBuilder Implementing Point WAT Conclusion

Slide 17

Slide 17 text

intro conversion plus [calls] strbuilder point wat end How many function/method calls? x = f(1) + f(2) Answer: 7 Axel Rauschmayer (rauschma.de) Fake operator overloading 2012-05-31 17 / 37

Slide 18

Slide 18 text

intro conversion plus [calls] strbuilder point wat end The operands: 6 calls function f(pos) { console.log("f"+pos); return { valueOf: function () { console.log("valueOf"+pos); return {}; // not primitive }, toString: function () { console.log("toString"+pos); return "result"; // primitive } }; } Axel Rauschmayer (rauschma.de) Fake operator overloading 2012-05-31 18 / 37

Slide 19

Slide 19 text

intro conversion plus [calls] strbuilder point wat end One more call x = f(1) + f(2) Define a setter for property x of global object. Object.defineProperty(this, "x", { set: function (x) { console.log("set: "+x); } }); Axel Rauschmayer (rauschma.de) Fake operator overloading 2012-05-31 19 / 37

Slide 20

Slide 20 text

intro conversion plus [calls] strbuilder point wat end Interaction > x = f(1) + f(2) f1 f2 valueOf1 toString1 valueOf2 toString2 set: resultresult 'resultresult' Axel Rauschmayer (rauschma.de) Fake operator overloading 2012-05-31 20 / 37

Slide 21

Slide 21 text

Converting to primitive The plus operator (+) Triggering function/method calls via + Implementing StringBuilder Implementing Point WAT Conclusion

Slide 22

Slide 22 text

intro conversion plus [calls] strbuilder point wat end Usage var sb = new StringBuilder(); sb << add("abc") << add("def"); console.log(sb.toString()); // abcdef Axel Rauschmayer (rauschma.de) Fake operator overloading 2012-05-31 22 / 37

Slide 23

Slide 23 text

intro conversion plus [calls] strbuilder point wat end sb << function StringBuilder() { this.data = ""; } // called by << StringBuilder.prototype.valueOf = function () { StringBuilder.current = this; }; Axel Rauschmayer (rauschma.de) Fake operator overloading 2012-05-31 23 / 37

Slide 24

Slide 24 text

intro conversion plus [calls] strbuilder point wat end add("abc") << add("abc") function add(value) { return { valueOf: function () { StringBuilder.current.data += value; } } } Axel Rauschmayer (rauschma.de) Fake operator overloading 2012-05-31 24 / 37

Slide 25

Slide 25 text

intro conversion plus [calls] strbuilder point wat end Return the built string StringBuilder.prototype.toString = function () { return this.data; }; Axel Rauschmayer (rauschma.de) Fake operator overloading 2012-05-31 25 / 37

Slide 26

Slide 26 text

Converting to primitive The plus operator (+) Triggering function/method calls via + Implementing StringBuilder Implementing Point WAT Conclusion

Slide 27

Slide 27 text

intro conversion plus calls strbuilder [point] wat end Usage var p = new Point(); p._ = new Point(1, 2) + new Point(3, 4) + new Point(5, 6); console.log(p.toString()); // Point(9, 12) p._ = new Point(1, 2) * new Point(3, 4) * new Point(5, 6); console.log(p.toString()); // Point(15, 48) Axel Rauschmayer (rauschma.de) Fake operator overloading 2012-05-31 27 / 37

Slide 28

Slide 28 text

intro conversion plus calls strbuilder [point] wat end Being an operand of +, *, etc. Point.prototype.valueOf = function () { Point.operands.push(this); return 3; } Lowest natural number x where the following are all different: x + x x − x x · x x / x Axel Rauschmayer (rauschma.de) Fake operator overloading 2012-05-31 28 / 37

Slide 29

Slide 29 text

intro conversion plus calls strbuilder [point] wat end // p._ = ... Object.defineProperty(Point.prototype, "_", { set: function (value) { var ops = Point.operands; var operator; if (ops.length >= 2 && (value === 3 * ops.length)) { // 3 + 3 + ... operator = this.setAdd; } else if (ops.length === 2 && value === 0) { // 3 - 3 operator = this.setSubtract; } else ... Point.operands = []; // reset return operator.apply(this, ops); } }); Axel Rauschmayer (rauschma.de) Fake operator overloading 2012-05-31 29 / 37

Slide 30

Slide 30 text

Converting to primitive The plus operator (+) Triggering function/method calls via + Implementing StringBuilder Implementing Point WAT Conclusion

Slide 31

Slide 31 text

intro conversion plus calls strbuilder point [wat] end WAT? (1/2) > [] + [] '' Explanation: > [].valueOf() [] > [].toString() '' Makes sense... Axel Rauschmayer (rauschma.de) Fake operator overloading 2012-05-31 31 / 37

Slide 32

Slide 32 text

intro conversion plus calls strbuilder point [wat] end WAT? (2/2) > {} + {} NaN Two components: Block {} Expression +{} (object literal) Axel Rauschmayer (rauschma.de) Fake operator overloading 2012-05-31 32 / 37

Slide 33

Slide 33 text

intro conversion plus calls strbuilder point [wat] end Computing +{} The following expressions are all equivalent: +{} Number({}) Number({}.toString()) // {}.valueOf() isn't primitive Number("[object Object]") NaN Axel Rauschmayer (rauschma.de) Fake operator overloading 2012-05-31 33 / 37

Slide 34

Slide 34 text

intro conversion plus calls strbuilder point [wat] end Properly adding objects > ({} + {}) '[object Object][object Object]' Axel Rauschmayer (rauschma.de) Fake operator overloading 2012-05-31 34 / 37

Slide 35

Slide 35 text

Converting to primitive The plus operator (+) Triggering function/method calls via + Implementing StringBuilder Implementing Point WAT Conclusion

Slide 36

Slide 36 text

intro conversion plus calls strbuilder point wat [end] Conclusion Operators always work with primitive values Fake operator overloading: fun hack, not much more Instead, use method names (see Java): plus, minus, etc. Axel Rauschmayer (rauschma.de) Fake operator overloading 2012-05-31 36 / 37

Slide 37

Slide 37 text

Thank you! Background: www.2ality.com/2011/12/fake-operator-overloading.html github.com/rauschma/op_overload www.2ality.com/2012/01/object-plus-object.html