sort API design

mipri mipri at minimaltype.com
Fri Nov 22 02:25:42 UTC 2019


On Thursday, 21 November 2019 at 23:28:48 UTC, Jonathan M Davis 
wrote:
> So, I'm sorry that you gotten bitten by sort not working the
> way you expected, but I don't see how that could have been
> prevented without implementing the range in the way that you
> expected, which would then screw over anyone who assumed that
> the range would be sorted in-place.

I don't disagree, but the problem also wasn't presented as a 
defect
of Phobos, but as "I did wrote this code. I learned it was wrong.
How might my error have been averted?"

 From some other languages,

| Language | Sort        | Mutates? | Returns? | Both? |
|----------+-------------+----------+----------+-------|
| Perl     | sort        | No       | Yes      | No    |
| Python   | list.sort   | Yes      | No       | No    |
| Python   | list.sorted | No       | Yes      | No    |
| C        | qsort       | Yes      | No       | No    |
| C++      | std::sort   | Yes      | No       | No    |
| Rust     | vec::sort   | Yes      | No       | No    |

The norm is to do one or the other, and not both.

Why does D do both? Because it has an efficiency focus (avoid
unnecessary copying) and also an expressiveness focus (go ahead 
and
do things with long pipelines of transformations), and this
combination is uncommon.

Actually I'm surprised Rust doesn't do both... and come to think 
of
it, I *was* surprised by that, when I rewrote a benchmark in it: I
tried putting the .sort_by() in the middle of a pipeline of
function calls and was confused by the error. So I had the exact
opposite "I did a thing. I learned it was wrong." problem with
sorting in Rust.

There's another reason D does both: 
thing.change().change().change()
is how you build pipelines in D, and each of these change()
functions needs to return the input to the next change(). But 
note,
this isn't a deliberate language feature, it's not taking 
advantage
of "pipeline syntax", it's just a consequence of how methods work
in OOP languages.

So it's more like a pattern :) One of those awful things that
highlights a failure of language design, where programmers, 
instead
of directly expressing their intentions with code, must 
laboriously
work around a void in the language. Or so I hear.

https://www.martinfowler.com/articles/collection-pipeline/
https://clojure.org/guides/threading_macros

Suppose, instead of expecting D programmers to make use of the
"collection pipelien" pattern, D just had a collection pipeline
feature? Like:

   thing |> change1() |> change2() |> change3()

If it's a language feature, D can, since it knows the types of all
these functions, apply a rule like

   if a function is void, reuse the last input for the next 
function
   otherwise, behave like . chaining

With this, Phobos could have a void sort that could still appear 
in
the middle of a long pipeline of transformations, and confusions
like the one in this thread about Phobos, and *also* the one I had
about Rust's sort, would both not be possible.

Instead you'd have the new potential confusion of thinking that
sort doesn't mutate because you saw it in a pipeline :)


To be clear, I don't recommend changing anything. I just think 
it's
not true that D has nothing to do with this.



More information about the Digitalmars-d mailing list