Thanks again for the reply, Peter. I’m a little confused by your latest 
questions, so I’ll try to clarify the questions at a time.

> > [me] To clarify: The way that bare style and topic style are distinguished 
> > are not by the absence/presence of a topic reference. Bare style has a 
> > simple and strict syntax: any identifiers, separated by `.`s, optionally 
> > preceded by `new` or `await`.
>
> [Peter] So `x['hello']`` would not be valid? Seems pretty inconsistent. I 
> think that checking for the lexical topic token would be simpler and easier 
> for developers.

`value |> x['hello'](#)` is a valid pipeline, in topic style. `value |> 
x['hello']` is an invalid pipeline, in order to prevent infinite unrestricted 
lookahead, therefore simplifying interpretation for both human readers and 
computer readers.

By “simplicity”, I’m referring to [several goals from the proposal 
explainer][goals]. Particularly relevant here is the goal of [syntactic 
locality][]. Copying and pasting from there: “The syntax should minimize the 
parsing lookahead that the compiler must check. If the grammar makes 
[garden-path syntax][] common, then this increases the dependency that pieces 
of code have on other code. This long lookahead in turn makes it more likely 
that the code will exhibit developer-unintended behavior.

“This is true particularly for distinguishing between different styles of 
pipeline body syntax. A pipeline’s meaning would often be ambiguous between 
these styles – at least without checking the pipeline’s body carefully to see 
in which style it is written. And the pipeline body may be a very long 
expression.

“By restricting the space of valid bare-style pipeline bodies (that is, without 
topic references), the rule minimizes garden-path syntax that would otherwise 
be possible – such as `value |> compose(f, g, h, i, j, k, #)`. Syntax becomes 
more locally readable. It becomes easier to reason about code without thinking 
about code elsewhere.”

In addition, changing the grammar to depend on containment of a token would 
make it impossible to parse with a context-free grammar or by introducing a new 
grammar-production parameter, which multiplies the number of productions in 
JavaScript’s grammar. The [pipeline syntax grammar][] alone would become 
considerably considerably more complicated – and this also applies to the 
grammars for every single other type of expression, all of which would have to 
be modified with an additional syntactic parameter.

At the very beginning, in fact, I actually considered making the grammar to 
depend on containment of a token – but then I realized many of the 
disadvantages above that it would bring.

The example `value |> x['hello']` seems simple. But the danger of requiring 
unrestrictedly infinite lookahead is that people will also write things like 
`value |> compose(x['hello'][symbol].propertyA.key(#).propertyB.propertyC, 
anotherFunction)`. It is easy for a human reader to miss the `#` in there, yet 
its presence or absence would completely change the pipeline’s semantics, from 
the value returned by `compose(…)` to a function call on that value. That’s the 
consequence of compromising syntactic locality. It means that a reader will 
have to check distant code in order to determine the style of a pipeline. 
[Avoiding footguns is a paramount goal][avoid footguns].


And `value |> x['hello'](#)` is still a valid pipeline.


[goals]: 
https://github.com/js-choi/proposal-smart-pipelines/blob/master/readme.md#goals

[syntactic locality]: 
https://github.com/js-choi/proposal-smart-pipelines/blob/master/readme.md#syntactic-locality

[garden-path syntax]: https://en.wikipedia.org/wiki/Garden_path_sentence

[pipeline syntax grammar]: 
https://jschoi.org/18/es-smart-pipelines/spec#sec-pipeline-operator

[avoid footguns]: 
https://github.com/js-choi/proposal-smart-pipelines/blob/master/readme.md#dont-shoot-me-in-the-foot

***

> > [me] Any pipeline body that does not fulfill that simple and strict syntax 
> > is in topic style. However, any pipeline body that is in topic style also 
> > must contain a topic reference, or else it is an early syntax error. x |> 
> > f() is in topic style; it is also an early syntax error, because it is a 
> > topic-style pipeline that does not use the topic reference.
>
> [Peter] This seems to not support auto-currying functions. For instance, 
> lodash/fp has auto-currying functions which take an iteratee as the first 
> argument:

My apologies – I’m a little confused by what your first sentence here means. By 
“this”, do you mean that smart pipelines do not support auto-currying 
functions, or do you mean that the bare style do not support them?

Auto-currying functions are indeed supported by smart pipelines, though not 
necessarily by bare style.

The purpose of bare style is merely to optimize a common use case – unary 
function calls. All other cases are intended to use topic style, which 
hopefully is still terse, yet explicit enough to avoid ambiguity.

In fact, several examples in the readme are drawn from Ramda’s cookbook, 
several of which, if I recall correctly, involve autocurrying functions ([Ramda 
examples, part 1][] and [Ramda examples, part 2][]).

Your example using Lodash/FP,  
`['a', null, 'c'] |> fs.filter(Boolean)`,  
is expressible using  
`['a', null, 'c'] |> fs.filter(Boolean)(#)`.  
The latter is a valid topic-style pipeline.

In general, `x |> f(a, b)` is visually ambiguous between four reasonable 
interpretations:\
`x |> f(a, b, #)`,  
`x |> f(a, #, b)`,  
`x |> f(#, a, b)`, and  
`x |> f(a, b)(#)`.  
The early error forces the writer to specify which of the four reasonable 
interpretations they mean, also reducing the parsing burden on the human reader.

[Ramda examples, part 1]: 
https://github.com/js-choi/proposal-smart-pipelines/blob/master/readme.md#ramda-core-proposal--additional-feature-bppf

[Ramda examples, part 2]: 
https://github.com/js-choi/proposal-smart-pipelines/blob/master/readme.md#ramda-core-proposal--additional-features-bppfnp

***

> > [me] optionally preceded by `new` or `await`
> 
> [Peter] This seems very arbitrary and not forwards-compatible.

My apologies again – I am also confused by what you mean here by 
forwards-compatible. What is there for bare style to be forward compatible 
with? New prefix operators? If a new operator is commonly used before unary 
function calls, then they could be added to bare style’s syntax later, but in 
the meantime topic style can handle them, as well as anything else, simply by 
appending `(#)`.

Bare style is a special syntax, with special evaluation semantics, optimized 
for one common use case: unary functions. The `new` and `await` tokens are just 
flags for bare style because unary constructor calls and awaited unary 
async-function calls are also quite common, as my review of real-world 
codebases in [Motivation][] shows. But in general, I expect topic style to be 
used more often, and topic style itself is very terse.

In fact, the `new` and `await` flags in bare style were originally not there. 
The only reason why I added them in the first place was because, during that 
[review of real-world code][Motivation], I found that unary constructor calls 
and awaited unary async-function calls are very common. I am still considering 
removing them from the Core Proposal, into their own separate Additional 
Features, so that their tradeoffs may be independently considered.

[Motivation]: 
https://github.com/js-choi/proposal-smart-pipelines/blob/master/readme.md#motivation

***

> By only allowing identifiers, you're requiring people to create unnecessary 
> intermittent variables. I propose that you allow any expression on the 
> right-hand side of the pipe operator, and decide whether it's in topic style 
> or bare style based on the inclusion of the lexical topic token. Your 
> argument that making it very restrictive reduced cognitive burden doesn't 
> make sense to me at all, as remembering what is and isn't allowed is more 
> difficult than just remembering "if it doesn't have the token, it will call 
> the function specified by the expression with the argument of the result of 
> the previous step in the pipeline".

Hopefully, the quotation I pasted from the [syntactic locality][] section from 
above is an adequate response to this paragraph. Bare style’s rules are simple: 
“”. The rules are simpler than humans and computers having to search a [long 
pipeline expression][garden-path syntax], such as `value |> compose(f, g, h, i, 
j, k, #, l, m, n, o)` or `value |> 
compose(x['hello'][symbol].propertyA.key(#).propertyB.propertyC, 
anotherFunction)`, for the absence or presence of a single topic reference `#`. 
In many reasonable cases, parsing would be considerably more complicated, for 
humans and computers alike.

[syntactic locality]: 
https://github.com/js-choi/proposal-smart-pipelines/blob/master/readme.md#syntactic-locality

[garden-path syntax]: https://en.wikipedia.org/wiki/Garden_path_sentence

***

Thanks again for the reply. Your `x['hello']`-method example and your Lodash/FP 
example are both already addressed by the current smart-pipelines proposal. I 
hope these explanations clarify your understanding of the current proposal.

I’ll have only intermittent free time in the next few days, but in the meantime 
James DiGioia and I will be working on the Babel plugin for both smart 
pipelines and F-sharp Style Only pipelines. I’ll try to reply to any reply here 
when I can.

Warm regards,
J. S. Choi

_______________________________________________
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss

Reply via email to