# Will we ever get private symbols? \`Symbol.private()\`

**URL:** <https://es.discourse.group/t/will-we-ever-get-private-symbols-symbol-private/2151>\
**Category:** 💡 Ideas\
**Created:** [September 22, 2024, 6:15am UTC](https://es.discourse.group/t/will-we-ever-get-private-symbols-symbol-private/2151 "2024-09-22T06:15:41Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![trusktr](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/trusktr/32/183_2.png) [@trusktr](https://es.discourse.group/u/trusktr)\
**Post date:** [September 22, 2024, 6:15am UTC](https://es.discourse.group/t/will-we-ever-get-private-symbols-symbol-private/2151/1 "2024-09-22T06:15:41Z")

</div>

# Why

I feel like they'd be more useful than private fields for scenarios outside of classes.

> **[GitHub - zenparsing/proposal-private-symbols: A proposal for private symbols in JavaScript](https://github.com/zenparsing/proposal-private-symbols)**
>
> A proposal for private symbols in JavaScript

(@zenparsing)

Also if `Symbol.private()` ever came out, who would actually keep using `Symbol()`? I feel like most people would want to migrate to `Symbol.private()`.

I feel that Symbols read nicer when associating state with objects:

```js
const someValue = new WeakMap()

someValue.set(someObject, 123)
log( someValue.get(someObject) )

```

vs

```js
const someValue = Symbol.private()

someObject[someValue] = 123
log( someObject[someValue] )

```

Besides the index access syntax is more useful:

```js
someObject[someValue]++
someObject[someValue] += 123
// --
// *=
// etc

```

Symbols are also a smidge faster than WeakMap in V8 as of writing this:

> **[Benchmark: WeakMap vs Symbol Property - MeasureThat.net](https://www.measurethat.net/Benchmarks/Show/7142/0/weakmap-vs-symbol-property)**
>
> JavaScript benchmarks, JavaScript performance playground. Measure performance accross different browsers. javascript benchmarks online.

* * *

# Syntax sugar?

What would syntax sugar look like?

```js
const someValue = Symbol.private()

someObject.!someValue = 123
log( someObject.!someValue )

```

For classes, could the sugar create the binding outside of the class automatically? F.e.

```js
class SomeClass {
  !someValue = 123
}

const someValue = 123 // SyntaxError, someValue has already been declared.

```

or

```js
const someValue = 123

class SomeClass {
  !someValue = 123 // SyntaxError, someValue has already been declared.
}

```

Basically this,

```js
class SomeClass {
  !someValue = 123
}

```

would be effectively the same as

```js
const someValue = Symbol.private('someValue') // name determined syntactically

class SomeClass {
  [someValue] = 123
}

```

And then, because the declared variable is in scope, it is usable anywhere in the class, as well as anywhere in the scope containing the class, matching the same semantics as without syntax sugar:

```js
import {someFunction} from 'somewhere'

export class SomeClass {
  !someValue = 123

  someMethod() {
    console.log(this.!someValue)

    someFunction(this, someValue) // pass the private key to allow private access to certain API, etc
    anotherFunction(this)
  }
}

function anotherFunction(instance) {
  // This works! No limitation on syntactic location like #private fields!
  console.log(instance.!someValue)
}

```

Just as with any other undefined variable, a typo would result in a `ReferenceError`:

```js
class SomeClass {
  !someValue = 123
}

const o = new SomeClass()

o.!someVale // ReferenceError: someVale is not defined

```

If we had this syntax, then maybe `.!foo` would just be short for `[foo]`, and would work for any variable?

F.e.:

```js
const prop = 'foo' // string property

o.!prop // it works

```

The class syntax `!foo = 123` would be unique to classes for the field declarations, without the period.

For objects too?

```js
const o = {
  // declares the variable in the scope that `o` is defined in.
  !someValue: 123
}

console.log( o.!someValue ) // 123

```

Encapsulate it, for example:

```js
function foo() {
  return class {
    !someValue = 123

    method() {
      console.log( this.!someValue ) // 123
    }
  }
}

const someValue = 123 // ok, not declared in outer scope

const Class = foo()

const o = new Class()

console.log( o.!someValue ) // undefined because property "123" does not exist

```

Another option could be to make it module scoped:

```js
function foo() {
  return class {
    !someValue = 123

    method() {
      console.log( this.!someValue ) // 123
    }
  }
}

const someValue = 123 // Error: someValue has already been declared

```

Perhaps in the immediate scope surrounding the class or object is better, more flexible, more options on how to organize? For example,

```js
const someValue = Symbol.private()

function foo() {
  class Foo {
    [someValue] = 123
    !otherValue = 456

    method() {
      console.log( this.!someValue ) // 123
      console.log( this.!otherValue ) // 456
    }
  }

  const o = { !otherValue: 'blah' }
  console.log( o.!otherValue ) // "blah"

  return Foo
}

// here only `someValue` is visible outside the function
const o = new (foo())()
o.!someValue // 123
o.!otherValue // ReferenceError: otherValue is not defined

```

Also,

```js
class Foo {
  static !someValue = 123

  get !foo() {...}
  set !foo() {...}

  !method() {...}

  accessor !bar = 456
}

console.log(someValue, foo, method, bar) // PrivateSymbol(someValue), PrivateSymbol(foo), PrivateSymbol(method), PrivateSymbol(bar)

```

### Reasoning for the Sugar

The reasoning behind this syntax sugar idea, namely with class and object definitions, is to match a very similar semantic as we would have if we were using symbols without syntax sugar (with one difference: the scope in which the symbol is created is chosen for us).

If, for example, `class { !someValue = 123 }` did not expose the symbol in the outer scope, then it seems that there would be almost no practical difference between that and `#private` fields, and in that case it also seems that `this.!someValue` would essentially be syntax for inside the class/object definition just like `#`.

Would there be any difference that would be useful over private fields if the symbol were not to be exposed in outer scope? If only the internal implementation mechanic differed, but otherwise the DX for end developers was merely a different symbol (! vs #), it wouldn't seem worth having.

The advantage of exposing the symbol in the outer scope is that it can be used just like a symbol manually declared would be usable (share it with other code in different ways).

## Advantages over private fields

Plus symbols have [advantages over private fields](https://github.com/zenparsing/proposal-private-symbols/blob/39abfdfcde99f9f187a6cfd510401eb9d61d6504/symbols-or-fields.md), which if we had `.!` syntax would make them as easy to use syntactically as private fields, plus the optional benefits (for example, share a symbol to implement a loose protected methods that can be extended from class to subclass, not doable with pricate methods.

For example `super.!someMethod()` with a shared symbol would work just as with any regular property, the look up happening on the prototype chain.

---

<div class="post-metadata">

**Author:** ![aclaymore](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/aclaymore/32/501_2.png) [@aclaymore](https://es.discourse.group/u/aclaymore)\
**Post date:** [September 22, 2024, 8:12am UTC](https://es.discourse.group/t/will-we-ever-get-private-symbols-symbol-private/2151/2 "2024-09-22T08:12:52Z")

</div>

There is also: [GitHub - tc39/proposal-private-declarations: A proposal to allow trusted code \_outside\_ of the class lexical scope to access private state](https://github.com/tc39/proposal-private-declarations)

Which has the advantage of being syntactic rather than needing the object methods to dynamically check if the symbol is private.

---

<div class="post-metadata">

**Author:** ![trusktr](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/trusktr/32/183_2.png) [@trusktr](https://es.discourse.group/u/trusktr)\
**Post date:** [September 23, 2024, 6:02am UTC](https://es.discourse.group/t/will-we-ever-get-private-symbols-symbol-private/2151/3 "2024-09-23T06:02:03Z")

</div>

I suppose there are pros and cons. Symbols can be passed around and be used in scenarios like string properties can be.

---

<div class="post-metadata">

**Author:** ![trusktr](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/trusktr/32/183_2.png) [@trusktr](https://es.discourse.group/u/trusktr)\
**Post date:** [September 24, 2024, 6:14am UTC](https://es.discourse.group/t/will-we-ever-get-private-symbols-symbol-private/2151/4 "2024-09-24T06:14:19Z")

</div>

@aclaymore Private Declarations will not work with the class+field decorator workaround for avoiding `accessor`: [Reactive/observable field without "accessor"? · Issue #478 · tc39/proposal-decorators · GitHub](https://github.com/tc39/proposal-decorators/issues/478#issuecomment-2370222601)

With Private Symbols, we would be able to reference and store them, therefore making it possible to implement class field reactivity while avoiding the use of `accessor` (yay 🎉).

However the following proposal would allow for fields defined with Private Declarations to be interceptable: [Intercept class field get/set (without accessor on prototype) · Issue #530 · tc39/proposal-decorators · GitHub](https://github.com/tc39/proposal-decorators/issues/530)

I would enjoy having fully private properties without having to start using `accessor` everywhere.
