Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ambiguity of the ... operator #18

Closed
caesarsol opened this issue Nov 19, 2017 · 9 comments
Closed

Ambiguity of the ... operator #18

caesarsol opened this issue Nov 19, 2017 · 9 comments

Comments

@caesarsol
Copy link

I think the ... operator could lead to confusion, being it already used for array destructuring and function variadic arguments.

My proposal is to use something more like ?..., that would be consistent with the other proposal #5 on the positional placeholders.

@Haroenv
Copy link

Haroenv commented Jan 18, 2018

What about ...?, implying you're spreading placeholders?

@elycruz
Copy link

elycruz commented Jun 15, 2018

@Haroenv seems to close to spread/rest op syntax (IMO); I.e., ...rest I take it back (lol) I think the solutions for this require more study as there are still other "possible features that could/should-(probably) be considered as part of partial application solution (namely currying in general).

@rbuckton
Copy link
Collaborator

rbuckton commented Apr 2, 2019

The ... token in partial application would be a direct parallel to both function "rest" parameters and call "spread" arguments, as it serves both purposes:

function f(...args) { console.log(JSON.stringify(args)); }
const g = f(1, ...);
g(2, 3); // [1, 2, 3]

Since it is effectively transposed as:

const g = (() => {
  const fn = f;
  const p0 = 1;
  return (...an) => fn(p0, ...an); // <- transposition of `...`
}();

I have also considered allowing ?... to mean "spread ? into the call here":

function f(...args) { console.log(JSON.stringify(args)); }
const g = f(1, ?...);
g([2, 3]); // [1, 2, 3];

As well as allowing ...? to mean "all the rest of the args go here":

function f(...args) { console.log(JSON.stringify(args)); }
const g = f(1, ...?);
g(2, 3); // [1, [2, 3]];

In which case ...?... would be synonymous with ... (and therefore unnecessary).

@nicolo-ribaudo
Copy link
Member

I think that ?... and ...? should be swapped: ...SOMETHING in function calls already is an array spread.

@rbuckton
Copy link
Collaborator

rbuckton commented Apr 2, 2019

@nicolo-ribaudo It's also used for rest in function parameters, and ? is both the argument for the call and the parameter for the resulting function. Its ambiguous either way:

function f(a, b, ...rest) {}
f(a, b, ...spread) {}

const [a, b, ...rest] = ar;
ar = [a, b, ...spread];

const { a, b, ...rest } = obj;
obj = { a, b, ...spread };

Therefore its highly ambiguous in partial application:

const g1 = f(a, b, ...); // both rest and spread (not ambiguous)
const g2 = f(a, b, ...?); // is this a `...rest` or a `...spread`?

If we were to support disambiguating the two, having ... on one side or the other of ? indicates direction and cardinality:

  • ? indicates a "one" binding.
    (i.e. "take the one argument and put it in this one place")
  • ... indicates a "many" binding.
    (i.e. "take the many rest arguments and spread its many elements in this place")
  • ...? indicates a "many-to-one" binding.
    (i.e. "take the many rest arguments (...) and put it in this one place (?)")
  • ?... indicates a "one-to-many" binding.
    (i.e. "take this one argument (?) and spread its many elements this place (...)")

Otherwise we'd need a different syntax to disambiguate direction (i.e. ...<?, ...>?).

In general I believe its simpler to just have ? (and possibly ...) and avoid the complexity/ambiguity of the one-to-many/many-to-one representations.

@rbuckton
Copy link
Collaborator

rbuckton commented Apr 2, 2019

Closing for now as the current proposal draft as removed support for the ... operator. We may reopen this issue for further discussion at a later date, should we decide to reintroduce this support in this or a follow-on proposal.

@rajington
Copy link

rajington commented Jun 26, 2019

In case this gets re-opened, how about just using parens:

macro y = transpiled y = y(a,b) calls f with
f(?) (x) => f(x) a
f(...?) (...x) => f(...x) a, b
f([...?]) (...x) => f([...x]) [a, b]
f({...?}) (...x) => f({...x}) {0: a, 1: b}
f([...(?)]) (x) => f([...x]) [...a]
f({...(?)}) (x) => f({...x}) {...a}

Parens are already commonly used to clear up syntax (e.g. () => {} vs () => ({})), and it feels very easy to remember.

It could also play well with types: foo(...(?: string)) vs foo(...?: string[]) although that example looks much better with _.

@Fenzland
Copy link

Fenzland commented May 6, 2020

I think ?... is better for rest and ...? for spread. Considering ?0, ?1 ... for specific arg, ?... for the rest args are reasonable. On the other hand, ...? for spread is intuitive and far-sighted, we can extend it to ...?0, ...?1 ... in fact, we can assume ...? as shortcut for ...?0 and ... for ...?...

@hax
Copy link
Member

hax commented May 11, 2020

I think having both ...? and ?... are always confusing, we'd better only use ....

f()  // x => f(x)
f(1, ..., 2) // (...x) => f(1, ...x, 2)
f(1, [...], 2) // (...x) => f(1, x, 2)
f(❓1, ...❓2, ...) // (x, y, ...z) => f(x, ...y, ...z)

(I use here for any character we finally decide, personally I prefer % which follow DOS batch script 😆, so use % in follow code example)

Ambiguity only occur if use both % and ..., so we'd better ban it!

f(...%...) // syntax error!
f(...%1...) // much clear what we want

// actually having multiple % is also confusing, we'd better also ban it
f(%, ..., %) // what this mean?
f(%1, ..., %1) // (x, ...y) => f(x, ...y, x)    or
f(%1, ..., %2) // (x, y, ...z) => f(x, ...z, y)   or
// (x, ...y) => f(x, y.slice(0, -1), y[y.length - 1])   ???

Current proposal use f(%1, ..., %2) semantic, but if consider ..., the order is not preserved any more which may cause confusion.

PS. the last semantic could be supported in the future by introducing %^n syntax: f(%1, ..., %^1) (^n is coming from the discussion of slice notation proposal)

PPS. I use %1 instead of %0 because:

  • %0 usually mean the callee if follow shell convention
  • theoretically there is an "implicit first argument" --- thisArg

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

No branches or pull requests

8 participants