6 ms·
The pipe operator seems silly until you learn to pipe into IO.inspect. for vscoders I use this snippet (https://slickb.it/bits/70 https://slickb.it/bits/70) wh
by dnautics 6y ago
The pipe operator seems silly until you learn to pipe into IO.inspect. for vscoders I use this snippet (https://slickb.it/bits/70 https://slickb.it/bits/70) which also labels with the line numbers, meaning you can multiline select a bunch of lines in your pipeline and when you're done ninja them out with another multiline select (usually line numbers have the same number of characters around each other). In combination with triggering single tests, it's invaluable for isolating errors in code.
In action: https://youtu.be/WMYc3VzOSpg&t=23m20s 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.
- aeturnum 6y agoI think OP's point about building huge systems with pipes is well taken. They can become confusing when the break and over-use can be a code smell. 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).
- dnautics 6y agoI think it also encourages a declarative style of programming, so that's a win if you ask me, especially for large systems, though I can't measure this.
- jolux 6y agoIf you’re chaining more than three or four things together I think you’re definitely doing something wrong but I’m not sure I’ve ever seen someone do that in Elixir.
- dnautics 6y agoNot an antipattern for nimble_parsec: https://github.com/ityonemo/zigler/blob/fe845a9fbbfef92da8aba99ffd599a2e6551e807/lib/zig/doc/parser.ex#L88 https://github.com/ityonemo/zigler/blob/fe845a9fbbfef92da8ab... Plus think of how much easier that pipe makes it for you to understand what is going on.
- jolux 6y agoThat’s a very beautiful usage of it. I hadn’t thought of it as a way to construct DSLs, but it makes a lot of sense here.
- owl57 6y agoLooks like Haskell-like do notation would be helpful.
- dnautics 6y agodo you feel like the code presented is broken? I don't. Could it be better? Maybe... But how much? Is it worth a whole new pattern to learn?
- cultofmetatron 6y agothe entire ecto api is built upon chaining statements together. I have a few queries that are 8-10 statements long.
- jolux 6y agoGood point, I don’t use Ecto so I wasn’t aware of this.
- Kaze404 6y agoMy longest pipe chain in Elixir so far (with ~1 year of usage) is this[1], where I build a GraphQL context from an HTTP session. I personally think it's clean enough, but your comment made me wonder if it can be better. [1] https://github.com/RodrigoLeiteF/craftup/blob/main/backend/lib/craftup_web/context.ex#L16 https://github.com/RodrigoLeiteF/craftup/blob/main/backend/l...
- 1_player 6y agoI disagree. I think a common antipattern is piping only one thing. 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.
- blackrock 6y agoI dislike uppercasing. I wished Elixir would’ve used “io” instead of “IO”.
- rlander 6y agoWell I believe that no pipe is better than a a handicapped pipe operator. 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.
- sodapopcan 6y agoIs it to its detriment? What's really at stake here? Elixir's pipe operator takes a stance, and I love that. It enforces consistency. I feel it's a lot better than having the "sometimes first, sometimes last" that Erlang and Clojure have.
- rlander 6y agoIME it is. Many Elixir apis end up forcing an unnatural parameter order just so that the entire body can be piped through. 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".
- sodapopcan 6y agoI don't have a functional background so I can only empathize that only being allowed to pipe first is not what folks are used to. I am having trouble understanding your argument, however, that includes both "consistent" and "choose your own adventure". I also don't buy that, other than simply being used to it, that piping last to sequences is more "natural". "reduce a into b with c" or "reduce value a into value b using function c" reads perfectly natural to me. I'm happy to hear arguments otherwise.
- rlander 6y agoYou’re missing the crux of the argument: auto-currying. In languages like Elm and Ocaml all functions are single arity which means a multi-arity function is just a partially-applied single arity function thus you can treat all functions as being single arity. This also means the pipe operator can be implemented as a higher order function being, as such, first class. Languages without auto-currying have to resort to macros. 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.