Skip to content
This repository has been archived by the owner on Jan 25, 2022. It is now read-only.

Should “optional new” be implemented? #22

Closed
claudepache opened this issue Jul 26, 2017 · 11 comments
Closed

Should “optional new” be implemented? #22

claudepache opened this issue Jul 26, 2017 · 11 comments

Comments

@claudepache
Copy link
Collaborator

claudepache commented Jul 26, 2017

That is:

new Foo?.()

The ongoing refactoring of Issue #20 will not allow that construct at first, because that would add complications in the grammar, and it is practically unused in CoffeeScript (#17). So, it is probably not worth.

However, If you have strong use cases for new, please share them

@claudepache
Copy link
Collaborator Author

Apart the absence of use cases, I have the following additional arguments against it:

  • A complication in the mental model for short-circuiting due to non-strict left-to-right evaluation order of new. The simple rule for short-circuiting is: “if the LHS of the operator is null, do not evaluate its RHS”. However, in expressions like new a?.() and new a?.b(), if a is null, the new operator will not be evaluated, even if the keyword is found on the left of ?.
  • Technically, a complication in the grammar, due to the coexistence of argument-less constructors new a and function invocations b() with similar precedence. That would force to duplicate the rules for OptionalExpression, in the same way that the current spec has both MemberExpression and CallExpression.

So, I’m closing this issue, deciding to drop support for new. But if you have objections, you can still share them in comments.

@ScottRudiger
Copy link
Contributor

@claudepache Sorry to bring up an old discussion that didn't seem to get much attention, but:

Feel free to tell me if this makes no sense, but if there's a use case for function invocation:

func?.(); // is the func non-null? call it.

Just from a naive point of view, there would also be a use case for creating an instance with new (as they're both kind of just function calls):

new Class?.(); // is the Class non-null? Create an instance.

However, I can definitely understand if this is not supported due to new undefined throwing TypeError: undefined is not a constructor (in the case where Class is null/undefined).


On the other hand, with the introduction of null coalescing, there's this possible case (admittedly a weird way of writing it):

// flag.js
const someCondition = 1 === 1;

module.exports = () => someCondition; // export some condition that evaluates to true
// NonNullish.js
const flag = require('./flag')();

class NonNullish {
// ...
}

module.exports = flag ? NonNullish : null; // if flag is set, export NonNullish
// Nullish.js
const flag = require('./flag')();

class Nullish {
 //...
}

module.exports = flag ? null : Nullish; // if flag is set, don't export Nullish
// instance.js
const NonNullish = require('./NonNullish');
const Nullish = require('./Nullish');

let instance;
if (Nullish != null)
  instance = new Nullish();
else
  instance = new NonNullish();

// when flag is set to true:
instance instanceof NonNullish // true
// when flag is set to false:
instance instanceof Nullish // true

The example ended up being a bit more lengthy than I first envisioned it, sorry. 😂


But with support for the new keyword and null coalescing, we could replace:

let instance;
if (Nullish != null)
  instance = new Nullish();
else
  instance = new NonNullish();

with

const instance = new Nullish.?() ?? NonNullish();

On the other hand, I may feel more strongly than others on the importance of "uniformity of treatment" as you mentioned in Issue #10:

For the sake of uniformity of treatment, I think one should include what the spec calls “Left-Hand-Side Expression”, which includes additionally new and tagged templates (which are sort of method/function invocations), e.g. new a?b.c().d[x] `{y}`;

I actually feel more strongly about support for tagged template literals, but that is a discussion for another time/place.

@ScottRudiger
Copy link
Contributor

ScottRudiger commented Mar 3, 2018

Realized shortly after posting that you can currently write this:

const instance = new (Nullish || NonNullish)();

and I'd expect this to be possible w/ null coalescing:

const instance = new (Nullish ?? NonNullish)();

but I'd think this should also be available (perhaps a bit more idiomatic to some):

const instance = new Nullish?.() ?? NonNullish)();

@Mouvedia
Copy link

Mouvedia commented Mar 3, 2018

const instance = new (Nullish || NonNullish)();

That's what I am currently doing:

throw new (self[type] || self.Error)(msg);

I didn't feel the need of anything fancy. Furthermore ?[] is not valid cf #5.

@ScottRudiger
Copy link
Contributor

ScottRudiger commented Mar 3, 2018

I didn't feel the need of anything fancy. Furthermore ?[] is not valid cf #5.

Sorry @Mouvedia, not sure what you mean. I realize there are problems with ?[ and ?(. How does that apply here?

I'm honestly not sure how you're using this, but it seems it's another use case! Would it be helpful for clarity if

throw new (self[type] || self.Error)(msg);

could also be written

throw new (self?.[type] ?? self?.Error ?? Error)(msg);

in case of self === undefined?

@Mouvedia
Copy link

Mouvedia commented Mar 3, 2018

How does that apply here?

Because my example features brackets: self[type].

@claudepache
Copy link
Collaborator Author

@ScottRudiger

Would it be helpful for clarity if

throw new (self[type] || self.Error)(msg);

could also be written

throw new (self?.[type] ?? self?.Error ?? Error)(msg);

in case of self === undefined?

Sure, it can. (There is no “optional new”, here.)


The use case for ”optional new” should be sufficiently strong in order to justify the significant complication needed to specify it.

@ScottRudiger
Copy link
Contributor

Thanks, I feel better about this direction now. 👍

@noscripter
Copy link

@ScottRudiger

Would it be helpful for clarity if

throw new (self[type] || self.Error)(msg);

could also be written

throw new (self?.[type] ?? self?.Error ?? Error)(msg);

in case of self === undefined?

Sure, it can. (There is no “optional new”, here.)

The use case for ”optional new” should be sufficiently strong in order to justify the significant complication needed to specify it.

What's the meaning of the double question marks ???

@claudepache
Copy link
Collaborator Author

@noscripter

What's the meaning of the double question marks ???

See https://github.com/tc39/proposal-nullish-coalescing

@noscripter
Copy link

@noscripter

What's the meaning of the double question marks ???

See tc39/proposal-nullish-coalescing

Thanks for your quick reply, I found it too.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants