-
Notifications
You must be signed in to change notification settings - Fork 107
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
Bikeshedding the Hack topic token #91
Comments
There's a few choices that use
Also, I find |
FWIW, I really like |
Pipelines will be single-line just as often as multiline; so "points up" and "points at the previous" won't consistently be the same. |
I take it that, if we go down the Hack-style path, we're not trying for any kind of path for the placeholder to be subsumed by @rbuckton's partial application proposal, and therefore should avoid using the same token, is that right? |
My 2c: I personally really like I think the "jQuery problem" is probably overblown for these reasons:
|
Is it at all possible to use |
@mAAdhaTTah I don't think it's possible for partial application to use |
From what I could tell, syntactic partial application could use the same placeholder as Hack style iff syntactic partial application were forbidden in every placeholder-using pipe’s RHS. This could be a footgun—it creates a hidden context dependency between two very different results, which may cause the programmer to accidentally commit a mode error—but if we logically proceed anyway: Proposal 2: Hack Style Only and Proposal 4: Smart Mix would forbid syntactic partial application in the RHS of all pipes—or, rather, the parser would always interpret the presence of a RHS placeholder as a pipe placeholder, not a partial-application placeholder. For instance, if Proposal 3: Split Mix would forbid syntactic partial application in the RHS of Hack pipes. It could also forbid it in the RHS of F-sharp pipes but it could also allow them. If If that analysis is correct, I’ll add it to the original post’s |
I would be very opposed to using any valid identifier - including Shadowing bindings is fine when users explicitly choose the identifier - it would not be ok with me that a magic implicit binding would appear that shadows my code just for using an operator. |
I prefer personally The ambiguity only creeps in when placeholders are nested in further expressions — @gilbert's original example being a placeholder in a ternary expression: It's a truism that nested ASCII operations are difficult to parse, but I think the placeholder is a special case inasmuch as it already bears the application-space cognitive weight of a deferred value within a special lexical scope of a higher order operation (the pipeline). So the situation only becomes complicated when we allow that the placeholder be used as an operand within a further expression nested inside a pipeline. Might it be worth outlawing that particular condition? — that is to say, a placeholder must be standalone, invocable only with In passing, I am firmly against the idea that an otherwise valid generic reference (like |
What about parameters with a name ? anArray
|array> pickEveryN(array, 2)
|array> array.filter(...)
|filteredArray> makeQuery(filteredArray)
|query> await readDB(query, config)
... Then one could write something like this: anArray
|$> pickEveryN($, 2)
|$> $.filter(...)
|$> makeQuery($)
|$> await readDB($, config)
... I think this would improve code readability, as there may be a lot of transformations applied. If I want to read one particular line, I won't know what's passed to the function and what's for. Other proposal, reuse arrow functions : [edit: actually, I noticed this is proposal 1] anArray
|> array => pickEveryN(array, 2)
|> array => array.filter(...)
|> filtered => makeQuery(filtered)
... I like this proposal because it can be used with destructuring and stuff like this, while being readable. There are probably a lot of issues with those proposals, but my main idea is that variables like "$" or "^^" lack of readability and are not really elegant (from my point of view). |
Whichever token we choose is going have an effect on the placeholder syntax, either by producing two different placeholder syntaxes (which I'd prefer to avoid), by superseding the placeholder syntax (effectively killing it), or by forcing its hand (requiring it to use the same token). We should probably decide which approach we're taking and keep that in mind as we bikeshed the token for use in the pipeline. @bisouduperou I think we ran into problems with a similar proposal for x |$> pickEveryN($, 2) could be parsed as: x | ($ > pickEveryN($, 2)) |
Reusing arrow functions’ arrow works very well for most purposes, but not for |
Honestly I just really hope any form that has a placeholder variable of any shape or spelling gets adopted, because it adds tremendous power and flexibility to an operator that would otherwise be much more limited and constrained... Thanks for letting me add my 2c. |
In #84 (comment) I used a |
Ok, if |
@gilbert I was also thinking about |
Let's try to not end up with smileys please |
Ah, For what it’s worth, Perl 6 actually turns Perl 5’s I am in no way suggesting that an implicit topic variable be a thing in JavaScript beyond Pipe Proposal 2/3/4, though it’s pretty fun to think about. |
@gilbert tbqh, i very strongly would object to any valid identifier there - it’s not just about “commonly used” for me, it’s about “ever used”. |
@ljharb I think such a strong stance to take would make sense if |
Magically introducing an implicit binding that shadows something defined in an outer scope is |
I agree it's implicit, but I would not equate to |
PowerShell also uses // pipes
Get-Files | ForEach-Object { Out-Host $_ };
// catch blocks
try { ... }
catch [System.Exception] {
Out-Host $_.Exception.GetType().FullName;
}
// filters/functions
function Foo {
begin { ... }
process { Out-Host $_; }
end { ... }
} Of course, that's because every variable in PowerShell is prefixed with |
FWIW, Ruby uses this too. If JS were to adopt |
Node's also set precedent with |
There is also Safari Web Inspector’s use of I used to be very against using a valid identifier for a pipe placeholder, but being reminded of Perl and Ruby made me realize that it might not be that weird. Then again, that there is an implicit binding at all in a Proposal-2,3,4 pipe is relatively unprecedented in ES. I plan to have my Babel plugin for Proposal 4 support configuration of what its placeholder is, to encourage experimentation (if its tokenization permits it). What its default placeholder should be, I don’t yet know. Maybe a non-ASCII placeholder by default might be interesting after all, haha. |
I don't think it's about weirdness but about origin. That you don't know about what an operator means is ok. You may don't know what "yield" or "await" means, because those are operators. But a valid identifier is, by default, a variable previously defined somewhere. By adding valid identifiers like "$_", you will need to ask yourself "am I in pipe ?" "does it come from pipe" "is it a global / simple variable?". I deeply encourage to avoid such (little) confusion. While I personnally prefer meaningful placeholders ("$_" is as readable as "let thing = stuff()"), why not using anArray
|> pickEveryN(@, 2)
|> @.filter(...)
|> makeQuery(@)
|> await readDB(@, config)
... |
"Hack pipes favor more common expressions" and "Hack pipes might be simpler to use" seem to apply just as well to that variant of F# pipes as well. |
@mybearworld We are no longer discussing F# pipes. I prefer them too, but Hack Pipes are more likely to actually ship and if you keep arguing we will never get any pipe operator. Further, this issue is only about the token to be used in the case that we move forward with the Hack pipes approach. Your comment doesn't belong here. |
I was responding to the comment above about extending the label syntax. |
What about:
Yeah would be cases like
But can be handled as a valid token if |
That would be ambiguous. |
I'd argue that no pipe operator at all is much better than this abomination. |
@zlumer That argument doesn't belong in this issue either. Read the title. Make that argument in a different issue. |
Hello everybody. I'm not sure if it this was considered already, but it could be interesting to have a dynamically named variable prefixed by a token that tells it is the pipeline token, without eager declaration. const greeting = 'fellow user'
|> `hello ${#user}`
|> #lower.toUpperCase()
const occurences = 'my very long string'
|> [...#string, ...#string]
|> Object.groupBy(#doubledChars, v => v) In this case the token would be a combination of prefix and JS identifier ( Since const greeting = 'fellow user'
|> `hello ${#_}`
|> #_.toUpperCase()
const occurrences = 'my very long string'
|> [...#$, ...#$]
|> Object.groupBy(#$, v => v) My suggestion would be to use The two issues that I see with this approach atm are:
|
This is not so - you can also write |
@pedro00dk trust me! We know! Dont worry, "bikeshedding" issue was created to give space to people to, well, bikeshed. In all honestly, by now, we collected enough bisons that we ran out of combinations of characters and ideas. We should start reaching for egyptian holographic. |
@shicks
Another ASCII option for token prefix could be backslash const greeting = 'fellow user'
|> `hello ${\user}`
|> \lower.toUpperCase()
const occurences = 'my very long string'
|> [...\string, ...\string]
|> Object.groupBy(\doubledChars, v => v) |
A major advantage of the pipe operator is that you don't need to come up with a name for every step. This would get into the way of that. |
@mybearworld |
The majority of pipes would be pretty simple, though. If the operations done in pipes get more complex where having names for the topic would be beneficiary, there are still options without requiring a named topic:
|
its commonness is irrelevant; it would never be acceptable to prevent its usage in any otherwise valid context. |
The |
It would be useful to optionally name the token for handling nested pipes, lest we'd be limited to piping only the immediate pipe's values (without declaring intermediary variables)
one possible unintended ergonomic consequence of |
What about @pedro00dk's |
That would be pretty unintuitive and confusing behavior, I'd say. |
@zaygraveyard a private name is not just a string identifier with a # prefixed - it must always be statically present and can’t be referenced dynamically. |
@ljharb I'm confused, where did I reference a private name dynamically? |
@zaygraveyard hm, on a reread i see that you did not, my apologies. the likelihood of confusion from your proposal, then, seems high :-p |
IMO this feature would be much better with First, the more verbose version, where you specify a name: expr().$ => f1($, etc);
// semantics are as if you did this (but optimized, not using actual lambdas):
($ => f1($, etc))(expr())
// $ is just an example, you can use any variable name, of course
const result = getId()?.id=> find(id, etc).obj=> add(a, b, obj);
// semantics are equivalent to this (but optimized):
const result = (id => id == null ? undefined : (obj => add(a, b, obj))(find(id, etc)))(getId());
// this syntax is generic enough to also let you not want to return a value
getObj()?.obj=> { if (!obj.valid) return; log(obj.name?.name=> uppercase(name)); };
// means:
(obj => { if (obj == null) return;
if (!obj.valid) return; log((name => name == null ? undefined : uppercase(name))(obj.name));
})(getObj()); To make it even more succinct, make specifying the name optional. getObj().name?.=> log(name);
// equivalent to:
getObj().name?.name=> log(name);
baz(foo().=> bar($));
// equivalent to:
baz(foo().$=> bar($));
// meaning:
baz(bar(foo())) |
The |
@ljharb Fair enough. getObj().name?|> log(name); // property `name` becomes an identifier `name` for the right-hand side We could require specifying it where a preceding identifier is unavailable, e.g.: getObj()?|>obj: log(obj); // value becomes an identifier `obj` for the right-hand side
getObj()?.name|>x: log(x); // this form can also be used to change the default name when available Different default identifiers simplify reusing them further, instead of having getObj().parent?|> parent.name|> join(parent.id, name)|>str: log(parent, str);
// properties `parent` and its `name` are both identifiers available on latter parts too |
This would cause implicit shadowing and introduce all sorts of ambiguities, as previously mentioned. Can you even tell what each identifier would refer to in this example? function cook(recipe, ingredients) {
return (
recipe.ingredients
|> prepare(ingredients)
|> measure(recipe.ingredients, ingredients)
|> other: mix(ingredients, other)
|> ingredients: heat(ingredients)
);
} I think the whole value of the Hack placeholder is that it's short and recognizable. If we can't have it, we might as well write pipelines as a series of assignments and not introduce new syntax. |
This issue is for bikeshedding the spelling of the topic token in Hack pipes, branching off from #75 (comment). For more context, see the Hack pipes proposal and the wiki home page.
The table has its own editable page on the wiki. Please read this table first before contributing to this issue.
Please also keep discussion on topic: bikeshedding the topic token for Hack pipes. For other topics, search for other existing issues. Thank you!
Old obsolete questions
These currently are the most topical bikeshedding questions that I see now:
What is the optimal tradeoff in writability (easily typed ASCII soup, e.g.,
?
, or easily typed privileged valid variable, e.g.,$
) versus readability (less easily inputted non-ASCII syntax, e.g.,■
)?Related to question 2: Can non-ASCII Unicode syntax characters be considered for the pipe placeholder, or must they be categorically excluded?
A list of all possible
Pattern_Syntax
Unicode characters is available.If question 3’s answer is that non-ASCII Unicode syntax may be excluded, which non-ASCII syntax character would be visually understandable and/or less difficuldifficultt?
Many non-ASCII symbols are easily inputted in certain OSes. For instance, in macOS, several dozen typographic characters are directly typable using Option or Option + Shift (image of keyboards with various active modifier keys via Macworld article. It may be worth determining if there is an intersection of these easily typable non-ASCII characters across the default keyboard layouts of many OSes.
For nullary operators vs. valid variable identifiers: How important is it that the placeholder be statically analyzable?
A nullary operator can be always be statically recognized in the RHS. In contrast, a valid identifier can be statically recognized only if the rule is: “Tacit function calling may occur only when the RHS is a bare identifier, rather than allowing the RHS to be any arbitrary expression without a placeholder.”
Operator vs. identifier again: How often would someone want to use an identifier from an outer lexical context of the same name as the pipe placeholder?
If the placeholder is
$
, how often would a programmer want to use jQuery’s$
or another externally defined$
in a pipe’s RHS, as well as the pipe placeholder? How often would they be surprised if they could not, without defining a dummy variable for the outer$
? How bad of a footgun (i.e., bug by programmer-unexpected behavior) would this be?How much should the pipe placeholder stay compatible with @rbuckton’s higher-order functional operators, which possibly would use
{…}
?@rbuckton proposed a partial-application placeholder that may be explainable by multiple topic placeholders. In other words, the pipeline syntax might be completely unifiable with the PA syntax with the right enhancements.
Assuming a future shorthand “pipe-function operator” like
+>
(which would be an abbreviation forx=>x|>
), then @rbuckton’s proposal’sf(?, 3)
would instead be+> f(?, 3)
, which in turn would be shorthand forx=>x|> f(?, 3)
.Creating non-unary functions could be done
by adding numbers to placeholders,
such as
?0
,?1
,?2
, etc.For instance,
example.sort(+> ?0 - ?1)
would mean
example.sort((x, y) => x - y)
.(
?0
would be equivalent to plain?
.)Which placeholders would have any problems with staying forward compatible with such a future proposal?
As of 2022-07-11, I like
^^
then more distantly$_
,@@
,%%
, and#_
.The text was updated successfully, but these errors were encountered: