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
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
“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
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.
[garden-path syntax]: https://en.wikipedia.org/wiki/Garden_path_sentence
[pipeline syntax grammar]:
> > [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
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
`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]:
[Ramda examples, part 2]:
> > [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
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.
> 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 |>
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.
[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.
J. S. Choi
es-discuss mailing list