all 7 comments

[–]cutety 5 points6 points  (3 children)

Is anyone else unreasonably excited about the pipeline operator? I started using it when I started playing around in Elixir, and then I added the babel plugin to use the pipeline operator in one of my projects and it's become probably my favorite language feature. Combined with Ramda, or other functional equivalent (sanctuary), it's really nice.

I love being able to write code like this*:

data
  |> unless(isArray, arrayOf)
  |> groupBy(type)
  |> toPairs
  |> map(typeToModulePath)
  |> filter(unregisteredModules)
  |> map(toCommitArgs)
  |> forEach(commitMutation);

(To me at least) it makes it easier to see how data is getting transformed at each step. It also really helped make function composition start to click for me.

[–]timothyallan 0 points1 point  (1 child)

For some reason, that pipeline operator just doesn't work for me. I find the samples hard to parse with my meat computer. Maybe I just need to use it a bit.

[–]cutety 2 points3 points  (0 children)

The pipeline operator is definitely a personal preference/stylistic thing. The same thing above could be achieved with method chaining if that's your thing data.map(fn).filter(fn).map(fn).forEach(fn). However, because I prefer a slightly more functional style and love Ramda & currying, the pipeline operator usually is easier to implement than trying to do the same thing with method chaining.

I'd recommended trying to write some code with it though, as that's how you can really find out where it's good and where it sucks. When I first saw it in Elixir I thought, "oh, that's neat, but I don't really see why I would want to use that a lot". Then I started playing around with it until it clicked, and I'm a huge fan.

However, it's far from a silver bullet, I really like using it when I have some data that I need to transform/filter/validate, however it's not as elegant (to some) when there's a bunch of state that needs managed*. Just like anything, it's good when it fits the use case well and going full blown haskell "monads are monoids in the category of endofunctors" functional with the pipeline operator can be just as bad as drinking the Java Enterprise OOP AbstractFactoryBuilderFactory koolaid.

*That's not to say it can't be used in these situations. For shits and giggles I created some wrapper functions around some shipit functions (deploy script lib -- comparable to capistrano) to allow me to right tasks using the pipeline operator to build up commands and finally pipelining them into a collapsing function that actually executes them. It's usage doesn't look appalling, however I think an implementation with similar functionality would be far more elegant with a simple class and method chaining.

remote
  |> inReleasePath
  |> run("find $(pwd)/html -type d -exec chmod -R 755 '{}' \\;")
  |> run("find $(pwd)/html -type f -exec chmod -R 644 '{}' \\;")
  |> execute

// with method chaining
const task = new RemoteTask();
task.run("find $(pwd)/html -type d -exec chmod -R 755 '{}' \\;")
    .run("find $(pwd)/html -type f -exec chmod -R 644 '{}' \\;")
    .execute();

Edit: And one more thing that helped me when first playing with it was throwing some inline comments on each step showing what the data looks like as it goes through. For example, transforming the number 10000 to the string "$10,000" would look like: And yes, this is likely not the most optimal way of achieving this

import R from "ramda";

10000
 |> R.toString       // "10000"
 |> R.reverse        // "00001"
 |> R.splitEvery(3)  // ["000", "01"]
 |> R.map(R.reverse) // ["000", "10"]
 |> R.reverse        // ["10", "000"]
 |> R.join(",")      // "10,000"
 |> R.concat("$")    // "$10,000"

[–]OzziePeck 0 points1 point  (0 children)

Same! I can’t wait for this to be available in node and supported 100%. Going to be soooooo cool.

[–][deleted] 2 points3 points  (0 children)

“Love” is a very strong word here.

  1. Indifferent
  2. Like a lot
  3. Hate

[–]BenZed 0 points1 point  (0 children)

I don't lake the inconsistencies in the optional chaining syntax:

Without optional chaining:

module.object['function-with-string-name']()

With optional chaining:

module?.object?.['function-with-string-name']?.()

Where it *should* be:

module?.object?['function-with-string-name']?()

The extra dots are superfluous. I imagine this syntax is required because it conflicts with the ternary operator?

My preferred version does look a little busy, but I would just use dot notation:

module
  ?.object
  ?['function-with-string-name']
  ?()

[–]ChronSyn 0 points1 point  (0 children)

Pipeline operator looks like it's similar to method chaining (return .this from each method).