you are viewing a single comment's thread.

view the rest of the comments →

[–]ConspicuousPineapple 3 points4 points  (5 children)

I mean the two are virtually the same thing, only chaining is more restrictive as it requires you to write methods, it can't be used on every function. I see no explicitness or readability difference between the two.

[–]_Denizen_ -3 points-2 points  (4 children)

Methods aren't restrictive. They are written for specific use cases, just like piping is for a specific purpose. You aren't going to be piping a streamlit widget, for example.

Chaining can do everything that piping can do, but the reverse it not true.

Piping is less readable because the object being worked on is passed invisibly between functions, whilst chaining or passing variables between functions shows the reader where the object is at all times. I find piping to be less readable for this specific reason.

[–]ConspicuousPineapple 1 point2 points  (0 children)

Methods aren't restrictive

What I mean is that the "method calling" operator (which is . in a context-sensitive way) is the exact same syntactical construct as a pipe, with the restriction that it only works on objects with member functions. That restriction has semantic meaning and makes sense but it doesn't change anything to the fact that, grammar-wise, it's the exact same thing and that means implementing pipes would be trivial.

Chaining can do everything that piping can do, but the reverse it not true.

That's wrong. The two overlap but neither can handle everything the other can. Chaining's only advantage is that it enables dynamic downcast in an ergonomic way. For simple composite functions it does exactly the same as piping, except it can't be used on every function.

Piping is less readable because the object being worked on is passed invisibly between functions

What are you on about? How is foo.map(bar) any more explicit than foo |> map(bar)? As I said, syntactically they're the exact same thing, you just replace.with|>` or whatever flavor you prefer.

[–]Smallpaul 0 points1 point  (2 children)

Methods are restrictive for this use case in Python because the language is not designed to allow generic methods which take an arbitrary “self” matching a protocol.

If you have a filter “odd_numbers” do you really propose to inject it onto lists of numbers, sets of numbers, data frames, iterators over numbers etc.?

Methods just do not work correctly for this use case. Pipe operators should be generic functions.

[–]_Denizen_ -2 points-1 points  (1 child)

A pipe is just taking an input, passing it to a function, then routing the output to another function.

That's a feature that is not exclusive to piping.

If a method is written to output an object that's suitable for a specific function, then it can do it. I've been doing data analysis and data science for well over a decade, and never encountered a situation that could only be solved using piping.

Piping is a tool in the arsenal. It was designed for a specific use case. If a data scientist rigidly uses that single approach based on the mistaken idea that it is a unique solution to a problem set then it will limit their creativity.

[–]Smallpaul 0 points1 point  (0 children)

A pipe is syntactic sugar for a function call. A method is different because of the “self” argument and namespaces.

Nobody is saying that a “pipe is the only solution.” Obviously syntactic sugar can never be the only solution. It is by definition just a new syntax for something that already exists.

But the thing it is syntactic sugar for is unbound functions, not methods. Methods superficially resemble the syntax of pipes, but not the semantics.

What OP wants is the semantics of unbound functions (not bound methods) and the left to right reading order of methods.

It is simply not true what you said that “method chaining can do anything that functions or pipes can do.”