1 of 18

Private Declarations

Bradley Farias

2 of 18

Driving Questions

  • Is the key of private data something that should be a first class value?
  • Should accessing private data have the exact appearance of public data?
  • Can we expand private data to be usable for arbitrary objects instead of classes?

3 of 18

Private State

class Foo {� #bar = 0;� get bar() {� return this.#bar++;� }�};

4 of 18

Private State

const privy = new WeakMap();�const foo = {� get bar() {� if (!privy.has(this)) throw …� let _ = privy.get(this);� privy.set(this, _ + 1);� return _;� }�};

5 of 18

Private State

const privy = new WeakMap();�const foo = {� get bar() {� if (!privy.has(this)) throw …� let _ = privy.get(this);� privy.set(this, _ + 1);� return _;� }�};

privy.set(foo, 0);

Interceptable via some means of mutating state.

6 of 18

Private State

private #bar;�foo.#bar;�

7 of 18

Private State

private #bar;�const foo = {� get bar() {� return this.#bar++;� }�};�foo.#bar = 0;�console.log(foo.#bar);

#bar on value that does not have an initialized field #bar could lead to impersonation and/or accidental "Branding"

8 of 18

Private State

private #bar;�const foo = {� get bar() {� return this.#bar++;� }�};�private.initialize(foo.#bar, 0);

Similar concept to new.initialize, syntax/api bikeshed could go all over the place

9 of 18

Private State

const bar = 'outside';�class Foo {� [bar] = … � bar = … �};

10 of 18

Private State

private #baz;

const bar = 'outside';�class Foo {� [bar] = … � bar = … �� [#baz] = 0� #baz = … �};

Since `#baz = 0` has meaning inside classes, take computed property precedence of pulling from outside context

11 of 18

Private State

private #bar;�

const bar = 'ignored';�const foo = {� [#bar]: 0,� bar: function () {� return this.#bar++;� }�};�

#bar = …;�foo = {};�private.initialize(foo.#bar, 0);

Object.defineProperty(foo, 'bar', {value: …});

12 of 18

Private State

const bar = 'ignored';�const foo = {� bar: function () {� }�};�

13 of 18

Private State

private #bar;�const foo = {� [#bar]: 0,� … �};�const baz = {� [#bar]: 0,� … �};�

14 of 18

Rambling: SHARING IS CARING

15 of 18

Gateway pattern

// Use cycles of modules to form a timing �// the modules are both initialized but not evaluated�// remove a setup function on evaluation

import {setup as setupFriend} 'friend';�var SECRET = setupFriend();�export function setup() {� setup = null;� if (shared) return;� SECRET = …;� return SECRET;�}

Cycles, timing, and a whole lotta trust going on here to do this right

16 of 18

Getters/setters across modules :-(

private #snacks;�function snacks(o, v) {� return o.#snacks = v;�}�export {snacks};

17 of 18

Limit who can get to private state

private #snacks;�function snacks(o) {� … �}�export {snacks} for 'friend';

18 of 18

BIKESHEDS

private #snacks;�export {#snacks} for 'friend';�

import {#snacks as #yums} from 'other';