Allen Wirfs-Brock (2014-02-11T19:04:31.000Z)
On Feb 11, 2014, at 6:40 AM, Claude Pache wrote:

> According to the current version of the ES6 spec [1], `Symbol(desc)`, when `desc` is not `undefined`, coerces its argument to a string and uses it as a description for a newly created symbol. In particular, if `sym` is a symbol, `Symbol(sym)` throws a TypeError (it can't be coerced to string).
> 
> Intuitively, I would expect that `Symbol(sym)` just returns `sym`, just like `Number(num)` returns `num`, or, more generally, just like `Primitive(x)` casts its argument to the corresponding primitive.
> 
> What do you think?
> 

I can't find any explicit mention of this in the meeting notes [1] where we decided to make Symbol a primitive type with a wrapper class.  However, I made the appropriate changes to the spec. immediately after that meeting when the discussion was fresh in my mind and I still think that throwing on Symbol(sym) is the right thing to do:

For the other primitive/wrapper types the following conventions apply:
   new Wrapper(prim)   //always creates a new Wrapper instances wrapping the supplied primitive value 
   Wrapper(prim)            //always returns a primitive value derived by coercing the argument to the appropriate primitive type. Returns prim if same type.

At [1] we made different decisions for symbols and Symbol wrappers :
  new Symbol(arg)     // always throws, we don't support explicit creation of Symbol wrapper objects 
  Symbol(arg)              // always returns a new, not previously observed, primitive symbol value

We made new Symbol throw to avoid the silent mistake where somebody uses it thinking they are actually creating a new symbol value rather than a wrapper object.  Instead we decide to make a direct call to Symbol the only way (other than Symbol.for) to access a new previously unobserved symbol value.

Symbol("string") is a symbol factory call,  not a coercion of "string" to a symbol. The argument is not a value to be coerced to  symbol but a string value that is part of the state of the new symbol value. In particular:
   console.log(Symbol("x") === Symbol("x"))  //false, each call to Symbol returns a new unique symbol value

If Symbol(sym) returned sym, that would break the invariant that calling Symbol always produces a new symbol value. Rather that reenforcing the fact the Symbol has its own usage patterns that are different from Number/String/Boolean it would  partially blur that distinction. 

ToString(symbolValue) throws because we don't want people doing string concatenation to a symbol thinking they are manipulating a string property key. 

ToString(symbolWrapper) just does a normal symbolWrapper.toString() call.

It would be consistent with the use of Symbol(foo) to allow Symbol(symbolValue) and to internally perform symbolValue.toString()  [note implicit wrapping via property access) .  However, that would still create a new unique symbol value which probably isn't what the programmer actually intended.  Another silent mistake.

When all these factors are considered, I think what is currently specified is just fine.

Allen

[1]: https://github.com/rwaldron/tc39-notes/blob/master/es6/2013-09/sept-18.md 
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20140211/b5e5431c/attachment.html>
domenic at domenicdenicola.com (2014-02-18T04:31:22.187Z)
On Feb 11, 2014, at 6:40 AM, Claude Pache wrote:

> According to the current version of the ES6 spec [1], `Symbol(desc)`, when `desc` is not `undefined`, coerces its argument to a string and uses it as a description for a newly created symbol. In particular, if `sym` is a symbol, `Symbol(sym)` throws a TypeError (it can't be coerced to string).
> 
> Intuitively, I would expect that `Symbol(sym)` just returns `sym`, just like `Number(num)` returns `num`, or, more generally, just like `Primitive(x)` casts its argument to the corresponding primitive.
> 
> What do you think?

I can't find any explicit mention of this  in the meeting notes [1] where we decided to make Symbol a primitive type with a wrapper class.  However, I made the appropriate changes to the spec. immediately after that meeting when the discussion was fresh in my mind and I still think that throwing on Symbol(sym) is the right thing to do:

For the other primitive/wrapper types the following conventions apply:

```js
new Wrapper(prim)   //always creates a new Wrapper instances wrapping the supplied primitive value 
Wrapper(prim)            //always returns a primitive value derived by coercing the argument to the appropriate primitive type. Returns prim if same type.
```

At [1] we made different decisions for symbols and Symbol wrappers :

```js
  new Symbol(arg)     // always throws, we don't support explicit creation of Symbol wrapper objects 
  Symbol(arg)              // always returns a new, not previously observed, primitive symbol value
```

We made new Symbol throw to avoid the silent mistake where somebody uses it thinking they are actually creating a new symbol value rather than a wrapper object.  Instead we decide to make a direct call to Symbol the only way (other than Symbol.for) to access a new previously unobserved symbol value.

Symbol("string") is a symbol factory call,  not a coercion of "string" to a symbol. The argument is not a value to be coerced to  symbol but a string value that is part of the state of the new symbol value. In particular:

```js
   console.log(Symbol("x") === Symbol("x"))  //false, each call to Symbol returns a new unique symbol value
```

If Symbol(sym) returned sym, that would break the invariant that calling Symbol always produces a new symbol value. Rather that reenforcing the fact the Symbol has its own usage patterns that are different from Number/String/Boolean it would  partially blur that distinction. 

ToString(symbolValue) throws because we don't want people doing string concatenation to a symbol thinking they are manipulating a string property key. 

ToString(symbolWrapper) just does a normal symbolWrapper.toString() call.

It would be consistent with the use of Symbol(foo) to allow Symbol(symbolValue) and to internally perform symbolValue.toString()  [note implicit wrapping via property access) .  However, that would still create a new unique symbol value which probably isn't what the programmer actually intended.  Another silent mistake.

When all these factors are considered, I think what is currently specified is just fine.

[1]: https://github.com/rwaldron/tc39-notes/blob/master/es6/2013-09/sept-18.md