Live data from Hacker News

Pipelining might be my favorite programming language feature

herecomesthemoon.net

191–200 of 360 posts

Re: Pipelining might be my favorite programming language feature

#191

Earlier quoted context omitted.

We might be able to cross one more language off your wishlist soon, Javascript is on the way to getting a pipeline operator, the proposal is currently at Stage 2 https://github.com/tc39/proposal-pipeline-operator I'm very excited for it.

It also has barely seen any activity in years. It is going nowhere. The TC39 committee is utterly dysfunctional and anti-progress, and will not let any this or any other new syntax into JavaScript. Records and tuples has just been killed, despite being cited in surveys as a major missing feature[1]. Pattern matching is stuck in stage 1 and hasn't been presented since 2022. Ditto for type annotations and a million oth…

I wouldn’t hold your breath for TypeScript introducing any new supra-JS features. In the old days they did a little bit, but now those features (namely enums) are considered harmful.

More specifically, with the (also ironically gummed up in tc39) type syntax [1], and importantly node introducing the --strip-types option [2], TS is only ever going to look more and more like standards compliant JS.

[1] https://tc39.es/proposal-type-annotations/

[2] https://nodejs.org/en/blog/release/v22.6.0

Re: Pipelining might be my favorite programming language feature

#192
post #24

I'm personally someone who advocates for languages to keep their feature set small and shoot to achieve a finished feature set quickly. However. I would be lying if I didn't secretly wish that all languages adopted the `|>` syntax from Elixir. ``` params |> Map.get("user") |> create_user() |> notify_admin() ```

I hate to be that guy, but I believe the `|>` syntax started with F# before Elixir picked it up.

(No disagreements with your post, just want to give credit where it's due. I'm also a big fan of the syntax)

Re: Pipelining might be my favorite programming language feature

#193
Pipelining is great. Currying is horrible. Though currying superficially looks similar to pipelining.

One difference is that currying returns an incomplete result (another function) which must be called again at a later time. On the other hand, pipelining usually returns raw values. Currying returns functions until the last step. The main philosophical failure of currying is that it treats logic/functions as if they were state which should be passed around. This is bad. Components should be responsible for their own state and should just talk to each other to pass plain information. State moves, logic doesn't move. A module shouldn't have awareness of what tools/logic other modules need to do their jobs. This completely breaks the separation of concerns principle.

When you call a plumber to fix your drain, do you need to provide them with a toolbox? Do you even need to know what's inside their toolbox? The plumber knows what tools they need. You just show them what the problem is. Passing functions to another module is like giving a plumber a toolbox which you put together by guessing what tools they might need. You're not a plumber, why should you decide what tools the plumber needs?

Currying encourages spaghetti code which is difficult to follow when functions are passed between different modules to complete the currying. In practice, if one can design code which gathers all the info it needs before calling the function once; this leads to much cleaner and much more readable code.

Re: Pipelining might be my favorite programming language feature

#194
post #24

I'm personally someone who advocates for languages to keep their feature set small and shoot to achieve a finished feature set quickly. However. I would be lying if I didn't secretly wish that all languages adopted the `|>` syntax from Elixir. ``` params |> Map.get("user") |> create_user() |> notify_admin() ```

I hate to be that guy , but I believe the `|>` syntax started with F# before Elixir picked it up. (No disagreements with your post, just want to give credit where it's due. I'm also a big fan of the syntax)

I turn older then f#, it’s been an ML language thing for a while but not sure where it first appeared

Re: Pipelining might be my favorite programming language feature

#195
> (This is not real Rust code. Quick challenge for the curious Rustacean, can you explain why we cannot rewrite the above code like this, even if we import all of the symbols?)

Um, you can:

        #![feature(import_trait_associated_functions)]
        use Iterator::{collect, map, filter};
        
        fn get_ids2(data: Vec) -> Vec {
            collect(map(filter(::iter(&data), |v| ...), |v| ...))
        }
and you can because it's lazy, which is also the same reason you can write it the other way.. in rust. I think the author was getting at an ownership trap, but that trap is avoided the same way for both arrangements, the call order is the same in both arrangements. If the calls were actually a pipeline (if collect didn't exist and didn't need to be called) then other considerations show up.

Re: Pipelining might be my favorite programming language feature

#196
post #143

Pipelining looks nice until you have to debug it. And exception handling is also very difficult, because that means to add forks into your pipelines. Pipelines are only good for programming the happy path.

Established debugging tools and logging rubric are not suitable for debugging heavily pipelined code. Stack traces, debuggers rely heavily on line based references which are less useful in this style and can make diagnostic practices feel a little clumsy.

The old adage of not writing code so smart you can’t debug it applies here.

Pipelining runs contrary enough to standard imperative patterns. You don’t just need a new mindset to write code this way. You need to think differently about how you structure your code overall and you need different tools.

That’s not to say that doing things a different way isn’t great, but it does come with baggage that you need to be in a position to carry.

Re: Pipelining might be my favorite programming language feature

#197

I feel like, at least in some cases, the article is going out of its way to make the "undesired" look worse than it needs to be. Compairing fn get_ids(data: Vec ) -> Vec { collect(map(filter(map(iter(data), |w| w.toWingding()), |w| w.alive), |w| w.id)) } to fn get_ids(data: Vec ) -> Vec { data.iter() .map(|w| w.toWingding()) .filter(|w| w.alive) .map(|w| w.id) .collect() } The first one would read more easily (and, s…

In my eyes newlines don't solve what I feel to be the issue. Reader needs to recognize reading from left->right to right->left. Of course this really only matters when you're 25 minutes into critical downtime and a bug is hiding somewhere in these method chains. Anything that is surprising needs to go. IMHO it would be better to set intermediate variables with dead simple names instead of newlines. fn get_ids(data: V…

> Reader needs to recognize reading from left->right to right->left.

Yeah, I agree. The problem is that you have to keep track of nesting in the middle of the expression and then unnest it at the end, which is taxing.

So, I also think it could also read better written like this, with the arguments reversed, so you don't have to read it both ways:

  fn get_ids(data: Vec) -> Vec {
      collect(
         map(|w| w.id,
             filter |w| w.alive,
               (map(|w| w.toWingding(), iter(data)))))
  }
That's also what they do in Haskell. The first argument to map is the mapping function, the first argument to filter is the predicate function, and so on. People will often just write the equivalent of:

  getIDs = map getID . filter alive . map toWingDing
as their function definitions, with the argument omitted because using the function composition operator looks neater than using a bunch of dollar signs or parentheses.

Making it the second argument only makes sense when functions are written after their first argument, not before, to facilitate writing "foo.map(f).filter(y)".

Re: Pipelining might be my favorite programming language feature

#198
Every example of why this is meant to be good is contrived.

You have a create_user function that doesn't error? Has no branches based on type of error?

We're having arguments over the best way break these over multiple lines?

Like.. why not just store intermediate results in variables? Where our branch logic can just be written inline? And then the flow of data can be very simply determined by reading top to bottom?

Re: Pipelining might be my favorite programming language feature

#199
post #143

Pipelining looks nice until you have to debug it. And exception handling is also very difficult, because that means to add forks into your pipelines. Pipelines are only good for programming the happy path.

Pipelining is just syntactic sugar for nested function calls.

If you need to handle an unhappy path in a way that isn’t optimal for nested function calls then you shouldn’t be nesting your function calls. Pipelining doesn’t magically make things easier nor harder in that regard.

But if a particular sequence of function calls do suit nesting, then pipelining makes the code much more readable because you’re not mixing right-to-left syntax (function nests) with left-to-right syntax (ie you’re typical language syntax).

Re: Pipelining might be my favorite programming language feature

#200
post #147

Earlier quoted context omitted.

The pipe operator relies on the first argument being the subject of the operation. A lot of languages have the arguments in a different order, and OO languages sometimes use function chaining to get a similar result.

IIRC the usual workaround in Elixir involves be small lambda that rearranges things: "World" |> then(&concat("Hello ", &1)) I imagine a shorter syntax could someday be possible, where some special placeholder expression could be used, ex: "World" |> concat("Hello ", &1) However that creates a new problem: If the implicit-first-argument form is still permitted (foo() instead of foo(&1)) then it becomes confusing which…

Yeah, R (tidyverse) has `.` as such a placeholder. It is useful but indeed I find the syntax off, though I find the syntax off even without it, anyway. I would rather define pipes as compositions of functions, which are pretty unambiguous in terms of what arguments they get, and then apply these to whatever i want.
Post reply on HN