From: "AlexandreMagro (Alexandre Magro) via ruby-core" Date: 2024-09-30T19:02:25+00:00 Subject: [ruby-core:119364] [Ruby master Feature#20770] A *new* pipe operator proposal Issue #20770 has been updated by AlexandreMagro (Alexandre Magro). bkuhlmann (Brooke Kuhlmann) wrote in #note-4: > For background, this has been discussed before: > > - [15799](https://bugs.ruby-lang.org/issues/15799): This was implemented and then reverted. > - [20580](https://bugs.ruby-lang.org/issues/20580): This recently popped up as well. > - There are probably other issues that I'm forgetting about that have been logged on this subject. > > Introducing `|>` as an operator that works like `#then` would be interesting and would be similar to how Elixir works, as Alexandre mentioned. This is also how [Elm](https://elm-lang.org) works where you can elegantly use `|>` or `<|` as mentioned in the [Operators](https://elm-lang.org/docs/syntax#operators) documentation. > > I also use something similar to how Sean uses a `#pipe` method with a block but mostly by refining the `Symbol` class as documented [here](https://alchemists.io/projects/refinements#_call) in my [Refinements](https://alchemists.io/projects/refinements) gem. > > Also, similar to what Sean is describing, I provide the ability to *pipe* commands together without using `|>` by using my [Pipeable](https://alchemists.io/projects/pipeable) gem which builds upon native function composition to nice effect. Here's a snippet: > > ``` ruby > pipe data, > check(/Book.+Price/, :match?), > :parse, > map { |item| "#{item[:book]}: #{item[:price]}" } > ``` > > In both cases (refining `Symbol` or using Pipeable), the solution works great and provides and implements what is described here using different solutions. All solutions are fairly performant but would be neat if the performance could be improved further if there was a way to optimize these solutions natively in Ruby. One issue with `.pipe` is that it mixes two approaches: the object method chain (`lhs.rhs`) and passing the result as an argument (`rhs(lhs)`). This inconsistency can be a bit confusing because it shifts between the two styles, making it harder to follow the flow. in the `.pipe` version: ``` "https://api.github.com/repos/ruby/ruby".pipe do URI.parse Net::HTTP.get JSON.parse.fetch("stargazers_count") yield_self { |n| "Ruby has #{n} stars" } Kernel.puts end ``` With a pipe operator, we can achieve the same result in a more consistent and readable way: ``` "https://api.github.com/repos/ruby/ruby" |> URI.parse(it) |> Net::HTTP.get(it) |> JSON.parse(it).fetch("stargazers_count") |> puts "Ruby has #{_1} stars" ``` This keeps the flow of passing the result from one step to the next clear and consistent, making the code easier to read and maintain. The pipe operator doesn���t add any extra complexity to method calls and provides more flexibility regarding how the "piped" value is used, making it feel more natural in the Ruby syntax. ---------------------------------------- Feature #20770: A *new* pipe operator proposal https://bugs.ruby-lang.org/issues/20770#change-109977 * Author: AlexandreMagro (Alexandre Magro) * Status: Open ---------------------------------------- Hello, This is my first contribution here. I have seen previous discussions around introducing a pipe operator, but it seems the community didn't reach a consensus. I would like to revisit this idea with a simpler approach, more of a syntactic sugar that aligns with how other languages implement the pipe operator, but without making significant changes to Ruby's syntax. Currently, we often write code like this: ```ruby value = half(square(add(value, 3))) ``` We can achieve the same result using the `then` method: ```ruby value = value.then { add(_1, 3) }.then { square(_1) }.then { half(_1) } ``` While `then` helps with readability, we can simplify it further using the proposed pipe operator: ```ruby value = add(value, 3) |> square(_1) |> half(_1) ``` Moreover, with the upcoming `it` feature in Ruby 3.4 (#18980), the code could look even cleaner: ```ruby value = add(value, 3) |> square(it) |> half(it) ``` This proposal uses the anonymous block argument `(_1)`, and with `it`, it simplifies the code without introducing complex syntax changes. It would allow us to achieve the same results as in other languages that support pipe operators, but in a way that feels natural to Ruby, using existing constructs like `then` underneath. I believe this operator would enhance code readability and maintainability, especially in cases where multiple operations are chained together. Thank you for considering this proposal! -- https://bugs.ruby-lang.org/ ______________________________________________ ruby-core mailing list -- ruby-core@ml.ruby-lang.org To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org ruby-core info -- https://ml.ruby-lang.org/mailman3/lists/ruby-core.ml.ruby-lang.org/