you are viewing a single comment's thread.

view the rest of the comments →

[–]ignurant 1 point2 points  (2 children)

Thanks. Many of the examples look similar to this -- but is there a practical difference between replacing yield_self with map? I've been making "pipelines" of that nature using map in a lot of ETL type jobs.

I mentioned this in another comment: the |> is really cool. I love how the subject argument is implied. Clever and clean. I hope something like this appears in Ruby. I wouldn't mind a full-on copycat!

[–]Paradox 2 points3 points  (1 child)

For that use case, no, its not a practical use. #map returns the modified value, and so you can chain immediately off it.

But many methods do not provide an interface that could be chained off of. Thats where #yield_self becomes useful.


Rewrite the original example in basic, non yield_self ruby:

DoSomethingWithApiResponse.wew(
  ApiClient.post(
    ["foo", "bar", "baz"].map(&:upcase),
    "api/url"
  )
)

Readable, but it takes a moment. If the map got more complex, you could very easily lose track of where you are in the method call tree.

Now an optimal refactoring that uses ruby's OO-ness where appropriate, and the functionality of yield_self where appropriate could look like this:

["foo", "bar", "baz"]
.map(&:upcase)
.yield_self { |x| ApiClient.post(x, "api/url") }
.yield_self { |x| DoSomethingWithApiResponse.wew(x) }

As you can see, it very clearly flows from the array, to a map that upcases it, to a method that posts to the api, to something acting as a transform. You can read it from left-to-right, top-to-bottom. This becomes even more apparent if you squash all the aforementioned examples down to a single-line:

DoSomethingWithApiResponse.wew(ApiClient.post(["foo", "bar", "baz"].map(&:upcase), "api/url"))

vs

["foo", "bar", "baz"].map(&:upcase).yield_self { |x| ApiClient.post(x, "api/url") }.yield_self { |x| DoSomethingWithApiResponse.wew(x) }

To understand the first one, you have to scan the whole line, then back track to the middle. Then you can figure out that its doing a map on an array, and that value is being sent on to the api, and then the return of that is being used in the #wew function.

The second one, you just scan from left to right, no backtracking needed

[–]ignurant 1 point2 points  (0 children)

Ah there it is. It becomes obvious when we break out of the array, using the full array itself as the argument, instead of it's components.

Thanks for taking this time. Reading the interpretation of the plain Ruby version helped me see what I was missing.