In action: https://youtu.be/WMYc3VzOSpg&t=23m20s
I suppose the problem with this snippet is that it keeps you from using more powerful tools like tracer and recon.
In action: https://youtu.be/WMYc3VzOSpg&t=23m20s
I suppose the problem with this snippet is that it keeps you from using more powerful tools like tracer and recon.
Their power, as you point it, is in the ability to jump into any statement and add another action with minimal syntax. It's extremely useful while iterating on development because you can quickly check that something works (or check on what is happening).
Plus think of how much easier that pipe makes it for you to understand what is going on.
[1] https://github.com/RodrigoLeiteF/craftup/blob/main/backend/l...
This is good and readable:
nuclear_missile
|> open_hatch()
|> open_fuel_lines()
|> fire_thrusters(:all)
|> configure_gps(%Coordinates{...})
This is unnecessary: word_count =
words
|> Enum.count()
This is better: word_count = Enum.count(words)
Pipes read like a list of bullet points. We can easily deal with up to a dozen bullet points, but a single bullet point is bad grammar style.The Elixir implementation inverts the classical order of piping last in functional languages to the detriment of it. IMO a language should either support pipe last AND currying by default or supply a multitude of thread operators like Clojure does (->, ->>, as->, etc). Elixir's is just middle-of-the-road-weird.
Clojure is way more consistent in this regard:
- thread first (->) when operating on maps.
- thread last (->>) when operating on sequences.
- as-> "choose your own adventure".The only place where pipe order bristles is Enum.reduce, but I'd bet if I counted I'd have wanted it the normal way more often than the backwards way.
often you want to apply a list of actions to an object.
This is a "backward reduce".
I don't feel it often, but when I do, it's such a bummer.
Clojure also doesn’t have auto currrying, but makes up for it by giving you 6 variants and creating a consistent default library for sequences and associative structures.
So, the pipe first operator is just a dirty hack.
I'm a bit stuck on your Clojure example still, though. If a language doesn't have auto-currying (or even currying at all in Elixir's case), why does the argument order matter? Whether it's a List or a Map, what does it matter if it's passed first instead of last?
But the threading macros do partial application in that they put the threaded-through value as an implicit argument. Look at the first examples in https://clojure.org/guides/threading_macros - the -> (thread-first) macro needs functions like assoc and update to take the map as the first argument.
And of course explicit use of partial application is also pretty common and argument order matters similarly there, just like it would eg in Python.
I wished Elixir would’ve used “io” instead of “IO”.