samuelgoto / proposal-block-params

A syntactical simplification in JS to enable DSLs
204 stars 8 forks source link

Will this corner ourselves? #26

Open samuelgoto opened 6 years ago

samuelgoto commented 6 years ago

This came up multiple times during the review, so kicking off a thread to allow commenting.

The problem comes down to:

If we bake this in, do we corner ourselves from ever exposing new control structures (e.g. match () {})?

samuelgoto commented 6 years ago

That's a good question, and that's the sort of challenge that would be a massive deal breaker to me. I don't think this feature would carry its weight if it meant that we would not be able to use the syntactical space anymore for anything.

I think it is exploring further, though, the consequences of a couple of paths:

  1. user defined form shadows built-in ones
  2. sigils (e.g. for! {})

It is important to note that the current built-in ones can't be shadowed because they are reserved keywords. So, you can't override for or if or while (which I think is working as intended), but you could override ones that are not reserved keywords (e.g. until or match).

For example:

function match () {
  // ...
}

match (expr) {
  // ... can a parser tell the difference between a built-in match() and a
  // userland match performantly?
}

Whereas this would certainly address the challenge (but with the cost of the added sigil):

match! (expr) {
  // ... ah, ok, now I can see the difference ....
}

Do any of these options sound plausible?

Any other options?

ljharb commented 6 years ago
match -> {
}

match (a, b) -> {
}

?

rwaldron commented 6 years ago
 // can a parser tell the difference between a built-in match() and a
 // userland match performantly?

It's not about telling the difference, it's about preventing the language from ever claiming a new "contextual keyword" for a keyword + block form. To clarify, the current design effectively ends any future additions that use the following grammar:

Keyword [no LineTerminator here] {

...Where "keyword" is any word that's not one of the existing reserved keywords. This pattern has been described as a "contextual keyword" in previous cases, eg. module { }. This occurs because there will never be a way to safely introduce a new keyword + block form that doesn't potentially break some code that uses that word in a CallExpression + block param.

samuelgoto commented 6 years ago

To clarify, the current design effectively ends any future additions that use the following grammar:

Just to make sure I understand, but option 2 outlined above would address this, right?

dissimulate commented 6 years ago

I don't see how this proposal poses a new problem here. What's the difference between this situation and me defining and using a regular function called match now? Are there any situations where I could declare a variable and reference a different function by the same name with the keyword {} format?

I would think it'd either shadow or throw a SyntaxError when you try to declare the function.

function with () {}
// Uncaught SyntaxError: Unexpected token with
function alert () {}

alert () {
  // shadows window.alert
}
borela commented 6 years ago

Any new keyword added to the language at this point would give some sort of headache, if match was added today as a keyword, it would break a lot of stuff.

I personally think that it proposal actually facilitates match to be implemented(without the sigil) because it could be added as core global function.

ljharb commented 6 years ago

We're not going to add new builtin globals like that, though - that's just a nonstarter.

borela commented 6 years ago

Why not? Considering that a keyword would break existing code.

ljharb commented 6 years ago

For one, it creates web compatibility risk - the chance that nobody's made a global variable called "match" (or an HTML element with the id of "match") is pretty slim.

borela commented 6 years ago

Make it available in strict mode only, any code that reference match in strict mode without declaring it prior to the match proposal would be buggy already.

ljharb commented 6 years ago

Some members of the committee (namely, browsers) will strongly object to making things available in strict mode only; and no, current strict code could reference a match global and work fine.

borela commented 6 years ago

current strict code could reference a match global and work fine.

I see, this could definitely be done by mixing non strict code. Is there any other cases?

ljharb commented 6 years ago

Strictness has nothing to do with it. window.match = true is perfectly valid strict code, and it creates a global variable. Separately, any HTML element's ID will become a global variable if it's an identifier, so <div id="match"></div> would cause similar issues.

borela commented 6 years ago

Thank you I wasn't aware of this, I always used getElementById; one more trap to remember.

Alhadis commented 5 years ago

Of course this is going to break forwards compatibility. Even with an unambiguous block syntax, users still have to import these functions from somewhere, meaning we end up with breakage waiting to happen:

import {if} from "./foo.mjs";
        ^^

SyntaxError: Unexpected reserved word
    at Loader.moduleStrategy (internal/modules/esm/translators.js:48:18)
    at async link (internal/modules/esm/module_job.js:38:36)

Replace if in the above example with unless or when or anything else that might make a nifty new keyword, and should be able to see what we're getting ourselves into.

Moreover, I don't see any real benefit here, aside from saving a few keystrokes and looking more "aesthetically pleasing" (to some… IMHO, it looks alien and confusing).

Separately, any HTML element's ID will become a global variable

Ahhh, good ol' DOM level 0. ❤️ May you never die.