Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Perl > Perl Misc > Why does sort return undef in scalar context ?

Reply
Thread Tools

Why does sort return undef in scalar context ?

 
 
Willem
Guest
Posts: n/a
 
      08-29-2011
Today I got bitten by a very strange bug/feature:

I wrote a function that returned a sorted list of things.
This function was used in several places, sometimes to use the things in
some way, and in one place just to check if it returned any things.

For example:

....
for my $s (get_sorted_things($foo)) {
do_something_with($s);
}
....
if (get_sorted_things($bar)) {
warn "There were things for $bar!\n";
}
....
sub get_sorted_things
{
my %unique = map { $_->Key => $_ } get_things();
return sort { $a->Property cmp $b->Property } values %unique;
}

And, because somebody decided that sort should always return undef
when called in scalar context, this does not work!

Why was it decided that sort returns undef in scalar context ?
IMO it is much more logical and consistent to have it return the
number of objects in the list that is to be sorted (it doesn't even
need to sort them for that).


SaSW, Willem
--
Disclaimer: I am in no way responsible for any of the statements
made in the above text. For all I know I might be
drugged or something..
No I'm not paranoid. You all think I'm paranoid, don't you !
#EOT
 
Reply With Quote
 
 
 
 
sln@netherlands.com
Guest
Posts: n/a
 
      08-29-2011
On Mon, 29 Aug 2011 20:36:26 +0000 (UTC), Willem <(E-Mail Removed)> wrote:

>Today I got bitten by a very strange bug/feature:
>
>I wrote a function that returned a sorted list of things.
>This function was used in several places, sometimes to use the things in
>some way, and in one place just to check if it returned any things.
>
>For example:
>
>...
>for my $s (get_sorted_things($foo)) {
> do_something_with($s);
>}
>...
>if (get_sorted_things($bar)) {
> warn "There were things for $bar!\n";
>}
>...
>sub get_sorted_things
>{
> my %unique = map { $_->Key => $_ } get_things();
> return sort { $a->Property cmp $b->Property } values %unique;
>}
>
>And, because somebody decided that sort should always return undef
>when called in scalar context, this does not work!
>
>Why was it decided that sort returns undef in scalar context ?
>IMO it is much more logical and consistent to have it return the
>number of objects in the list that is to be sorted (it doesn't even
> need to sort them for that).
>
>


I don't know why this is the case, but you should fix it up in the
function that wraps the return of sort().

$ret = get_sort_stuff('aa'=>8, 'bb' => 1 );
print "a_ret = $ret\n\n";

@ret = get_sort_stuff('aa'=>8, 'bb' => 1 );
print "b_ret = @ret\n\n";

$ret = get_sort_stuff();
print "c_ret = $ret\n\n";

@ret = get_sort_stuff();
print "d_ret = @ret\n\n";

if (get_sort_stuff('aa'=>8, 'bb' => 1 )) {
print "conditional > 0\n\n"
}

if (!get_sort_stuff()) {
print "conditional = 0\n"
}


sub get_sort_stuff {
my %unique = @_;
print wantarray ? 'wantarray = 1' : 'wantarray = 0', "\n";
return wantarray ?
sort values %unique :
values %unique ;
}

-sln
 
Reply With Quote
 
 
 
 
Rainer Weikusat
Guest
Posts: n/a
 
      08-30-2011
Willem <(E-Mail Removed)> writes:

[...]

> for my $s (get_sorted_things($foo)) {
> do_something_with($s);
> }
> ...
> if (get_sorted_things($bar)) {
> warn "There were things for $bar!\n";
> }
> ...
> sub get_sorted_things
> {
> my %unique = map { $_->Key => $_ } get_things();
> return sort { $a->Property cmp $b->Property } values %unique;
> }
>
> And, because somebody decided that sort should always return undef
> when called in scalar context, this does not work!


The sort documentation actually says

sort SUBNAME LIST
sort BLOCK LIST
sort LIST

In list context, this sorts the LIST and returns the
sorted list value. In scalar context, the behaviour of
"sort()" is undefined.

> Why was it decided that sort returns undef in scalar context ?
> IMO it is much more logical and consistent to have it return the
> number of objects in the list that is to be sorted


'Much more logical' seems like a matter of opinion here. But it is
certainly not 'more consistent since evaluating a list in scalar
context returns the final element "as with the C comma operator"
(perldata(1)). Evaluating an array in scalar context yields the number
of elements in the array. The keys function behaves in this way but
expecting that to return the number of keys in a scalar context makes
IMHO more sense than expecting sort to return the number of items to
be sorted in a scalar context.
 
Reply With Quote
 
Keith Thompson
Guest
Posts: n/a
 
      08-30-2011
Willem <(E-Mail Removed)> writes:
> Today I got bitten by a very strange bug/feature:
>
> I wrote a function that returned a sorted list of things.
> This function was used in several places, sometimes to use the things in
> some way, and in one place just to check if it returned any things.
>
> For example:
>
> ...
> for my $s (get_sorted_things($foo)) {
> do_something_with($s);
> }
> ...
> if (get_sorted_things($bar)) {
> warn "There were things for $bar!\n";
> }
> ...
> sub get_sorted_things
> {
> my %unique = map { $_->Key => $_ } get_things();
> return sort { $a->Property cmp $b->Property } values %unique;
> }
>
> And, because somebody decided that sort should always return undef
> when called in scalar context, this does not work!
>
> Why was it decided that sort returns undef in scalar context ?
> IMO it is much more logical and consistent to have it return the
> number of objects in the list that is to be sorted (it doesn't even
> need to sort them for that).


Any "sensible" behavior for sort() in scalar context would not (need to)
sort anything -- which implies to me that calling sort() in such a
context doesn't make much sense. Similarly, "get_sorted_things($bar)"
would be better written as some other operation on $bar that doesn't
imply an unnecessary expensive sort.

As Rainer Weikusat points out, the behavior of sort() in scalar context
is actually undefined. IMHO it would make more sense for it to be an
error.

--
Keith Thompson (The_Other_Keith) http://www.velocityreviews.com/forums/(E-Mail Removed) <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
 
Reply With Quote
 
Willem
Guest
Posts: n/a
 
      08-30-2011
Tad McClellan wrote:
) Willem <(E-Mail Removed)> wrote:
)> Today I got bitten by a very strange bug/feature:
)>
)> I wrote a function that returned a sorted list of things.
<snip>
)> sub get_sorted_things
)> {
)> my %unique = map { $_->Key => $_ } get_things();
)> return sort { $a->Property cmp $b->Property } values %unique;
)> }
)
) ... but get_sorted_things() does not consult any arguments!
)
) What is the relationship between $foo and $bar and get_things()?

It was JUST AN EXAMPLE! I happened to forget to include the argument.
Here, I'll fix it for you:

sub get_sorted_things
{
my ($arg) = @_;
my %unique = map { $_->Key => $_ } get_things($arg);
return sort { $a->Property cmp $b->Property } values %unique;
}

Better ? Or are you going to harp about that you don't know what
get_things does ? It's irrelevant to the point of the example.

) Before I got to the definition of get_sorted_things(),
) I had guessed that $bar was an arrayref of things to sort,
) if it was then you could just do:
)
) if (@$bar) {
) warn "There were things for $bar!\n";
)
) But it isn't. So you can't.
)
) And since I don't know what $bar is, I cannot even attempt to
) help you here.

I don't need help. The code is just to exemplify what I ran into.
I came up with a workaround as soon as I figured out the bug in sort().
The arguments are irrelevant; all they do is show that the function
returns a different sorted list on different invocations.

What I want to know is *why* Larry chose to have sort() return undef
in scalar context.

)> And, because somebody
)
) Larry Wall.
)
)> decided that sort should always return undef
)> when called in scalar context, this does not work!
)
) So fix it!
)
) sub get_sorted_things {
) die "get_sorted_things() was called with a useless argument\n" if @_;
)
) my %unique = map { $_->Key => $_ } get_things();
) if (wantarry) {
) return sort { $a->Property cmp $b->Property } values %unique;
) }
) else {
) return keys %unique;
) }
) }

I am very well aware that (and how) you can workaround that bug, TYVM.

)> Why was it decided that sort returns undef in scalar context ?
)
) I dunno.
)
) Have to ask Larry, or search for comments in the perl code I guess.
)
) I would want it to return the first element, or the last element,
) or the median element, or ... but all of those would O(n log n),
) (ie. expensive, there are algorithms for determinig those things that
) have a better running time) so then I'd give up and make it
) undefined in a scalar context.
)
) I don't know if that was his thinking or not.

Well, if you use an array in scalar context, you get the count of items.
If you use sort on an array, you get an array. Therefore, if you use sort
on an array in scalar context, you should get the count of the array.

I am well aware that you actually get a list, and that a list in scalar
context does something different than an array in scalar context. That
alone is quite horrid, IMO.

)> IMO it is much more logical and consistent to have it return the
)> number of objects in the list that is to be sorted
)
) If you are writing a call to sort(), then you already know the list
) of things that you are going to ask sort() to sort.

Not always, which is why I provided the example above.

) Why run it through another function only to find out something
) that you already have access to?

Reusability.
Here's the same example, but abstractly:

- I have a function that does some work to retrieve a list of items, and as
the final step it sorts the items.
- Most of the time, I want to use the sorted list (in order), but sometimes
I just want to check if there were any items.

Now, because sort() returns undef, I have to make two separate functions,
one which returns the list, and another that returns the sorted list.
(The second uses the first of course).

I consider that a workaround.

) Why would we want to call a function named sort() if we wanted
) something that did not even require sorting?

Reusability. Polymorphism. Consistency. See above.


SaSW, Willem
--
Disclaimer: I am in no way responsible for any of the statements
made in the above text. For all I know I might be
drugged or something..
No I'm not paranoid. You all think I'm paranoid, don't you !
#EOT
 
Reply With Quote
 
Willem
Guest
Posts: n/a
 
      08-30-2011
(E-Mail Removed) wrote:
) I don't know why this is the case, but you should fix it up in the
) function that wraps the return of sort().

My apologies.
I hadn't made clear that I was well aware how to work around this issue.


SaSW, Willem
--
Disclaimer: I am in no way responsible for any of the statements
made in the above text. For all I know I might be
drugged or something..
No I'm not paranoid. You all think I'm paranoid, don't you !
#EOT
 
Reply With Quote
 
Wolf Behrenhoff
Guest
Posts: n/a
 
      08-30-2011
Am 30.08.2011 18:51, schrieb Willem:
> Now, because sort() returns undef, I have to make two separate functions,
> one which returns the list, and another that returns the sorted list.
> (The second uses the first of course).


Well, you could force list context.

$ perl -E'sub x{return sort qw(1 4 2)}; $n=()=x(); say $n'
3

- Wolf
 
Reply With Quote
 
Willem
Guest
Posts: n/a
 
      08-30-2011
Rainer Weikusat wrote:
) The sort documentation actually says
)
) sort SUBNAME LIST
) sort BLOCK LIST
) sort LIST
)
) In list context, this sorts the LIST and returns the
) sorted list value. In scalar context, the behaviour of
) "sort()" is undefined.

Ah, I must have found some different documentation.

)> Why was it decided that sort returns undef in scalar context ?
)> IMO it is much more logical and consistent to have it return the
)> number of objects in the list that is to be sorted
)
) 'Much more logical' seems like a matter of opinion here. But it is
) certainly not 'more consistent since evaluating a list in scalar
) context returns the final element "as with the C comma operator"

The same could be said for map and grep. But those do return the count.

) (perldata(1)). Evaluating an array in scalar context yields the number
) of elements in the array. The keys function behaves in this way but
) expecting that to return the number of keys in a scalar context makes
) IMHO more sense than expecting sort to return the number of items to
) be sorted in a scalar context.

IMO it's irrelevant that it makes "more" sense.
I'm just countering the argument that it "doesn't make sense"
by providing an example where it does make sense.

If you were to say "It doesn't make enough sense to warrant implementing
it that way", then *that* would be a matter of opinion.


SaSW, Willem
--
Disclaimer: I am in no way responsible for any of the statements
made in the above text. For all I know I might be
drugged or something..
No I'm not paranoid. You all think I'm paranoid, don't you !
#EOT
 
Reply With Quote
 
Rainer Weikusat
Guest
Posts: n/a
 
      08-30-2011
Willem <(E-Mail Removed)> writes:
> Rainer Weikusat wrote:


[...]

> )> Why was it decided that sort returns undef in scalar context ?
> )> IMO it is much more logical and consistent to have it return the
> )> number of objects in the list that is to be sorted
> )
> ) 'Much more logical' seems like a matter of opinion here. But it is
> ) certainly not 'more consistent since evaluating a list in scalar
> ) context returns the final element "as with the C comma operator"
>
> The same could be said for map and grep. But those do return the count.
>
> ) (perldata(1)). Evaluating an array in scalar context yields the number
> ) of elements in the array. The keys function behaves in this way but
> ) expecting that to return the number of keys in a scalar context makes
> ) IMHO more sense than expecting sort to return the number of items to
> ) be sorted in a scalar context.
>
> IMO it's irrelevant that it makes "more" sense.
> I'm just countering the argument that it "doesn't make sense"
> by providing an example where it does make sense.


The purpose of map and grep is to produce an output list based on some
input list and 'an operation' which is sucessively performed on each
element of the input list. In both cases, the number of elements on
the output list can be different from the number of elements on the
input list, trivially for grep because its purpose is to filter the
input list based on the return value of the operation and somewhat
less trivially for map because 'the operation' may return an arbitrary
number of output elements for each input element. In contrast to this,
the purpose of sort is to return a permutation of the elements on the
input list which implies that the number doesn't change. Consequently,
it is pointless to invoke sort to determine this number.

There is actually at least on similar operation in Perl, namely,
reverse, which also returns a permutation of the input list. In scalar
context, it will concatenate whatever the elements on the list
stringify to and return a reversed string. This seems a little
arbitrary and not really useful in many cases, eg,

[rw@tear]~ $perl -de 0

Loading DB routines from perl5db.pl version 1.3
Editor support available.

Enter h or `h h' for help, or `man perldebug' for more help.

main:-e:1): 0
DB<1> print scalar(reverse(\$a, \$b, \$c))
)0efcb38x0(RALACS)0ffcb38x0(RALACS)040db38x0(RALAC S

and extending this to sort, while 'consistent' also doesn't exactly
appear useful:

DB<2> print join('', sort(split(//, join('', \$a, \$b, \$c))))
((()))00000003334888AAAAAACCCLLLRRRSSSbbbccdefffxx x

 
Reply With Quote
 
Randal L. Schwartz
Guest
Posts: n/a
 
      08-30-2011
>>>>> "Willem" == Willem <(E-Mail Removed)> writes:

Willem> ) 'Much more logical' seems like a matter of opinion here. But it is
Willem> ) certainly not 'more consistent since evaluating a list in scalar
Willem> ) context returns the final element "as with the C comma operator"

Willem> The same could be said for map and grep. But those do return
Willem> the count.

They return the count because the count is variable and can't be
determined by a trivial inspection of the input.

print "Just another Perl hacker,"; # the original

--
Randal L. Schwartz - Stonehenge Consulting Services, Inc. - +1 503 777 0095
<(E-Mail Removed)> <URL:http://www.stonehenge.com/merlyn/>
Smalltalk/Perl/Unix consulting, Technical writing, Comedy, etc. etc.
See http://methodsandmessages.posterous.com/ for Smalltalk discussion
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
undef($foo) versus $foo = undef()? Tim McDaniel Perl Misc 6 08-19-2009 08:31 AM
WHY are args for sprintf in scalar context? w.c.humann@arcor.de Perl Misc 1 10-31-2007 04:11 PM
findcontrol("PlaceHolderPrice") why why why why why why why why why why why Mr. SweatyFinger ASP .Net 2 12-02-2006 03:46 PM
Replace scalar in another scalar Mark Perl Misc 4 01-27-2005 02:48 PM
Shorthand for($scalar) loops and resetting pos($scalar) Clint Olsen Perl Misc 6 11-13-2003 12:50 AM



Advertisments