let transformedData = transformFoo(data);
transformedData = transformBar(transformedData);
transformedData = transformBaz(transformedData);
vs.
const transformedData = data
|> transformFoo
|> transformBar
|> transformBaz
If you want have const's the first becomes even more unwieldy, and in general I'd recommend using const by default.Just like lambda syntax makes it much easier and readable to write small functions, the pipe operator make it much easier and readable to write chains.
arg function_name
Then instead of arg |> func1 |> func2 |> func3
you could simply write arg func1 func2 func3
It might get a bit ugly when used with arrow functions instead of named functions, and there might need to be a special case when arg is a function, but if those problems could be handled not too unreasonably this seems a fine approach for a programming language.succinct =/= more readable.
Readability here is really in the eye of the beholder...
It's certainly quicker to type, but that's not a good argument enough to make such a drastic change in javascript.
I am so glad this argument has not been winning out in the JavaScript language design community. There are so many wonderful constructs that have been added in the last 20 years that are just sorter ways to write things that could mostly already be done in the language. Many of these features focused on allowing developers to write what they intended to do without having to explicitly construction the intermediate steps to express the mechanics of how that should be carried out using basic language features.
After all why do we need arrow functions when we could just sprinkle our code with `var self = this;` declarations for anonymous functions to bind to, the way it was done in the late 90's and early 00's.
I'd much rather JavaScript adopt succinct ways to write common code patterns and let the developers and the community decide if those constructs are the correct ones to use on a case by case basis.
Beware of survival bias, though. There have been many proposals that aren't part of JS today.
- The pipeline operator can be used to assign to a const, to prevent further assignments. While const isn’t necessarily immutable, it is often idiomatically used to signal that the assigned value is intended to be final. The same can’t be achieved with your example without wrapping it in an IIFE, which is (IMO) much harder to follow than the pipeline operator.
- More subjectively, it (in the F# variant) encourages better interfaces. For most use cases where piping would be appropriate, it’s generally a good idea to make the data you’re processing the last parameter. This also, as the article notes, works well with partial application. Which in turn also encourages good practices like composition.
Those are my opinions, however.
This is somewhat less true in some frontend projects, where the underlying libraries/frameworks come with infectious built-in interface complexity (side-eyes React/JSX even though I quite like JSX otherwise).
Part of it may also be due to the limitations of TypeScript. Structural typing is not always the best choice. ADT support is also not the best.
Look at shell scripting. Imagine trying to apply a type system to shell scripts. It wouldn't map cleanly at all because (almost) everything is a string, and the operations define how those strings are interpreted - not the data itself.
However for what it is, shell scripting is quite useful. Most would argue it has a simple interface, simple syntax, simple concepts.
Perhaps a contrived example - my point mostly being that you can't draw conclusions like that.
Oh, I wasn’t saying the language is poorly designed. I was saying the particular JavaScript code where people complain about the TypeScript types is usually poorly designed. It’s not the types’ fault the interface is so convoluted the types describing it are also convoluted.
Like people write variadic functions that take arguments, or an options map, or a boolean, or a magic string or enum… and then say “there’s 100 lines of types describing this functiona! That’s such a pain!” And like, yeah, it is a pain understanding what your function does.
> Look at shell scripting. Imagine trying to apply a type system to shell scripts. It wouldn't map cleanly at all because (almost) everything is a string, and the operations define how those strings are interpreted - not the data itself.
Amusingly, you’d end up with a type system a lot like TS. Particularly template literal and mapped types.
> However for what it is, shell scripting is quite useful. Most would argue it has a simple interface, simple syntax, simple concepts.
I think this is the only point of disagreement for me here. I find shell scripting absolutely painful, and try to do as little of it as possible.
Everything is a string because every program deserializes and then serializes data from and into a string. But you still have expectation encoded into the tools. If not, they wouldn't be able to work together. Static typing is about making these expectations explicit.
It’s worth noting though that the TypeScript team does participate in the standards process. And Microsoft has two members on the committee.
Source? This hasn't been my experience. Going on 10 years of heavy Node.js ecosystem involvement, immutable data enthusiasts are exceedingly rare.
Plus, this is const vs let, which is a reach to call "immutable data". We're not talking about object properties.
Immutable.js is relatively popular and immutable records and tuples are a stage 2 TC39 proposal. From what I've seen, immutability is mostly popular on the frontend, probably because functional programming had a huge impact there. It's also popular in other languages (FP or FP inspired generally, so OCaml, Haskell, Scala, Elm, Elixir, Rust) that are relatively close to the web ecosystem.
> Plus, this is const vs let, which is a reach to call "immutable data". We're not talking about object properties.
I'm not sure what you mean here.
Not an authoritative source, but since you cite your own experience, mine has been the opposite. Especially so when TypeScript is also in the mix.
> Plus, this is const vs let, which is a reach to call "immutable data". We're not talking about object properties.
As I mentioned in a sibling comment, const is often used to signal the intent to treat an assignment as immutable. This isn’t universal, but I understand it to be idiomatic usage.
return first() | second(_, 10) | third(x, y, _)
I somewhat agree.And the placeholder can't be _ as that's a valid identifier. The first issue on the tracker is the bike shedding thread about what the placeholder symbol should be, and it's neither _ nor ^, but instead probably something like ^label.
Suppose you had "const _ = 42; /* more code / return x | f | g(11, _);". This would be semantically equivalent to "const _ = 42; / more code */ return ((_) => g(11, _))(f(x))". Since it is a new function, shadowing is not forbidden.