Why ES6 introduced classes yet `Symbol` not to be used with `new`?

classic Classic list List threaded Threaded
15 messages Options
Reply | Threaded
Open this post in threaded view
|

Why ES6 introduced classes yet `Symbol` not to be used with `new`?

#!/JoePea
It seems like `new Symbol()` would be inline with the introduction of classes. Why was it chosen not to be constructible? Seems like it would make sense to throw an error on `Symbol()` but not `new Symbol()`. Was it to save three characters of typing?

/#!/JoePea

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Why ES6 introduced classes yet `Symbol` not to be used with `new`?

Oriol _

Probably, because symbols are primitive values, and constructors only create and initialize objects.


So you are supposed to call it as a function instead of as a a constructor.


That said, it might make sense for `new Symbol()` to return a symbol object. But instead, you can use


```javascript

Object(Symbol());

```


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

RE: Why ES6 introduced classes yet `Symbol` not to be used with `new`?

Domenic Denicola
In reply to this post by #!/JoePea

Symbol is not a class.

 

From: es-discuss [mailto:[hidden email]] On Behalf Of /#!/JoePea
Sent: Sunday, August 14, 2016 18:31
To: es-discuss <[hidden email]>
Subject: Why ES6 introduced classes yet `Symbol` not to be used with `new`?

 

It seems like `new Symbol()` would be inline with the introduction of classes. Why was it chosen not to be constructible? Seems like it would make sense to throw an error on `Symbol()` but not `new Symbol()`. Was it to save three characters of typing?


/#!/JoePea


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Why ES6 introduced classes yet `Symbol` not to be used with `new`?

Allen Wirfs-Brock
Because, to be consistent with Number/String/Boolean you would expect `new Symbol()` to create a  Symbol wrapper object.  But we anticipated that if `new Symbol` was allowed many devs (who lacked an understanding of the difference between primitive values and wrapper objects for primitive values) would code `new Symbol()` with the expectation that they were creating a Symbol value. This would be a silent bug so we disallowed `new Symbol()`.


On Aug 14, 2016, at 4:15 PM, Domenic Denicola <[hidden email]> wrote:

Symbol is not a class.
 
From: es-discuss [[hidden email]] On Behalf Of /#!/JoePea
Sent: Sunday, August 14, 2016 18:31
To: es-discuss <[hidden email]>
Subject: Why ES6 introduced classes yet `Symbol` not to be used with `new`?
 
It seems like `new Symbol()` would be inline with the introduction of classes. Why was it chosen not to be constructible? Seems like it would make sense to throw an error on `Symbol()` but not `new Symbol()`. Was it to save three characters of typing?

/#!/JoePea
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

RE: Why ES6 introduced classes yet `Symbol` not to be used with `new`?

Domenic Denicola
I believe, but am not sure, that we also decided we would follow that pattern for any future primitive types, since in general constructing wrapper objects is a bad idea. (I want to say that wrapper objects themselves are a bad idea, but I think the conclusion was more subtle than that... they are an important part of the semantics, it's just unfortunate that they're so easy to create.)

If some enterprising person wants to dig through the meeting notes, there might be some hints there...

> From: Allen Wirfs-Brock [mailto:[hidden email]]
>
> Because, to be consistent with Number/String/Boolean you would expect `new Symbol()` to create a  Symbol wrapper object.  But we anticipated that if `new Symbol` was allowed many devs (who lacked an understanding of the difference between primitive values and wrapper objects for primitive values) would code `new Symbol()` with the  expectation that they were creating a Symbol value. This would be a silent bug so we disallowed `new Symbol()`.

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Why ES6 introduced classes yet `Symbol` not to be used with `new`?

Kris Siegel
Interesting.

Because, to be consistent with Number/String/Boolean you would expect `new Symbol()` to create a  Symbol wrapper object.

Currently Symbol is the only primitive that can't be converted to a string through the use of the + operator, so why the consistency in one place and the lack thereof in another? I understand there isn't really a meaningful representation of Symbol() as a string but I didn't see any particular reason in my cursory look at the past notes for it to throw an exception so I've been curious.

But we anticipated that if `new Symbol` was allowed many devs (who lacked an understanding of the difference between primitive values and wrapper objects for primitive values) would code `new Symbol()` with the expectation that they were creating a Symbol value. This would be a silent bug so we disallowed `new Symbol()`.

Forgive me for the ignorance but what kind of bug would this introduce? Since Symbol() is already an oddball compared to all other built-in objects and primitives would it have been so bad to simply make `new Symbol()` equate to `Symbol()`? I'm not sure you'll get developers to understand the difference between primitives and wrapper objects (still haven't found one yet who understands this in my inner-circle of JS devs that I know at least).


On Sun, Aug 14, 2016 at 9:18 PM, Domenic Denicola <[hidden email]> wrote:
I believe, but am not sure, that we also decided we would follow that pattern for any future primitive types, since in general constructing wrapper objects is a bad idea. (I want to say that wrapper objects themselves are a bad idea, but I think the conclusion was more subtle than that... they are an important part of the semantics, it's just unfortunate that they're so easy to create.)

If some enterprising person wants to dig through the meeting notes, there might be some hints there...

> From: Allen Wirfs-Brock [mailto:[hidden email]]
>
> Because, to be consistent with Number/String/Boolean you would expect `new Symbol()` to create a  Symbol wrapper object.  But we anticipated that if `new Symbol` was allowed many devs (who lacked an understanding of the difference between primitive values and wrapper objects for primitive values) would code `new Symbol()` with the  expectation that they were creating a Symbol value. This would be a silent bug so we disallowed `new Symbol()`.

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Why ES6 introduced classes yet `Symbol` not to be used with `new`?

Claude Pache

Le 15 août 2016 à 07:33, Kris Siegel <[hidden email]> a écrit :

Interesting.

Because, to be consistent with Number/String/Boolean you would expect `new Symbol()` to create a  Symbol wrapper object.

Currently Symbol is the only primitive that can't be converted to a string through the use of the + operator, so why the consistency in one place and the lack thereof in another? I understand there isn't really a meaningful representation of Symbol() as a string but I didn't see any particular reason in my cursory look at the past notes for it to throw an exception so I've been curious.

In short, preventing *implicit* conversion to string is for avoiding silent bugs. Typically, in situation where you expect a string, such as:

```js
foo[somePrefix_' + s] = bar[s]
```

This is not an inconsistency at the language level: implicit conversion to string is done using `.toString()` or `.@@toPrimitve("string")`, which has never been guaranteed to succeed. Example:

```js
var o = Object.create(null)
o + "" // will throw a TypeError
```



But we anticipated that if `new Symbol` was allowed many devs (who lacked an understanding of the difference between primitive values and wrapper objects for primitive values) would code `new Symbol()` with the expectation that they were creating a Symbol value. This would be a silent bug so we disallowed `new Symbol()`.

Forgive me for the ignorance but what kind of bug would this introduce?

Examples:

```js
var s = new Symbol
typeof s // "object", not "symbol"

switch (typeof s) {
case "symbol": // will not match
}
```

and:

```js
var s = new Symbol
var o = { }
o[s] = 42 // the wrapper object is converted to a primitive, 
var s2 = Object.getOwnPropertySymbols(o)[0]
s2 == s // true
s2 === s // false
```


Since Symbol() is already an oddball compared to all other built-in objects and primitives would it have been so bad to simply make `new Symbol()` equate to `Symbol()`? I'm not sure you'll get developers to understand the difference between primitives and wrapper objects (still haven't found one yet who understands this in my inner-circle of JS devs that I know at least).

That would introduce an irregularity in the language, for `new Foo` has always been allowed to return an object only, not a primitive. The fact there is some lack of understanding among developers is not an excuse for increasing the confusion with inconsistent semantics.

The alternative design would have been to specify symbols as true objects rather than primitives. I recall that that alternative has been considered and discussed during the conception of ES6. You have to dig through the archives in order to find why one design was chosen over the other. The only thing I recall is that it was not a trivial decision.

—Claude



On Sun, Aug 14, 2016 at 9:18 PM, Domenic Denicola <[hidden email]> wrote:
I believe, but am not sure, that we also decided we would follow that pattern for any future primitive types, since in general constructing wrapper objects is a bad idea. (I want to say that wrapper objects themselves are a bad idea, but I think the conclusion was more subtle than that... they are an important part of the semantics, it's just unfortunate that they're so easy to create.)

If some enterprising person wants to dig through the meeting notes, there might be some hints there...

> From: Allen Wirfs-Brock [mailto:[hidden email]]
>
> Because, to be consistent with Number/String/Boolean you would expect `new Symbol()` to create a  Symbol wrapper object.  But we anticipated that if `new Symbol` was allowed many devs (who lacked an understanding of the difference between primitive values and wrapper objects for primitive values) would code `new Symbol()` with the  expectation that they were creating a Symbol value. This would be a silent bug so we disallowed `new Symbol()`.

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Why ES6 introduced classes yet `Symbol` not to be used with `new`?

Andrea Giammarchi-2
In reply to this post by Domenic Denicola
FWIW, if `Object(Symbol()) instanceof Symbol` is true, and it is, we can say `Symbol` is just an anomaly in the specs because it acts like other primitive constructors but it throws if used as `new Symbol()`.

Developers that would've written `new Symbol` are the same that write `new Boolean` or `new Number` and `new String`.

If these people don't put minimal effort to better learn/use the programming language I wonder why the rest of the entire community should be penalised with "quirks" like `Symbol` is.

Throw at everything and then, or don't ... and keep it consistent in both good or bad expectations.
I know it's too late for `Symbol` but I hope there won't be other inconsistent primitives/classes added to the lang in the future.

Best Regards


On Mon, Aug 15, 2016 at 12:15 AM, Domenic Denicola <[hidden email]> wrote:

Symbol is not a class.

 

From: es-discuss [mailto:[hidden email]] On Behalf Of /#!/JoePea
Sent: Sunday, August 14, 2016 18:31
To: es-discuss <[hidden email]>
Subject: Why ES6 introduced classes yet `Symbol` not to be used with `new`?

 

It seems like `new Symbol()` would be inline with the introduction of classes. Why was it chosen not to be constructible? Seems like it would make sense to throw an error on `Symbol()` but not `new Symbol()`. Was it to save three characters of typing?


/#!/JoePea


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Why ES6 introduced classes yet `Symbol` not to be used with `new`?

Andrea Giammarchi-2
just to clarify:

I hope there won't be other inconsistent primitives/classes added to the lang in the future.

meaning: I'd rather throw at every attempt to `new Boolean/Number/String` too as amend in the future if "_primitives gotta primitive_" is the idea and `Symbol` throwing was to help developers.





On Mon, Aug 15, 2016 at 9:27 AM, Andrea Giammarchi <[hidden email]> wrote:
FWIW, if `Object(Symbol()) instanceof Symbol` is true, and it is, we can say `Symbol` is just an anomaly in the specs because it acts like other primitive constructors but it throws if used as `new Symbol()`.

Developers that would've written `new Symbol` are the same that write `new Boolean` or `new Number` and `new String`.

If these people don't put minimal effort to better learn/use the programming language I wonder why the rest of the entire community should be penalised with "quirks" like `Symbol` is.

Throw at everything and then, or don't ... and keep it consistent in both good or bad expectations.
I know it's too late for `Symbol` but I hope there won't be other inconsistent primitives/classes added to the lang in the future.

Best Regards


On Mon, Aug 15, 2016 at 12:15 AM, Domenic Denicola <[hidden email]> wrote:

Symbol is not a class.

 

From: es-discuss [mailto:[hidden email]] On Behalf Of /#!/JoePea
Sent: Sunday, August 14, 2016 18:31
To: es-discuss <[hidden email]>
Subject: Why ES6 introduced classes yet `Symbol` not to be used with `new`?

 

It seems like `new Symbol()` would be inline with the introduction of classes. Why was it chosen not to be constructible? Seems like it would make sense to throw an error on `Symbol()` but not `new Symbol()`. Was it to save three characters of typing?


/#!/JoePea


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss




_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Why ES6 introduced classes yet `Symbol` not to be used with `new`?

Rick Waldron

On Mon, Aug 15, 2016 at 4:29 AM Andrea Giammarchi <[hidden email]> wrote:
just to clarify:

I hope there won't be other inconsistent primitives/classes added to the lang in the future.

meaning: I'd rather throw at every attempt to `new Boolean/Number/String` too as amend in the future if "_primitives gotta primitive_" is the idea and `Symbol` throwing was to help developers.





On Mon, Aug 15, 2016 at 9:27 AM, Andrea Giammarchi <[hidden email]> wrote:
FWIW, if `Object(Symbol()) instanceof Symbol` is true, and it is, we can say `Symbol` is just an anomaly in the specs because it acts like other primitive constructors but it throws if used as `new Symbol()`.

Developers that would've written `new Symbol` are the same that write `new Boolean` or `new Number` and `new String`.

If these people don't put minimal effort to better learn/use the programming language I wonder why the rest of the entire community should be penalised with "quirks" like `Symbol` is.

Throw at everything and then, or don't ... and keep it consistent in both good or bad expectations.
I know it's too late for `Symbol` but I hope there won't be other inconsistent primitives/classes added to the lang in the future.

Best Regards


On Mon, Aug 15, 2016 at 12:15 AM, Domenic Denicola <[hidden email]> wrote:

Symbol is not a class.

 

From: es-discuss [mailto:[hidden email]] On Behalf Of /#!/JoePea
Sent: Sunday, August 14, 2016 18:31
To: es-discuss <[hidden email]>
Subject: Why ES6 introduced classes yet `Symbol` not to be used with `new`?

 

It seems like `new Symbol()` would be inline with the introduction of classes. Why was it chosen not to be constructible? Seems like it would make sense to throw an error on `Symbol()` but not `new Symbol()`. Was it to save three characters of typing?


/#!/JoePea


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Why ES6 introduced classes yet `Symbol` not to be used with `new`?

Allen Wirfs-Brock
In reply to this post by Claude Pache

On Aug 14, 2016, at 11:33 PM, Claude Pache <[hidden email]> wrote:

The alternative design would have been to specify symbols as true objects rather than primitives. I recall that that alternative has been considered and discussed during the conception of ES6. You have to dig through the archives in order to find why one design was chosen over the other. The only thing I recall is that it was not a trivial decision.

The "symbols are true objects” approach was fully spec’ed in ES6 drafts before ultimately being abandoned. 

As Claude says, the history is all in the archives.

Allen


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Why ES6 introduced classes yet `Symbol` not to be used with `new`?

Allen Wirfs-Brock
In reply to this post by Andrea Giammarchi-2

> On Aug 15, 2016, at 1:27 AM, Andrea Giammarchi <[hidden email]> wrote:
>
> FWIW, if `Object(Symbol()) instanceof Symbol` is true, and it is, we can say `Symbol` is just an anomaly in the specs because it acts like other primitive constructors but it throws if used as `new Symbol()`.
>
> Developers that would've written `new Symbol` are the same that write `new Boolean` or `new Number` and `new String`.
>
> If these people don't put minimal effort to better learn/use the programming language I wonder why the rest of the entire community should be penalised with "quirks" like `Symbol` is.


The difference is that unlike Number/String/Boolean, there is not a literal syntax for creating Symbol values. For those primitive types that  have a literal representation, it is very rare to ever need to explicitly instantiate a wrapper object via `new` and hence the there is little chance confusing the designation of a primitive value with instantiating a wrapper.

Because Symbol does not have a syntactic literal form, some sort of invocation is required to acquire a new unique primitive Symbol value.  That is where you get the potential for confusion between `Symbol()` and `new Symbol()`.  And minimizing this sort of mistake is not just a matter of needing “better learning”.  Even an experts can have momentary mental slips and type a `new Symbol()` when they really meant `Symbol()`.

In the future, I would expect any new primitive types that have literals to follow the precedent of Number/String/Boolean and any that do not to follow the precedent of Symbol.

Allen
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Why ES6 introduced classes yet `Symbol` not to be used with `new`?

Andrea Giammarchi-2
`Symbol.create()` together with others `Symbol.for()` and company would've been a "least surprise" choice with a `Symbol` spec'd like `Math`, `JSON` or other global objects ... but yeah, we have a precedent now, so I guess in the future will be like that.

On Mon, Aug 15, 2016 at 7:20 PM, Allen Wirfs-Brock <[hidden email]> wrote:

> On Aug 15, 2016, at 1:27 AM, Andrea Giammarchi <[hidden email]> wrote:
>
> FWIW, if `Object(Symbol()) instanceof Symbol` is true, and it is, we can say `Symbol` is just an anomaly in the specs because it acts like other primitive constructors but it throws if used as `new Symbol()`.
>
> Developers that would've written `new Symbol` are the same that write `new Boolean` or `new Number` and `new String`.
>
> If these people don't put minimal effort to better learn/use the programming language I wonder why the rest of the entire community should be penalised with "quirks" like `Symbol` is.


The difference is that unlike Number/String/Boolean, there is not a literal syntax for creating Symbol values. For those primitive types that  have a literal representation, it is very rare to ever need to explicitly instantiate a wrapper object via `new` and hence the there is little chance confusing the designation of a primitive value with instantiating a wrapper.

Because Symbol does not have a syntactic literal form, some sort of invocation is required to acquire a new unique primitive Symbol value.  That is where you get the potential for confusion between `Symbol()` and `new Symbol()`.  And minimizing this sort of mistake is not just a matter of needing “better learning”.  Even an experts can have momentary mental slips and type a `new Symbol()` when they really meant `Symbol()`.

In the future, I would expect any new primitive types that have literals to follow the precedent of Number/String/Boolean and any that do not to follow the precedent of Symbol.

Allen


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Why ES6 introduced classes yet `Symbol` not to be used with `new`?

Alexander Jones
In reply to this post by Allen Wirfs-Brock
On 15 August 2016 at 19:20, Allen Wirfs-Brock <[hidden email]> wrote:

Because Symbol does not have a syntactic literal form, some sort of invocation is required to acquire a new unique primitive Symbol value.  That is where you get the potential for confusion between `Symbol()` and `new Symbol()`.  And minimizing this sort of mistake is not just a matter of needing “better learning”.  Even an experts can have momentary mental slips and type a `new Symbol()` when they really meant `Symbol()`.

Honestly, I think this kind of basic type error is something which is so trivially catchable at a very early stage when you have even a semblance of static analysis. `new Symbol()` should give you an object of class Symbol, and `Symbol()` should give you a symbol - and TypeScript even without annotations is going to give you a pretty strong warning. IMO it's a bit ugly to break the pattern of primitive wrappers being newable for the sake of saving programming errors, when the analyzer can do a much more complete job anyway.

```js
let s1 = String("banana"); // string
let s2 = new String("banana"); // object
let o = {banana: 2};
o[s1];
o[s2]; // red squiggly: An index expression argument must be of type 'string', 'number', 'symbol', or 'any'.
```

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Why ES6 introduced classes yet `Symbol` not to be used with `new`?

Andrea Giammarchi-2
It's too late for Symbol, but I agree with Alexander.

Anyway, this is my a summary:

  * `Symbol` is not a class and `new Symbol` throws
  * `Object(Symbol())` is possiboe and it's also an `instanceof Symbol`
  * `Symbol` cannot be implicitly converted to a string so `"" + Symbol()` throws
  * `String(Symbol())` works though
  * `{[Symbol()]: value}` is by default enumerable, even if kinda born to be defined on prototypes
  * `for/in` and `for/of` won't show it though ... but ...
  * `Object.assign` will copy them over

As a developer, I would've stick with a basic `String` variant that inherits `toString` via `Object` prototype and by default is not enumerable, at least the latter part would've been the only quirk, but a useful one.

Instead, all the effort put to make it right became quite confusing so that, from time to time, somebody will ask about `new Symbol` VS `Object`, about `Object.assign` symbols clashes (iterators and others) and the fact `JSON` silently ignores them as if these are `undefined` and these are not even passed to the `replacer` like other enumerable keys.

Yes, there is history, discussions and reasons behind `Symbol` done in this way, but I bet we can all agree it didn't came out exactly as a "unicorn".

Best Regards


On Tue, Aug 16, 2016 at 12:03 AM, Alexander Jones <[hidden email]> wrote:
On 15 August 2016 at 19:20, Allen Wirfs-Brock <[hidden email]> wrote:

Because Symbol does not have a syntactic literal form, some sort of invocation is required to acquire a new unique primitive Symbol value.  That is where you get the potential for confusion between `Symbol()` and `new Symbol()`.  And minimizing this sort of mistake is not just a matter of needing “better learning”.  Even an experts can have momentary mental slips and type a `new Symbol()` when they really meant `Symbol()`.

Honestly, I think this kind of basic type error is something which is so trivially catchable at a very early stage when you have even a semblance of static analysis. `new Symbol()` should give you an object of class Symbol, and `Symbol()` should give you a symbol - and TypeScript even without annotations is going to give you a pretty strong warning. IMO it's a bit ugly to break the pattern of primitive wrappers being newable for the sake of saving programming errors, when the analyzer can do a much more complete job anyway.

```js
let s1 = String("banana"); // string
let s2 = new String("banana"); // object
let o = {banana: 2};
o[s1];
o[s2]; // red squiggly: An index expression argument must be of type 'string', 'number', 'symbol', or 'any'.
```


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss