Last active
December 24, 2015 13:59
-
-
Save domenic/6808845 to your computer and use it in GitHub Desktop.
DOMPoint desugaring
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Point { | |
get number x | |
get number y | |
get number length | |
} | |
class MutablePoint extends Point { | |
set x(ToNumber) | |
set y(ToNumber) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Point { | |
private [[x]], [[y]] | |
constructor(ToNumber x: [[x]], ToNumber y: [[y]]) | |
get number x: [[x]] | |
get number y: [[y]] | |
get number length | |
} | |
class MutablePoint extends Point { | |
set x(ToNumber): [[x]] | |
set y(ToNumber): [[y]] | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Global private variable store. | |
// Shared among unlimited instances; no real need to segregate by constructor (that I can see). | |
const privates = new WeakMap(); | |
// Branding helpers | |
const domPoints = new WeakSet(); | |
function ensureDomPoint(thisP) { | |
if (!domPoints.has(thisP)) { | |
throw new TypeError("Called DOMPoint method on incompatible object!"); | |
} | |
} | |
class DOMPoint { | |
[Symbol.create]() { | |
const newPoint = super(); | |
// Install private state | |
privates.set(newPoint, { x: undefined, y: undefined }); | |
// Install brand | |
domPoints.add(newPoint); | |
return newPoint; | |
} | |
constructor(x, y) { | |
ensureDomPoint(this); | |
privates.get(this).x = Number(x); | |
privates.get(this).y = Number(y); | |
} | |
// The brand checks are not actually necessary on the getters, but they give better error | |
// messages than trying to access property `x` of undefined if you just let the next line happen. | |
get x() { | |
ensureDomPoint(this); | |
return privates.get(this).x; | |
} | |
get y() { | |
ensureDomPoint(this); | |
return privates.get(this).y; | |
} | |
get length() { | |
// This method doesn't use any private state, so it shouldn't check branding. | |
// It can be applied generically to anything with `x` and `y` properties. | |
return this.x + this.y; | |
} | |
} | |
// Each class needs its own branding helper | |
const domPointMutables = new WeakSet(); | |
function ensureDomPointMutable(thisP) { | |
if (!domPointMutables.has(thisP)) { | |
throw new TypeError("Called DOMPointMutable method on incompatible object!"); | |
} | |
} | |
class DOMPointMutable extends DOMPoint { | |
[Symbol.create]() { | |
// By calling super, we ensure that this DOMPointMutable instance is also branded as DOMPoint. | |
const newPoint = super(); | |
// No new private state | |
// Install brand | |
domPointMutables.add(newPoint); | |
return newPoint; | |
} | |
// Brands apply to the setters; they can only be used on DOMPointMutables, not DOMPoints. | |
set x(value) { | |
ensureDomPointMutable(this); | |
privates.get(this).x = Number(value); | |
} | |
set y(value) { | |
ensureDomPointMutable(this); | |
privates.get(this).y = Number(value); | |
} | |
// Getters are inherited, but since they only check the DOMPoint brand, they can work on | |
// DOMPointMutables too. | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment