Notes
2026/10/06

10/b

One disadvantage of Universal Function Call Syntax a.f(b, c) is that it makes pipelining awkward for any functions where the pipelined value doesn't appear as the first argument. In other words, f(a, b, c) can be pipelined using UFCS as a.f(b, c), but there's no way to pull the b out of the pipeline.

What if a.f(b, c) is just sugar for a.f(_, b, c)? We can then pull b out by writing b.f(a, _, c). This generalizes UFCS while keeping the common case short. And a.f is sugar for a.f(). More interestingly, we can also use the pipelined value multiple times: a.f(_, _, _) And we can even transform the pipelined value before passing it as an argument, a.f(g(_), _, c), or pass the pipelined value into another pipeline: a.f(_.g(b, c), _, e)

Is pipelining important enough to receive its own syntax in languages that already have infix functions? Why not just use an infix operator such as |>? Perhaps that's the wrong question to ask, because UFCS (with or without _ as a placeholder) is much more about implicitly constructing anonymous functions than it is about . vs |>. It's just that . is a convenient way to delimit the extent of the lambda syntactically: a.f(g(_)) is (x) => f(g(x)) applied to a, whereas just f(g(_)) would leave it unclear whether it's meant to be (x) => f(g(x)) or f((x) => g(x)).

No special syntax for ., but anonymous function with directly bound _: If f(g(_)) is always f((x) => g(x)), then the pipeline operator can just be a regular infix function like |>.

If _ is just sugar for a single anonymous function argument so that f(_) desugars to (x) => f(x), what is the meaning of f(_, _) and f(g(_))? Are these forms allowed or is it better to restrict the shortform to a single _ in a top level prefix expression? Let's say f(_, _) is short for (x) => f(x, x) and f(g(_)) short for f((x) => g(x)).

If function call syntax and lambda syntax are kept fully extensible and general even with additional sugar, is it defensible to have sugar like [x, y] for lists that privileges them over user-defined data structures? Should there just be a uniform list(x, y), which is the same as set(x, y) etc? But that would require giving up the combination of trailing [...] arguments and infix functions, because f(x) g (y h z) could be either (with g(...) as the trailing argument) f(x, g(h(y, z))) or (with ... g ... as an infix function) g(f(x), h(y, z)). Unless the languages distinguishes between g(...) and g (...)? Which might be fine in practice?