19 comments

[ 3.0 ms ] story [ 53.2 ms ] thread
So in practice, Symbols are likely to be used to replace UUIDs?

I'm not sure the color example reads particularly well, as the value of the symbol would not actually be useful as a color (you could turn it into one, but it wouldn't reflect the name of the constant).

Could anybody explain what problems this was designed to solve?
It seems they can be used as a little safer enums, like :keywords in clojure. It can come handy if you want to add method to object that nobody will overwrite by accident.

But clojure was designed around :keywords, while js was designed around strings as property names. Adding another possibility now complicates everything.

I don't know if I like it.

I think you'd add methods nobody can overwrite using Object. defineProperty(), which is an ES5 thing.
Unique (derived) tokens that are not equal to any other value.

For example, symbols let you implement a map data structure without having to worry about shadowing built-in properties of the object.

If you have Symbols, you also have Map and WeakMap which don't have that problem.
Seems like it could be used as a way to lazily copy objects; a solution like this could make a lot of sense if, say, a server had entire objects instantiated and the client only needs to know they exist, but not what each object contains.
In addition to the other replies, Symbols were at one point meant to be used for implementing private visibility in classes - the idea being that the private fields of an object would only be visible inside the class closure, preventing external code from being able to access them. However, private has been backed off from ES6 now.
To be clear, "private" variables (including "methods", ie. variables bound to functions) can be implemented anywhere using lexical scope; whether you're pretending to have "classes" or not.

The feature which symbols offer is unforgeable contracts. These offer some benefits of type systems and module systems (AKA existential type systems). Any time we want to restrict access to some value, we can "seal" it by generating a new symbol and using that as its key in an object/mapping. We can pass the symbol to the code we want to "unseal" it, whilst the object itself can get passed around anywhere at all, without anyone being able to extract or replace the value until it reaches the "unsealer".

To see why this would be useful for "private visibility", the trick is not that we're hiding the values to everyone outside our lexical scope (which is trivial, since that's what lexical scope is); it's that we can allow access to these values, via functions which check that they're given the correct symbol. In other words, we can have our code "recognise" when some other code should be given access. If we limit ourselves to making "classes", where the symbol is in-scope in the "constructor" and doesn't leak out, then we have a primitive form of type-checking; if we're given the correct symbol, the other code must be of the same "class", so we might decide to let it see our "privates".

Of course, that's just a degenerate edge-case. There are all kinds of other uses, for example section XII of Harper's Practical Foundations for Programming Languages is dedicated to the topic http://www.cs.cmu.edu/~rwh/plbook/book.pdf

Reflect.ownKeys will list all keys (string or symbol or otherwise) of an object. It's not clear from the article if it can be excluded via an ES5 definition with `enumerable: false`; perhaps so? In that case, this is pretty cool.
I'm not sure of the JS implementation in particular, but it wouldn't surprise me. Keep in mind that the security/encapsulation features of many languages (private, final, const, etc.) can be bypassed using reflection, especially in "more dynamic" languages like Javascript.
There's also Object.getOwnPropertySymbols()

At any rate, Symbol properties aren't meant to be a bullet-proof way to hide private properties. They just reduce the default public API surface of an object by suppressing its internals.

>To be clear, "private" variables (including "methods", ie. variables bound to functions) can be implemented anywhere using lexical scope; whether you're pretending to have "classes" or not.

Sure, as long as you declare all methods that require access to said private fields also within that same scope.

For example, TypeScript emits class methods (and getters-setters) as properties on the constructor's prototype. The reason for assigning methods to the prototype instead of each new instance is of course efficiency - you don't want to make new closures every time you create an instance. If the private fields were only available within the constructor body, the methods could not access them.

Same use (albeit with less nice syntax) as the ruby symbols.

Many frameworks based on ruby (like Rails) make heavy use of symbols.

They are handy as they are immutable, very cheaply comparable for equality and (in ruby) very light on syntax and they can be made out of thin air whenever you need one.

    some_array[:foo] = 'bar'
instead of

    FOO=0
    some_array[FOO] = 'bar';
(think how error prone it's going to be to add more keys like this. Forgotten declarations, duplication declarations and so on).

You could use strings, but they are often heap-allocated (slow) and sometimes (ruby) even mutable and thus way more expensive to compare for equality and require some kind of hashing to put them as keys into hash tables. Symbols don't. And never conflict.

My idea of them was, they are like string-identifiers, but instead of creating a new string for every string-literal the symbol-literal creates one global, immutable instance.
The main reason why Symbols were added AFAIK is to specify protocols / interfaces. Right now, duck typing is all we have in JS.

How do you check if an object is a Promise? You do `(typeof obj.then === 'function')`. Is this good? No, not really, especially not when the language reserves such a word - the problem is that they're global names and can easily conflict with existing methods.

In contrast, a symbol is used for the Iterator protocol [1]. You implement the protocol by adding a method to your object at the key "Symbol.iterator" that returns an iterator object. Unlike with string keys, its impossible for someone to have already used Symbol.iterator as a key before: the value didn't exist at all. As a result, this feature lets ES.next and libraries define new protocols without the need to come up with unique method names that aren't used in any library.

[1]: https://developer.mozilla.org/en/docs/Web/JavaScript/Guide/T...

(comment deleted)
What really? I haven't read through this yet, but my initial thought was the annoying syntax in Rails. Sometimes you have 3 freaking ways to access something which is dot syntax, brackets with a string, and brackets with a symbol. I hope its better than I expect.
What do these symbols add that's not possible with just using Objects as symbols?

E.g. 'foo = {}; bar = {}; foo === bar' yields false.