Can `new` be optional?

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

Can `new` be optional?

Michael Lewis
Why can't `new` be optional?

I found this thread, https://esdiscuss.org/topic/obsoleting-the-new-keyword, but it's so long (and 9 years old), I didn't read much of it.  Can someone summarize the current status of this decision?

On a side note, it seems the ES Steering Committee needs a wiki - a place to document important decisions.  I feel like the MDN web docs would be a good place to put all levels of documentation.  I'm going to make a new thread about docs, it's so important...

Anyway, in my ES5 "classes", I use an `if (!(this instanceof Class)) return new Class()` (similar to what jQuery does) to avoid having to use `new`.  I feel like there should be a way to build this into the language.

I have a `View()` class that is invoked a lot:

```
View().append({
    one: View(...),
    two: View(View(...), View(...))
});
```

And, being forced to write `new View()` every time is actually the only reason why I won't switch to native classes, at the moment.


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

Re: Can `new` be optional?

Michał Wadas
This was covered by "call constructor" proposal, but unfortunately, it was withdrawn. 


Status: "Withdrawn: can be solved with decorators" - https://github.com/tc39/proposals/blob/master/inactive-proposals.md

On 5 Nov 2017 12:55 pm, "Michael Lewis" <[hidden email]> wrote:
Why can't `new` be optional?

I found this thread, https://esdiscuss.org/topic/obsoleting-the-new-keyword, but it's so long (and 9 years old), I didn't read much of it.  Can someone summarize the current status of this decision?

On a side note, it seems the ES Steering Committee needs a wiki - a place to document important decisions.  I feel like the MDN web docs would be a good place to put all levels of documentation.  I'm going to make a new thread about docs, it's so important...

Anyway, in my ES5 "classes", I use an `if (!(this instanceof Class)) return new Class()` (similar to what jQuery does) to avoid having to use `new`.  I feel like there should be a way to build this into the language.

I have a `View()` class that is invoked a lot:

```
View().append({
    one: View(...),
    two: View(View(...), View(...))
});
```

And, being forced to write `new View()` every time is actually the only reason why I won't switch to native classes, at the moment.


_______________________________________________
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: Can `new` be optional?

Michael Lewis
Is there a technical limitation, or just an opinion?

If I call an ES6 `class MyClass {}` without new:  `MyClass()`, it throws.  Just change this bit to do whatever `new` was supposed to do.  Problem solved?

On Sun, Nov 5, 2017 at 6:01 AM, Michał Wadas <[hidden email]> wrote:
This was covered by "call constructor" proposal, but unfortunately, it was withdrawn. 


Status: "Withdrawn: can be solved with decorators" - https://github.com/tc39/proposals/blob/master/inactive-proposals.md

On 5 Nov 2017 12:55 pm, "Michael Lewis" <[hidden email]> wrote:
Why can't `new` be optional?

I found this thread, https://esdiscuss.org/topic/obsoleting-the-new-keyword, but it's so long (and 9 years old), I didn't read much of it.  Can someone summarize the current status of this decision?

On a side note, it seems the ES Steering Committee needs a wiki - a place to document important decisions.  I feel like the MDN web docs would be a good place to put all levels of documentation.  I'm going to make a new thread about docs, it's so important...

Anyway, in my ES5 "classes", I use an `if (!(this instanceof Class)) return new Class()` (similar to what jQuery does) to avoid having to use `new`.  I feel like there should be a way to build this into the language.

I have a `View()` class that is invoked a lot:

```
View().append({
    one: View(...),
    two: View(View(...), View(...))
});
```

And, being forced to write `new View()` every time is actually the only reason why I won't switch to native classes, at the moment.


_______________________________________________
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: Can `new` be optional?

Oriol _
In reply to this post by Michael Lewis
> Why can't `new` be optional?

When you call a function, you are using the internal [[Call]] method. When you use the `new` operator, it's the internal [[Construct]] method.

They are different things, so IMO avoiding `new` when you are instantiating is bad practice.

But if you really want to avoid `new` when using ES6 `class` syntax, you can use proxies, e.g.

```js
let MyClass = new Proxy(class MyClass {
  constructor(arg) { this.arg = arg; }
}, {
  apply: (target, thisArg, args) => Reflect.construct(target, args)
});
MyClass(1); // { arg: 1 }
new MyClass(2); // { arg: 2 }
```

--Oriol

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

Re: Can `new` be optional?

Andrea Giammarchi-2
oldie but goldie ?

```js
Object.defineProperty(
  Function.prototype,
  'new',
  {
    configurable: true,
    value(...args) {
      return new this(...args);
    }
  }
);
```





On Sun, Nov 5, 2017 at 11:28 AM, Oriol _ <[hidden email]> wrote:
> Why can't `new` be optional?

When you call a function, you are using the internal [[Call]] method. When you use the `new` operator, it's the internal [[Construct]] method.

They are different things, so IMO avoiding `new` when you are instantiating is bad practice.

But if you really want to avoid `new` when using ES6 `class` syntax, you can use proxies, e.g.

```js
let MyClass = new Proxy(class MyClass {
  constructor(arg) { this.arg = arg; }
}, {
  apply: (target, thisArg, args) => Reflect.construct(target, args)
});
MyClass(1); // { arg: 1 }
new MyClass(2); // { arg: 2 }
```

--Oriol

_______________________________________________
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: Can `new` be optional?

J Decker


On Sun, Nov 5, 2017 at 7:53 AM, Andrea Giammarchi <[hidden email]> wrote:
oldie but goldie ?

```js
Object.defineProperty(
  Function.prototype,
  'new',
  {
    configurable: true,
    value(...args) {
      return new this(...args);
    }
  }
);
```

doesn't make new optional, just moves it, and doesn't apply to 'class'es which the OP is saying.
 




On Sun, Nov 5, 2017 at 11:28 AM, Oriol _ <[hidden email]> wrote:
> Why can't `new` be optional?

When you call a function, you are using the internal [[Call]] method. When you use the `new` operator, it's the internal [[Construct]] method.

They are different things, so IMO avoiding `new` when you are instantiating is bad practice.


Of course it is... with out new, classes throw an exception.

This seems like a really short sighted issue.  Why can't calling a class just invoke it's constructor?

I also don't see how decorators can solve it.

Seems just as arbitrary as the underscore proposal not accepting underscore trailing a number or before or after a decimal.

Maybe, it would be better to ask 'Why does calling a class throw an exception instead of just creating a new instance.
 
But if you really want to avoid `new` when using ES6 `class` syntax, you can use proxies, e.g.

```js
let MyClass = new Proxy(class MyClass {
  constructor(arg) { this.arg = arg; }
}, {
  apply: (target, thisArg, args) => Reflect.construct(target, args)
});
MyClass(1); // { arg: 1 }
new MyClass(2); // { arg: 2 }
```

At the cost of non-zero overhead.
 
--Oriol

_______________________________________________
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: Can `new` be optional?

Logan Smyth
I also don't see how decorators can solve it.

Making to wrapper for class constructor to allow the constructor to callable would be fairly straightforward, e.g.

```
function callable(cls) {
  
function Wrapper(...args) {
    
return Reflect.construct(cls, args, new.target || cls);
  }
  Object.defineProperty(Wrapper, "name", { value: cls.name });
  Object.setPrototypeOf(Wrapper, cls);
  Wrapper.prototype = cls.prototype;
  return Wrapper;
}

const 
Example = callable(class Example {});

Example();
```
and thus potentially
```
@callable
class Example {}
```

I know you said "At the cost of non-zero overhead." but it seems like this would be something engines could optimize more easily than proxies. 

This seems like a really short sighted issue.  Why can't calling a class just invoke it's constructor?

I think the big question for me when discussing this with people is, is it more surprising to throw a clear error in these case, or to do something close but not quite the same as if it were an ES5-style constructor?

```
class Foo {
  constructor() {
    this.foo = 4;
  }
}

var obj = {};
var inst = Foo.call(obj);

// what happens?
// obj.foo => 4 or undefined 
// inst => obj, new object, or undefined
// inst.foo => 4 or undefined
```
To be consistent with ES6 class semantics it has to be that a new instance is returned and `obj` is 100% ignored
 but that are very much not what you'd get if you replaced the class there with `function Foo(){ this.foo = 4; }`. Isn't that its own set of confusing changes?

Specifically for "This seems like a really short sighted issue" I'd say this is the opposite of short-sighted. There's nothing preventing support for this in the future, but if it got added with a behavior that ended up confusing people _more_ than not having it at all, then we'd be stuck with it for good.


On Sun, Nov 5, 2017 at 11:53 AM, J Decker <[hidden email]> wrote:


On Sun, Nov 5, 2017 at 7:53 AM, Andrea Giammarchi <[hidden email]> wrote:
oldie but goldie ?

```js
Object.defineProperty(
  Function.prototype,
  'new',
  {
    configurable: true,
    value(...args) {
      return new this(...args);
    }
  }
);
```

doesn't make new optional, just moves it, and doesn't apply to 'class'es which the OP is saying.
 




On Sun, Nov 5, 2017 at 11:28 AM, Oriol _ <[hidden email]> wrote:
> Why can't `new` be optional?

When you call a function, you are using the internal [[Call]] method. When you use the `new` operator, it's the internal [[Construct]] method.

They are different things, so IMO avoiding `new` when you are instantiating is bad practice.


Of course it is... with out new, classes throw an exception.

This seems like a really short sighted issue.  Why can't calling a class just invoke it's constructor?

I also don't see how decorators can solve it.

Seems just as arbitrary as the underscore proposal not accepting underscore trailing a number or before or after a decimal.

Maybe, it would be better to ask 'Why does calling a class throw an exception instead of just creating a new instance.
 
But if you really want to avoid `new` when using ES6 `class` syntax, you can use proxies, e.g.

```js
let MyClass = new Proxy(class MyClass {
  constructor(arg) { this.arg = arg; }
}, {
  apply: (target, thisArg, args) => Reflect.construct(target, args)
});
MyClass(1); // { arg: 1 }
new MyClass(2); // { arg: 2 }
```

At the cost of non-zero overhead.
 
--Oriol

_______________________________________________
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



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

Re: Can `new` be optional?

Andrea Giammarchi-2
In reply to this post by J Decker
Why does calling a class throw an exception instead of just creating a new instance

backward compatibility and early "rushed" behavior is one of the reasons.

`String() instanceof String` is false and it's just one example.

Because of primitives and `typeof`, `new Symbol` throws too, you are not meant to do that.

Array and Regexp though, have no primitive namespace, but that's old gotcha later specs tried to prevent.

What about `new Date` ? Now that's an instance, while `Date()` is a string.

Using `new` makes your intent unambiguous in a PL where functions can be used as constructors too.

There is also the possibility to create functions that cannot be used as `new`:

```js
const method = {method(){}}.method;

new method; // throws
```

Accordingly, since you have Reflect for all procedural use cases, what is the benefit of not using `new` where it's an instance of that Class you are after?





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