develooper Front page | perl.perl5.porters | Postings from July 2021

Re: Elevator pitch, deprecating $a/$b sort globals by using sub{}

Thread Previous | Thread Next
From:
Dan Book
Date:
July 6, 2021 15:28
Subject:
Re: Elevator pitch, deprecating $a/$b sort globals by using sub{}
Message ID:
CABMkAVW_cZPagEgrx82=BMXi4k9kHS7oukGH9FbOwonWPxhcpA@mail.gmail.com
On Tue, Jul 6, 2021 at 5:49 AM Smylers <Smylers@stripey.com> wrote:

> Nicholas Clark writes:
>
> > On Sun, Jul 04, 2021 at 05:40:09PM +0200, Martijn Lievaart wrote:
> >
> > >     sort sub($a,$b){ $a->{x} <=> $b->{x} } @list
> >
> > The first thing that thought was that this makes sort special,
> > compared with the other builtins that take blocks (map, grep)
> >
> > But those take one implicit argument, for which $_ works just fine.
> >
> > Our problem here is that sort needs two implicit arguments.
>
> Does it?
>
> I mean, yes, obviously at the moment a sort routine requires two
> arguments. But how common is it for those not to be duplicates of each
> other? That is, in:
>
>     sort { f($a) <=> g($b) } @list
>
> f() and g() are overwhelmingly identical operations. And if either of
> them are involved, it's irksome to have to duplicate the operation on
> both sides:
>
>     sort { lc "$a->{somefield}->@*" cmp lc "$b->{somefeild}->@*" } @list
>
> [Ooops — typo in the second hash key!]
>
> If we're looking at re-doing sort, it might be worth considering whether
> this repetition can be avoided, rather than just at different ways of
> specifying it.
>
> Sort needs to know:
>
> 1.  How to transform an item into a key to use for comparison.
> 2.  Whether to compare with <=> or cmp.
> 3.  Whether the output should be ascending or descending.
>
> So instead of $a and $b, a sort routine could be specified with $_ and
> an indication of whether to use <=> or cmp.
>
> One possible design (to show the concept; I'm not suggesting
> specifically this):
>
>     asort { lc "$_->{somefield}->@*" } @list
>
>     reverse nsort { $_->{age} } @list
>
> That is:
>
> 1.  A single (optional) block takes $_ and returns the sort key.
> 2.  Comparison operator specified with the function name — cos this
>     seems less messy than trying to force it into an argument somewhere.
> 3.  Ascending by default; reverse is available for occasions where
>     descending is required.
>
> And it gets rid of $a and $b.


See sort_by and nsort_by in List::UtilsBy for prior art. The main weakness
of this approach is that it does not allow you to chain comparisons, a
common way to specify how to compare entries which are considered
equivalent by the first comparison. Also that you must have separate
functions for different comparison operators and directions (though reverse
could be optimized for a core version of this operator).

my @sorted = sort { foo($a) <=> foo($b) || bar($b) cmp bar($a) } @stuff; #
not possible with *sort_by

I think *sort_by are still worthwhile ops to core eventually, even if just
by putting them in List::Util, but this really should be kept to a new
thread.

-Dan

Thread Previous | Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About