Skip to content

Instantly share code, notes, and snippets.

@ParadoxV5
Last active February 13, 2023 03:02
Show Gist options
  • Save ParadoxV5/4f563e609decbdac07d40e5f2dead751 to your computer and use it in GitHub Desktop.
Save ParadoxV5/4f563e609decbdac07d40e5f2dead751 to your computer and use it in GitHub Desktop.
a follow-up miniblog to ParadoxV5/ruby-pipeline

According to https://bugs.ruby-lang.org/issues/17353#note-1, there were (if not still are) consistent posts requesting adding Elixir’s Pipeline Operator |> to Ruby.

However, unlike Lisp-1 languages like Python or JavaScript, Lisp-2s like Ruby face the additional challenge of namespace disambiguation. In addition to rightward calling, the Pipeline Operator would also change the call of the RHS to include the LHS. Therefore, its syntax is incompatible with the traditional designs for message passing programming and introduces a never-before-seen mental load.

As if by the the Single-Responsibility Principle, a separate step solves the namespace challenge neater than overloading it on the rightward call component. My solution to the Pipeline Operator – as prototyped in my ParadoxV5/ruby-pipeline – is in two steps:

  1. Build a separate shorthand for Object#method to counter the namespacing difference.

    • My prototype (re)uses #`:
      using Pipeline
      
      arguments
        .then(&`construct_url`)
        .then(&`URI`)
        .read # or `.then(&:read)`
        .then(&JSON.`(:parse))
    • Follow the proposal for a new operator at https://bugs.ruby-lang.org/issues/12125.
      • A Method Reference Operator .: existed an experimental feature during Ruby 2.7 previews 1 and 2, but its finalization did not make the deadline, and it was gone in Ruby 2.7 preview 3.
        arguments
          .then(&self.:construct_url)
          .then(&self.:URI)
          .read
          .then(&JSON.:parse)
      • Dedicating a non-method-based operator can also double it as an alternate reflection API that respects method visibilities. In contrast, method-based APIs must have separate methods for each visibility (i.e., Object#public_method on top of Object#method).
  2. The Pipeline Operator part of the puzzle then becomes humorously trivial.

    • My prototype half-bakes it with the #then_pipe method:
      using Pipeline
      
      arguments.then_pipe(
        `construct_url`,
        `URI`,
        :read,
        JSON.`:parse
      )
    • Here’s the example with both .: and |>:
      arguments
        |> self.:construct_url
        |> self.:URI
        |> :read # `&:meth` ≅ `&->(o,*a){ o.meth(*a) }`
        |> JSON.:parse

It turns out that the controversial portion of the Pipeline Operator isn’t the operator itself.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment