javascript-private-state icon indicating copy to clipboard operation
javascript-private-state copied to clipboard

Is the `private` part of this proposal transpilable via Babel + WeakMaps?

Open dead-claudia opened this issue 9 years ago • 6 comments

I'm just wondering if there's any aspect of specifically the private part that isn't possible to transpile statically with Babel (beyond possible static/runtime error differences).

I believe much of this can be done with a per-class cache, and I was looking at maybe filing a possible feature request on their end if it can.

// Original
class Foo {
  private #prop, #unused

  constructor(data) {
    #prop = data
  }

  equal(other) {
    return #prop === other.#prop
  }

  set(data) {
    #prop = data
  }

  static is(obj1, obj2) {  
    return obj1.#prop === obj2.#prop
  }
}

// Transpiled
function _privateCheck(cache, obj, field) {
  if (typeof obj !== "object" || obj === null) {
    throw new TypeError("private fields are only accessible on objects")
  }
  const data = cache.get(obj)
  if (data === void 0) {
    throw new ReferenceError("private member #" + field + " is not defined")
  }
  return data
}

const _privateFoo = new WeakMap()
class Foo {
  constructor(data) {
    // The constructor doesn't need any checks.
    const _data = {prop: data, unused: void 0}
    _privateFoo.add(this, _data)
  }

  equals(other) {
    return _privateCheck(_privateFoo, this, "prop").prop ===
      _privateCheck(_privateFoo, other, "prop").prop
  }

  set(data) {
    _privateCheck(_privateFoo, this, "prop").prop = data
  }

  static is(obj1, obj2) {  
    return _privateCheck(_privateFoo, obj1, "prop").prop ===
      _privateCheck(_privateFoo, obj2, "prop").prop
  }
}

Friend semantics can similarly be done. Just use symbols for the property keys in the friend access.

dead-claudia avatar Mar 19 '16 00:03 dead-claudia

You'd have to use a WeakMap to get a per-class cache that didn't leak memory, and WeakMap can't be truly polyfilled.

ljharb avatar Mar 19 '16 03:03 ljharb

WeakMap can't be truly polyfilled.

That is correct but it amazing how close we can come:

https://github.com/google/caja/blob/master/src/com/google/caja/ses/WeakMap.js

Fortunately, we rarely need to polyfill it anymore. https://kangax.github.io/compat-table/es6/ (see WeakMap row)

erights avatar Mar 19 '16 03:03 erights

Many people and companies still need to support older browsers and older node versions, down to IE 8 or node 0.4 even. Polyfillability is still very important :-)

ljharb avatar Mar 19 '16 04:03 ljharb

Indeed. Our WeakMap polyfill is open source. You and they are welcome to it.

See also @kriskowal 's port and refactoring at https://github.com/drses/weak-map . This if the more useful one if you want to use it outside the rest of the Caja framework ;).

erights avatar Mar 19 '16 04:03 erights

@ljharb I know it requires a WeakMap implementation to reliably implement. I was just curious if it was polyfillable down to at least ES6.

dead-claudia avatar Mar 20 '16 01:03 dead-claudia

As for a true weak map polyfill, although it's a bit moot now, you could always use node-weak to write a Node-specific polyfill.

dead-claudia avatar Mar 20 '16 01:03 dead-claudia