Live data from Hacker News

Pipelining might be my favorite programming language feature

herecomesthemoon.net

221–230 of 360 posts

Re: Pipelining might be my favorite programming language feature

#221

The author keeps calling it "pipelining", but I think the right term is "method chaining". Compare with a simple pipeline in bash: grep needle Each of those components executes in parallel, with the intermediate results streaming between them. You get a similar effect with coroutines. Compare Ruby: data = File.readlines("haystack.txt") .map(&:strip) .grep(/needle/) .map { |i| i.gsub('foo', 'bar') } .map { |i| File.re…

> The author keeps calling it "pipelining", but I think the right term is "method chaining".

I believe the correct definition for this concept is the Thrush combinator[0]. In some ML-based languages[1], such as F#, the |> operator is defined[2] for same:

  [1..10] |> List.map (fun i -> i + 1)
Other functional languages have libraries which also provide this operator, such as the Scala Mouse[3] project.

0 - https://leanpub.com/combinators/read#leanpub-auto-the-thrush

1 - https://en.wikipedia.org/wiki/ML_(programming_language)

2 - https://fsharpforfunandprofit.com/posts/defining-functions/

3 - https://github.com/typelevel/mouse?tab=readme-ov-file

Re: Pipelining might be my favorite programming language feature

#222
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 would be lying if I didn't secretly wish that all languages adopted the `|>` syntax from Elixir.

This is usually the Thrush combinator[0], exists in other languages as well, and can be informally defined as:

  f(g(x)) = g(x) |> f
0 - https://leanpub.com/combinators/read#leanpub-auto-the-thrush

Re: Pipelining might be my favorite programming language feature

#223
post #134

Lisp macros allow a general solution to this that doesn't just handle chained collection operators but allows you to decide the order in which you write any chain of calls. For example, we can write: (foo (bar (baz x))) as (-> x baz bar foo) If there are additional arguments, we can accommodate those too: (sin (* x pi) as (-> x (* pi) sin) Where expression so far gets inserted as the first argument to any form. If yo…

Yes threading macros are so much nicer than method chaining, because it allows general function reuse, rather than being limited to the methods that happen to be defined in your initial data object.

Re: Pipelining might be my favorite programming language feature

#224
Why is the SQL syntax so unnecessarily convoluted? SQL is already an operator language, just an overly constrained one due to historical baggage. If you're going to allow new syntax at all, you can just do

  from customer
  left join orders on c_custkey = o_custkey and o_comment not like '%unusual%'
  group by c_custkey
  alias count(o_orderkey) as count_of_orders
  group by count_of_orders
  alias count(*) as count_of_customers
  order by count_of_customers desc
  select count_of_customers, count_of_orders;
  
I'm using 'alias' here as a strawman keyword for what the slide deck calls a free-standing 'as' operator because you can't reuse that keyword, it makes the grammar a mess.

The aliases aren't really necessary, you could just write the last line as 'select count(count(*)) ncust, count(*) nord' if you aren't afraid of nested aggregations, and if you are you'll never understand window functions, soo...

The |> syntax adds visual noise without expressive power, and the novelty 'aggregate'/'call' operators are weird special-case syntax for something that isn't that complex in the first place.

The implicit projection is unnecessary too, for the same reason any decent SQL linter will flag an ambiguous 'select *'

Re: Pipelining might be my favorite programming language feature

#225

Earlier quoted context omitted.

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…

Records and Tuples weren't stopped because of tc39, but rather the engine developers. Read the notes.

Aren't the engine devs all part of the TC39 committee? I know they stopped SIMD in JS because they were mire interested in shipping WASM, and then adding SIMD to it.

Re: Pipelining might be my favorite programming language feature

#226

Why is the SQL syntax so unnecessarily convoluted? SQL is already an operator language, just an overly constrained one due to historical baggage. If you're going to allow new syntax at all, you can just do from customer left join orders on c_custkey = o_custkey and o_comment not like '%unusual%' group by c_custkey alias count(o_orderkey) as count_of_orders group by count_of_orders alias count(*) as count_of_customers…

I think they are solving two different problems at the same time. One is the order of elements in a single operation (SELECT then FROM then WHERE etc), and the second is the actual pipelining which replaces the need for nested queries.

It does seem like the former could be solved by just loosening up the grammar to allow you to specify things in any order. Eg this seems perfectly unambiguous:

  from customer
  group by c_custkey
  select c_custkey, count(*) as count_of_customers

Re: Pipelining might be my favorite programming language feature

#227
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 prefer Scala. You can write ``` params.get("user") |> create_user |> notify_admin ``` Even more concise and it doesn't even require a special language feature, it's just regular syntax of the language ( |> is a method like .get(...) so you could even write `params.get("user").|>(create_user) if you wanted to)

Isn't it being a method call not quite equivalent? Are you able to define the method over arbitrary data types?

In Elixir, it is just a macro so it applies to all functions. I'm only a Scala novice so I'm not sure how it would work there.

Re: Pipelining might be my favorite programming language feature

#229
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…

Last time I checked (2020) there were already a few rejected proposals to shorten the syntax for this. It seemed like they were pretty exasperated by them at the time.

Re: Pipelining might be my favorite programming language feature

#230

Earlier quoted context omitted.

I prefer Scala. You can write ``` params.get("user") |> create_user |> notify_admin ``` Even more concise and it doesn't even require a special language feature, it's just regular syntax of the language ( |> is a method like .get(...) so you could even write `params.get("user").|>(create_user) if you wanted to)

Isn't it being a method call not quite equivalent? Are you able to define the method over arbitrary data types? In Elixir, it is just a macro so it applies to all functions. I'm only a Scala novice so I'm not sure how it would work there.

> Are you able to define the method over arbitrary data types?

Yes exactly, which is why it is not equivalent. No macro needed here. In Scala 2 syntax:

``` implicit class AnyOps[A](private val a: A) extends AnyVal { def |>[B](f: A => B) = f(a) } ```

Post reply on HN