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

Too much question mark #21

Open
ysaskia opened this Issue Dec 27, 2017 · 21 comments

Comments

Projects
None yet
@ysaskia
Copy link

ysaskia commented Dec 27, 2017

I really love this proposal and I want it to be implemented but... I believe that the question mark is not a good choice. We already have the existing ternary operator and probably later we'll have the implementation of the 2 proposals optional chaining and nullish coalescing. Obviously, the futur js code will looks like very ugly hieroglyphs.

Why not an asterisk or another special character ?

const add = (x, y) => x + y;
const mul = (x, y) => x * y;

10
  |> add(1, *)
  |> mul(*, 2)

It's just my personal opinion but maybe it's just me.
Too much question marks...

@ysaskia

This comment has been minimized.

Copy link

ysaskia commented Dec 27, 2017

Maybe this silly example can help

// partial + ternary operator + optional chaining + nullish coalescing in the same call.
const doStuff = (x, y, z, w) => {
  // do something with x, y, z and w
}

const curriedDoStuff = doStuff(?, v.?a ?? 0, v.b > 10 ? 10 : 0, ?);

And I think we can easily be more cryptic.

@flying-sheep

This comment has been minimized.

Copy link

flying-sheep commented Jan 9, 2018

Just to name an alternative: how about the dot, like in R?

const curriedDoStuff = doStuff(., v.?a ?? 0, v.b > 10 ? 10 : 0, .)
const curriedDoStuff = doStuff(*, v.?a ?? 0, v > 10*b ? 10 : 0, *)

but the * is nice, and both are better than the ?

@borela

This comment has been minimized.

Copy link

borela commented Jan 19, 2018

How about something like a string format? It would allow you to specify which argument you want:

const curriedDoStuff = doStuff(%, v.?a ?? 0, v > 10*b ? 10 : 0, %...)
const curriedDoStuff = doStuff(%0, v.?a ?? 0, v > 10*b ? 10 : 0, %1)

const curriedDoStuff = doStuff({0}, v.?a ?? 0, v > 10*b ? 10 : 0, {...})
const curriedDoStuff = doStuff({0}, v.?a ?? 0, v > 10*b ? 10 : 0, {1})
@CrossEye

This comment has been minimized.

Copy link

CrossEye commented Jan 20, 2018

I really, really wish that the underscore character was available!

@ShadRPG

This comment has been minimized.

Copy link

ShadRPG commented Jan 25, 2018

Since it cannot be used as a variable character, I propose using the arobase character @ for place-holder and @@ for rest placeholder.
We then even use numbered place holder (@1, @2, etc.) to change the order of expected arguments in the resulting function like:

const f = (x,y,z,w) => ( (x * y) - ( z *w) )

// "ordered placeholders"
const g = f(@, 12, @, 14)
 // then g = ( a1, a2 ) => f( a1, 12, a2, 14)
g(11, 13) === f(11, 12, 13, 14)

// "rest placeholder"
const h = f( @@, 14)
 h(11, 12, 13) === f(11, 12, 13, 14)

// "numbered placeholders"
const k = f( @3, @1,  13, @2 ) 
      // equivalent to
const k = ( a1 , a2, a3) => f( a3, a1, 13, a2)

 k(21, 22, 23) === f( 23, 21, 13, 22 )

// even
lodash_filter( @2, @1) == ramda_filter
lodash_filter == ramda_filter(@2,@1)

Moreover, @ naturally sounds like "arg" (ok pittyful argument :P)

@ShadRPG

This comment has been minimized.

Copy link

ShadRPG commented Jan 25, 2018

Moreover, @0 could represent the complete arguments passed to the partial function.
Cannot think of a use case but could be possible

@rbuckton

This comment has been minimized.

Copy link
Collaborator

rbuckton commented Jan 25, 2018

Since it cannot be used as a variable character, I propose using the arobase character @ for place-holder

This would be ambiguous with future support for decorators on arrow functions and function expressions.

@ShadRPG

This comment has been minimized.

Copy link

ShadRPG commented Jan 28, 2018

Well, the question mark is already in use and for 90% of time it's used to deal with null values ( x==null ? 0 : x ) or optional properties on objects, so it makes complete sense to use it on both proposals with ?? and object.prop?.value......
However it makes no sense to use it as new partial operator which is totally different thing: it is actually more a decorator thing than an operator thing!
Since decorators are meant to modify the surrounding code, I found it leggit to use a decorator-like synthax for partial application synthax.

So I propose finally:

  • @_ for ordered placeholders
  • @1, @2, @3,... for numbered placeholders, which define order of arguments on the created function.
  • @... for the "rest" placeholder

Finally, all of this could be short synthax for decorators, for example: @partial(), @partial(1), @partial(...)

@rbuckton

This comment has been minimized.

Copy link
Collaborator

rbuckton commented Jan 28, 2018

Interesting single-character tokens on a standard keyboard already have a use in JavaScript, unfortunately:

  • ~ - ones' complement (prefix)
  • ! - boolean negation (prefix)
  • @ - decorators (prefix)
  • # - private name (prefix)
  • \ - escape (prefix)
  • % - modulo (infix)
  • ^ - bitwise XOR (infix)
  • & - bitwise AND (infix)
  • * - multiplication (infix), yield (prefix/infix), generator methods (prefix)
  • - - numeric negation (prefix), subtraction (infix)
  • + - numeric plus (prefix), addition (infix)
  • | - bitwise OR (infix)
  • : - object assignment, label (prefix), conditional (ternary)
  • ; - statement separator (postfix)
  • < - less than (infix)
  • > - greater than (infix)
  • / - division (infix), regexp (prefix+postfix)
  • . - property access (infix), decimal number (prefix)
  • ` - template literal (prefix+postfix)
  • ' - single quote (prefix+postfix)
  • " - double quote (prefix+postfix)
  • ( ) - parens (prefix+postfix)
  • { } - block/object literal (prefix+postfix)
  • [ ] - array (prefix+postfix), element access (postfix)
  • $ - identifier
  • _ - identifier
  • ? - conditional (ternary)

Anything that is a prefix token is out due to forwards incompatibility with possible future features such as positional placeholders. Balanced tokens (such as `, ', ", ( ), { }, and [ ]) are out due to parsing issues with lookahead. Identifiers (like $ and _) are out as they are valid existing syntax. That leaves us with only infix and ternary tokens: %, ^, &, |, <, >, and ?. I ruled out & as I have a strawman for a "pass-by-reference" proposal that would leverage & for consistency with other languages. I ruled out the |, <, and > characters as they could be confusing when paired with pipeline (and any possible future backpipe <| operator). That leaves us with ?, % and ^.

Of the remaining three characters, ? seems the most like a "what goes here?" token and is the main reason I chose it for the proposal.

As to ambiguity with other proposals, the ? character is currently used in two proposals:

  • Optional chaining (as ?.)
  • Nullish coalesce (as ??)

The optional chaining proposal is one reason why I did not allow ?.x() as a means of marking the this receiver for a placeholder. However, it looks like optional chaining may be changing their tokens for consistency either to ??. or ?... If that is the case, the parsing ambiguity goes away and is instead limited only to possible user confusion (in which case the ??. token for optional chaining would be preferred), meaning that using ? as the receiver becomes a possibility.

As with the optional chaining proposal, the coalesce proposal is considering changing their token to ??: which removes even more ambiguity.

As far as "too many question marks" that all depends on coding style. You can already have perfectly legal javascript with +a + b++ + ++ c or [+[]][++[]] - +[] + []++ (though I obviously wouldn't recommend such practice). I imagine most uses of this sigil when combined with other uses of ? will not be no more complex or hard to read than any other token we would choose:

ar |> map(?, x => x > 0 ? true : false);
ar |> map(?, x => x ?? "missing");

As such, I believe that ? is still the best token for this proposal.

@rbuckton

This comment has been minimized.

Copy link
Collaborator

rbuckton commented Jan 28, 2018

Also, regarding using * or other infix operators:

I have considered eventually proposing an "operator function" shorthand syntax to pair with pipeline and partial application as something like ar |> map(?, {*} 2) as a shorthand for ar |> map(?, (x) => x * 2) and wanted to avoid confusion with such operations.

I haven't put this proposal before the committee yet as that would be far too much syntax to propose all at once.

@ShadRPG

This comment has been minimized.

Copy link

ShadRPG commented Jan 28, 2018

Ok..... as I understand it, the @ is for decorators, but a decorator has the form @valid_function_identifier
; since a single number is not a valid identifier, nor is the @ character or the three-dots, we can use
the following:

  • @ for ordered placeholders (will always be followed by , or a ) because we are in a function call expression, so not a decorator)
  • @1, @2, @3,... for numbered placeholders, which define order of arguments on the created function.
  • @... for the "rest" placeholder^

I admit I didn't understand this sentence

Anything that is a prefix token is out due to forwards incompatibility with possible future features such as positional placeholders

and I agree that the question mark is the best token if we cannot do anything against it.

@rbuckton

This comment has been minimized.

Copy link
Collaborator

rbuckton commented Jan 28, 2018

I'm worried that using @ would be ambiguous with other proposals in progress (such as value types and suffix notation) when combined with decorators and would also limit us with future directions for this feature.

@littledan

This comment has been minimized.

Copy link
Member

littledan commented Jan 29, 2018

@rbuckton I appreciate this thorough analysis. Have you considered using multiple character tokens?

@ljharb

This comment has been minimized.

Copy link
Member

ljharb commented Jan 29, 2018

or even <?>

@rbuckton

This comment has been minimized.

Copy link
Collaborator

rbuckton commented Jan 30, 2018

@littledan Other than for ..., no. I didn't feel it was necessary.

@ljharb I would be concerned that this would be confusing if I ever attempted to introduce shorthand operator functions.

I considered (?) as a syntax to attempt to bind the this receiver but it feels too fragile:

// ok
(?).x(); // a => a.x()
(?).x(?); // (a, b) => a.x(b)

// not ok
(?).x.y();
(?)();
x((?));
@Mouvedia

This comment has been minimized.

Copy link

Mouvedia commented Feb 24, 2018

or even <?>

@ljharb I gotta say it would improve the readability a bunch but it seems over the top to me, it should be simpler.

const addOne = add(1, <?>);
addOne(2); // 3

const addTen = add(<?>, 10);
addTen(2); // 12

let newScore = player.score
  |> add(7, <?>)
  |> clamp(0, 100, <?>);
@scf4

This comment has been minimized.

Copy link

scf4 commented Mar 29, 2018

I think the contrived example in the OP would look just as confusing with any other syntax.

IMO ? is perfect, but * is the best of all the alternatives proposed. Both * and ? are universal wildcard symbols.

@rbuckton

This comment has been minimized.

Copy link
Collaborator

rbuckton commented Mar 29, 2018

Unfortunately * has too overloaded of a meaning to be used, and if we ever considered allowing ?() or ?[x]() (per #23 (comment)), then it would conflict with yield/yield *. If I had to choose another token with a placeholder-like semantic meaning I would probably choose % given its use in string expansion (a la printf and console.log) and environment variable expansion on some platforms.

@mAAdhaTTah

This comment has been minimized.

Copy link

mAAdhaTTah commented Mar 29, 2018

@rbuckton I like %; would %this.map(x => x + 1) work as well (related to #23).

@js-choi

This comment has been minimized.

Copy link

js-choi commented Mar 29, 2018

% is a great idea for a placeholder. Clojure also uses % for its bare anonymous-function form’s placeholders. For instance, Clojure #(+ % 5) is equivalent to Clojure (fn [x] (+ x 5)).

(As an aside, % also may be a good choice for the placeholder of the alternative smart-pipelines proposal, too—perhaps one more palatable than its current placeholder #. I’ll add it to the table in tc39/proposal-pipeline-operator#91. With the smart pipelines proposal, +> f(%, 5) would be equivalent to x => f(x, 5) (or this partial-application proposal’s f(?, 5)). Likewise, +> %.map(f) would be equivalent to x => x.map(f) (or this proposal’s %this.map(f)).)

@mlanza

This comment has been minimized.

Copy link

mlanza commented Jun 13, 2018

Semantically, ? just feels right -- better than % or * or something else.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment