Want to pipe into a Case statement? You can!

pipe into case? I use that fairly frequently…unless I’m misunderstanding what you’re wanting…could be… its still very early…

str = "Hello"
str |> case do
   "Goodbye" -> "see ya!"
   "Hello" -> "welcome!"
end
20 Likes

Yep this! I pipe into case statements probably a lot more excessively than I really should… ^.^;

And I pipe into if and other such things as well… >.>

6 Likes

Oh my…so much code I have to rewrite now! Wow thats something I really…should have…checked.

5 Likes

Cool tip - moved into a new thread :003:

2 Likes

OMG, just please don’t pipe when you don’t need it, I just don’t see any improvement when piping for example just one time e.g. mylist |> Enum.map(myfunc). It is such less readable, just because you can, it doesn’t mean you should :wink:

4 Likes

Yup!

One pipe–not worth it.

Two or more pipes–extremely worth it :slight_smile:

1 Like

I always find this something |> IO.inspect() more readable than IO.inspect(something) I really don’t see nothing wrong with piping even when there is only one pipe

If you do

something 
|> do_something()
|> do_something_else()
|> with_additional_param(param)

then what’s wrong with just

something |> do_something()

I think we should not mistake readability with familiarity. Just my 2 cents.

8 Likes

Yet in the end it is just personal taste I think. for people’s doing elixir It is pretty normal, new devs coming to the code base might not get over it easily. I just think that reading this piped into IO.inspect is less readable than IO.inspect this because it looks more like a description of a command. And reaching for | and > is hard :laughing:

Piping into case is pretty cool, but after I do it, I realize it’s often better for me to wrap that case statement into a function that I can name so it reveals the intention a little better.

I especially don’t like doing it in the middle of a pipeline. I find myself using case statements more often in Phoenix controllers to handle the happy path and unhappy path.

8 Likes

This style often confused subject and object. Therefore I’m not really a friend of it.

1 Like

Also a fan of that, and we can use pattern matching in the head of the function as each case match, since both will be compiled down to the same thing

1 Like

I’m not sure what you mean by that, what’s in this context is object and what is a subject.

It very easy not to be confused if remember that nouns are the objects or in other words subjects of given function/transformation, and verbs are the functions or in other words labels for transformations we do to our data, objects, the nouns.

It’s actually the case of: IO inspects this vs this is being inspected by IO And I think we do care more about this than IO and it’s easier to skim code if this is at the beginning of the line (or at least closer the the side which I’m starting to read given line).

If you are telling someone about your friend Bob and how you spend last evening, would you rather tell I wen't with Bob to a bar or Bob and I wen't to a bar? Both versions are perfectly understandable, but which one is the correct one? :wink:

1 Like

The problem for me here is, that usually in a sentence the object comes first, so thing |> IO.inspect reads for me as if thing were inspecting something not further mentioned.

But actually thing is (or better: should be) seen as the subject, the thing we do something with.

People should be very familiar with piping:

something 
|> do_something()
|> do_something_else()
|> with_additional_param(param)

is essentially equivalent to OO

something 
  .do_something()
  .do_something_else()
  .with_additional_param(param)

i.e. method chaining and fluent interface.

The returned object and implicitly passed this (“parameter”) is replaced with the convention of the “result to the first parameter of the function”. That’s it.

From that perspective I’ve always found

something.do_something()

more pretentious (objects are the “leads”, methods only play “supporting” roles) than

do_something(some_thing)

I mean people always make such a big deal about “functions being first class citizens”. Therefore I have similar misgivings about:

something |> do_something()

And the community style guide happens to agree.

Avoid using the pipe operator just once.

There is nothing messy about:

do_something(some_thing)

which can’t be said about

with_additional_param(
  do_something_else(
    do_something(something)
  ), 
  param
)

which is why

something 
|> do_something()
|> do_something_else()
|> with_additional_param(param)

is preferred.

5 Likes

I think you are confusing object and subject. Object is the thing upon which the subject acts - subject is the thing performing the action.

total_point = staging_items
|> Enum.reduce(0, fn (item,acc) -> Board.piece_point(item) + acc end)
|> Kernel.+(Enum.reduce(const_board_items, 0, fn (item,acc) -> item.point + acc end))
|> Kernel.*(Enum.reduce(staging_items, 1, fn (item,acc) -> Board.equation_mult(item) * acc end))

No kidding, this is my production code (not a serious app, 1 developer)

Wait! I think I could refactor it this way:

total_point = 1
|> Kernel.*(Enum.reduce(staging_items, 0, fn (item,acc) -> Board.piece_point(item) + acc end))
|> Kernel.+(Enum.reduce(const_board_items, 0, fn (item,acc) -> item.point + acc end))
|> Kernel.*(Enum.reduce(staging_items, 1, fn (item,acc) -> Board.equation_mult(item) * acc end))
1 Like

Just to be explicit that’s not actually a different factoring .

A different factor would be

total_score = 1 + count(board_items) + count(const_board_items) + count(other_staging)

Maybe you can do pattern matching on count , maybe not - if you can’t- it is clear to say count_stage_items, count_const_board_items - this gives you abstraction over the details of how you count. Also it gives you a way to test In isolation the properties of “count_board_items” et.all

Refactoring typically refers to a set of specific operations (extract method, extract constant, extract class/module, merge method, merge class, rename class, rename method , etc ) and not simply rewriting a line of code into a different form.

I say this to help you become one with the art of appropriate abstractions which is a foundation for successful refactoring.

1 Like

Agreed on abstraction :slight_smile: that’s why I mentioned about seriousness and sole developer.
Also my bad on saying “refactor”.

I just wanted to give one more pipe obsession example. Like anything can be piped will be piped.
Thanks!

1 Like

I very much dislike piping into cases/ifs/anything of that sort. I will 100% of the time extract that to a function and name it for readability purposes, and will always call it out in code review. To me, it reads very poorly, and is the lesser of all alternatives. For full disclosure, I often do this with case statements in general, but it’s especially pronounced with pipes.

2 Likes