Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

return sort (@ary) --- sort() bug?

5 views
Skip to first unread message

Jay Hannah

unread,
Apr 22, 2004, 12:25:16 PM4/22/04
to perl5-...@perl.org

perl 5.6.1 and 5.8.3 on linux:

Program:
---
print
"go array context: ", go(), "\n",
"go scalar context: ", scalar(go()), "\n",
"go2 array context: ", go2(), "\n",
"go2 scalar context: ", scalar(go2()), "\n";

sub go {
return sort (3,2,1);
}

sub go2 {
my @return = sort (3,2,1);
return @return;
}
---

Output:
---
go array context: 123
go scalar context:
go2 array context: 123
go2 scalar context: 3
---

My actual case is an OO method.

I thought the 2nd line of output was a bug. As a work around to go() I wrote go2(), which behaves as expected.

Writing this email, I think I learned that 'return EXPR' returns EXPR unevaluated. I thought EXPR was evaluated first and then returned. I hope I learned that correctly.

Understanding that, now I'm wondering why sort() returns undef in scalar context. Shouldn't sort in scalar context return the number of elements sorted?

10 years of Perl and I'm still learning new things... -grin-

Thanks,

Jay Hannah
Director of Development
Omni Hotels Reservation Center
Tel: (402) 952-6573
Mobile: (402) 578-3976
Email: jha...@omnihotels.com

Come see San Diego as you've never seen it before. It's a "Whole New View" from the new Omni San Diego Hotel, with spectacular views of downtown, the bay and PETCO Park. Learn more at www.omnisandiegohotel.com.


Jeff 'Japhy' Pinyan

unread,
Apr 22, 2004, 12:32:38 PM4/22/04
to Jay Hannah, perl5-...@perl.org
On Apr 22, Jay Hannah said:

>print


> "go scalar context: ", scalar(go()), "\n",
>

>sub go {
> return sort (3,2,1);
>}
>

>go scalar context:

>I thought the 2nd line of output was a bug. As a work around to go() I
>wrote go2(), which behaves as expected.
>
>Writing this email, I think I learned that 'return EXPR' returns EXPR
>unevaluated. I thought EXPR was evaluated first and then returned. I hope
>I learned that correctly.

It's evaluated in the context that the function is called in.

>Understanding that, now I'm wondering why sort() returns undef in scalar
>context. Shouldn't sort in scalar context return the number of elements
>sorted?

It's not a bug, because it's not documented to return anything useful in
scalar context. And if sort() in scalar context *should* return the
number of elements sorted, why not save time and just return the number of
elements?

--
Jeff "japhy" Pinyan ja...@pobox.com http://www.pobox.com/~japhy/
RPI Acacia brother #734 http://www.perlmonks.org/ http://www.cpan.org/
CPAN ID: PINYAN [Need a programmer? If you like my work, let me know.]
<stu> what does y/// stand for? <tenderpuss> why, yansliterate of course.

Randal L. Schwartz

unread,
Apr 22, 2004, 12:56:32 PM4/22/04
to perl5-...@perl.org, jha...@omnihotels.com
>>>>> "Jay" == Jay Hannah <jha...@omnihotels.com> writes:

Jay> Understanding that, now I'm wondering why sort() returns undef in
Jay> scalar context. Shouldn't sort in scalar context return the
Jay> number of elements sorted?

No. It's not documented that way. It returns undef now. Maybe
in a future Perl it will return "percentage sortedness" if there's
a fast way to calculate that.

Methinks you've fallen into the trap of thinking "you can have a list
value in a scalar context". This can never be true. Instead, each
operation can have a defined scalar behavior and a defined list
behavior.

There are more things that *don't* return length for scalar than do,
actually. (We figured that out once in class.)

Here are some commonly used list returns, and what they do in a scalar
context:

grep - length
map - length
@foo - length (efficiently)
keys/values - length (efficiently)
split - length, but @_ side-effect

(10, 20, 30) - last element
@foo[3..5] - last element
(10, 20, 30)[2, 0] - last element
splice - last element

caller - package name (first element of list return)
each - key (first element)
getpwuid - username (first element)
getpwnam - user ID (*third* element of list return)
glob - "next" item (repeat until undef)
gmtime/localtime - printable string (instead of list of components)
readline/<> - "next" item (repeat until undef)
readpipe/``/qx - one item instead of list of lines
readdir - "next" item (repeat until undef)
reverse - string reverse instead of list reverse
select(4-arg) - $nfound (first element of list)
sort - undef
stat - success value
times - $user (first element)
unpack - first element

Hmm. Maybe this should be added to the perlfaq as a specific list.

--
Randal L. Schwartz - Stonehenge Consulting Services, Inc. - +1 503 777 0095
<mer...@stonehenge.com> <URL:http://www.stonehenge.com/merlyn/>
Perl/Unix/security consulting, Technical writing, Comedy, etc. etc.
See PerlTraining.Stonehenge.com for onsite and open-enrollment Perl training!

Jay Hannah

unread,
Apr 22, 2004, 12:57:20 PM4/22/04
to ja...@pobox.com, perl5-...@perl.org

> From: Jeff 'japhy' Pinyan [mailto:ja...@perlmonk.org]

> >Writing this email, I think I learned that 'return EXPR' returns EXPR
> >unevaluated. I thought EXPR was evaluated first and then returned. I hope
> >I learned that correctly.
>
> It's evaluated in the context that the function is called in.

Yes. Evaluated in that context *after* the return. I thought EXPR was evaluated in the appropriate context and *then* returned. My example taught me that I was wrong.

> >Understanding that, now I'm wondering why sort() returns undef in scalar
> >context. Shouldn't sort in scalar context return the number of elements
> >sorted?
>
> It's not a bug, because it's not documented to return anything useful in
> scalar context.

Understood.

> And if sort() in scalar context *should* return the number of elements
> sorted, why not save time and just return the number of elements?

Agreed.

Would defining the return of sort() in scalar context (the number of elements in the array that would have been sorted) be an improvement to sort()?

Or is it the fault of the class author (me) for writing a method which contains 'return sort (@ary);' when I should have (1) realized that the user of my class might call my method in scalar context, and (2) realized that sort in scalar context is undefined, and therefore (3) added a line of code to sort before I return the array?

It seems to me defining it might be valuable in some cases...? (Especially in OO development?)

Thanks,

Jay Hannah

Chip Salzenberg

unread,
Apr 22, 2004, 1:04:50 PM4/22/04
to Jay Hannah, ja...@pobox.com, perl5-...@perl.org
According to Jay Hannah:
> Jeff Pinyan:

> > It's evaluated in the context that the function is called in.
>
> Yes. Evaluated in that context *after* the return.

No, *before*. The <return> operator has no compile-defined context of
its own. It the context in which the function was called through to
the expression that it its target.

> Would defining the return of sort() in scalar context (the number of
> elements in the array that would have been sorted) be an improvement
> to sort()?

Depends on how you define it. I could define it as the current number
of days until the next US presidential election, for example. But that
wouldn't really be an improvement.
--
Chip Salzenberg - a.k.a. - <ch...@pobox.com>
"I wanted to play hopscotch with the impenetrable mystery of existence,
but he stepped in a wormhole and had to go in early." // MST3K

Chip Salzenberg

unread,
Apr 22, 2004, 1:14:17 PM4/22/04
to Jay Hannah, ja...@pobox.com, perl5-...@perl.org
According to Chip Salzenberg:

> The <return> operator has no compile-defined context of its own.
> It the context in which the function was called through to the
> expression that it its target.

Geeze, I mangled that but good. Let me try again:

The C<return> operator doesn't know at compile time what context it
will impose on its parameters. At runtime, it imposes the context in
which the enclosing function was called. The same is true of a final
expression in a subroutine (e.g. C< sub foo { sort @_ } >).

Randal L. Schwartz

unread,
Apr 22, 2004, 1:21:33 PM4/22/04
to perl5-...@perl.org, ja...@pobox.com
>>>>> "Jeff" == Jeff 'Japhy' Pinyan <ja...@perlmonk.org> writes:

Jeff> It's not a bug, because it's not documented to return anything useful in
Jeff> scalar context.

Actually, it's documented to *not* return anything useful:

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

:-)

Yitzchak Scott-Thoennes

unread,
Apr 22, 2004, 2:00:53 PM4/22/04
to Jay Hannah, ja...@pobox.com, perl5-...@perl.org
On Thu, Apr 22, 2004 at 11:57:20AM -0500, Jay Hannah <jha...@omnihotels.com> wrote:
>
> > From: Jeff 'japhy' Pinyan [mailto:ja...@perlmonk.org]
> > >Writing this email, I think I learned that 'return EXPR' returns EXPR
> > >unevaluated. I thought EXPR was evaluated first and then returned. I hope
> > >I learned that correctly.
> >
> > It's evaluated in the context that the function is called in.
>
> Yes. Evaluated in that context *after* the return. I thought EXPR was evaluated in the appropriate context and *then* returned. My example taught me that I was wrong.

I don't understand you. Can you elaborate? return(expr) certainly evaluates expr in the calling context.

> Would defining the return of sort() in scalar context (the number of elements in the array that would have been sorted) be an improvement to sort()?
>
> Or is it the fault of the class author (me) for writing a method which contains 'return sort (@ary);' when I should have (1) realized that the user of my class might call my method in scalar context, and (2) realized that sort in scalar context is undefined, and therefore (3) added a line of code to sort before I return the array?

It's a very good idea to look at every sub/method you write with an
eye toward what it will do in each of scalar, list, and void context.

> It seems to me defining it might be valuable in some cases...? (Especially in OO development?)

IIRC, the trouble has been that every time it comes up, people start
coming up with really novel things that sort in scalar/void context
should do, and that kind of kills the thread, as no one willing to
actually do the work seems to want bizarre dwimmery.

Jay Hannah

unread,
Apr 22, 2004, 2:11:03 PM4/22/04
to perl5-...@perl.org

> From: Chip Salzenberg [mailto:ch...@tytlal.perlsupport.com]On Behalf Of
> No, *before*. The <return> operator has no compile-defined context of...

I'm sure my "before/after" comments were wrong or irrelevant.

I expected this to print "3":

$ perl -e 'print scalar(go()); sub go { return sort (1,2,3) };'

Nope. It's silly in this example, but it's not so silly in my real (OO) code.

> > Would defining the return of sort() in scalar context (the number of
> > elements in the array that would have been sorted) be an improvement
> > to sort()?
>
> Depends on how you define it. I could define it as the current number
> of days until the next US presidential election, for example.
> But that wouldn't really be an improvement.

Indeed. I thought my sentence explained how I would define it. Let me try again. Proposed:

sort SUBNAME LIST
sort BLOCK LIST
sort LIST


In list context, this sorts the LIST and returns

the sorted list value. In scalar context, "sort()"
returns the number of elements in LIST.

(As japhy mentioned, perl wouldn't have to go through the trouble of actually sorting LIST in scalar context.)

> From: Randal L. Schwartz [mailto:mer...@stonehenge.com]
> Jay> Understanding that, now I'm wondering why sort() returns undef in
> Jay> scalar context. Shouldn't sort in scalar context return the
> Jay> number of elements sorted?
>
> No. It's not documented that way. It returns undef now. Maybe
> in a future Perl it will return "percentage sortedness" if there's
> a fast way to calculate that.

I apologize. I implied bugginess in my sentence when I meant to offer a suggestion for changing sort().

"Percentage sortedness" would certainly be a million times fancier than my proposal. Give me about 5 years if you want me to take a stab at that patch. Then give me another 2 for my subsequent attempts after my first 12 are rejected. -grin-

> From: Yitzchak Scott-Thoennes [mailto:stho...@efn.org]
> It's a very good idea to look at every sub/method you write with an
> eye toward what it will do in each of scalar, list, and void context.

Indeed. I'll be more careful. Thank you.

> > It seems to me defining it might be valuable in some
> cases...? (Especially in OO development?)
>
> IIRC, the trouble has been that every time it comes up, people start
> coming up with really novel things that sort in scalar/void context
> should do, and that kind of kills the thread, as no one willing to
> actually do the work seems to want bizarre dwimmery.

Ah. I'll try to Google up some previous threads. Thanks. My suggestion is the simplest I can think of (short of undef -grin-). And strangely useful, IMHO.

Thanks for humoring me,

Jay Hannah

hubristically suggesting a change to an explicitly documented nonexistant feature in the bedrock of perl...


Torsten Foertsch

unread,
Apr 22, 2004, 2:15:39 PM4/22/04
to jha...@omnihotels.com, ja...@pobox.com, perl5-...@perl.org
On Thursday 22 April 2004 18:57, Jay Hannah wrote:
> Or is it the fault of the class author (me) for writing a method which
> contains 'return sort (@ary);' when I should have (1) realized that the
> user of my class might call my method in scalar context, and (2) realized
> that sort in scalar context is undefined, and therefore (3) added a line of
> code to sort before I return the array?

You can write your return statement this way:

return @{[sort @ary]};

perl -e 'sub x{return @{[sort 3,2,1]};} print "list: ", x, "\n", "scalar: ",
scalar(x), "\n";'
list: 123
scalar: 3

Torsten

Chip Salzenberg

unread,
Apr 22, 2004, 2:28:07 PM4/22/04
to Jay Hannah, perl5-...@perl.org
According to Jay Hannah:

> sort LIST
> In list context, this sorts the LIST and returns
> the sorted list value. In scalar context, "sort()"
> returns the number of elements in LIST.

Not enough value for users. If you want to champion some kind of
return value that is actually useful, I suggest the fraction of pairs
that are in order. Sorted list == 1, reversed list == 0.

Before you assume that a plain count is a useful return value, take a
look at all the operators that do NOT return counts in scalar context
even though they do return lists in list context. The get* functions,
for example.

Use some imagination!

Chip Salzenberg

unread,
Apr 22, 2004, 2:30:30 PM4/22/04
to Jay Hannah, perl5-...@perl.org
According to Jay Hannah:

> $ perl -e 'print scalar(go()); sub go { return sort (1,2,3) };'

By the way, this case illustrates that there's more than one obvious
thing. You happened to want '3' as the length of the list, but you
might have wanted '3' as the last element in the sorted list. That's
what happens if you just return (1,2,3), after all.

Yitzchak Scott-Thoennes

unread,
Apr 22, 2004, 2:31:58 PM4/22/04
to Jay Hannah, perl5-...@perl.org
On Thu, Apr 22, 2004 at 01:11:03PM -0500, Jay Hannah <jha...@omnihotels.com> wrote:
> hubristically suggesting a change to an explicitly documented nonexistant feature in the bedrock of perl...

Not so hubristic. One of the barriers had been that people have
wanted void context sort(@a) to sort @a in place more efficiently than
@a = sort @a would do -- but as of 5.8.4, @a = sort @a is optimized to
be more efficient, so now is a good time to reopen the sort
can-o-worms.

Things to think about:

scalar sort { mangle($a,$b) } LIST may have side effects; should they
take place? (i.e. should sort do anything other than just return the
number of items in LIST)?

The current behavior is useful in that it clues people in that
something undefined is taking place and forces them to decide
what they want (though a warning would force them even more).

Chip Salzenberg

unread,
Apr 22, 2004, 2:29:08 PM4/22/04
to Torsten Foertsch, jha...@omnihotels.com, ja...@pobox.com, perl5-...@perl.org
According to Torsten Foertsch:
> return @{[sort @ary]};

Indeed, though given the overhead of sorting, constructing the array, and
then getting its length, I'd suggest something more like:

wantarray ? sort(@ary) : @ary;

Ovid

unread,
Apr 22, 2004, 3:15:52 PM4/22/04
to Chip Salzenberg, Jay Hannah, perl5-...@perl.org
--- Chip Salzenberg <ch...@pobox.com> wrote:
> According to Jay Hannah:
> > $ perl -e 'print scalar(go()); sub go { return sort (1,2,3) };'
>
> By the way, this case illustrates that there's more than one obvious
> thing. You happened to want '3' as the length of the list, but you
> might have wanted '3' as the last element in the sorted list. That's
> what happens if you just return (1,2,3), after all.

No to blow my own horn, but those issues are pretty easy to get around with Attribute::Context.
It's a generic mechanism for handling those issues.

use base 'Attribute::Context';
sub sort_last : Last(NOVOID) { sort @_ };

Now it will croak in void context, return a list in list context, or return the last element from
the list in scalar context. You could beef it up by allowing an optional sort sub, if preferred.

Cheers,
Ovid

=====
Silence is Evil http://users.easystreet.com/ovid/philosophy/indexdecency.htm
Ovid http://www.perlmonks.org/index.pl?node_id=17000
Web Programming with Perl http://users.easystreet.com/ovid/cgi_course/

Ton Hospel

unread,
Apr 26, 2004, 8:36:02 AM4/26/04
to perl5-...@perl.org
In article <2004042612...@llama.elixent.com>,
Nick Ing-Simmons <ni...@ing-simmons.net> writes:
> The "obvious" (to me) thing for scalar(sort(...)) to return is the
> 1st element of the sorted list - but do it just be one pass to find
> the value.
>
But until it does something like that, make it an error instead of a
warning. I cannot imagine any current use that isn't an error.

Nick Ing-Simmons

unread,
Apr 26, 2004, 8:22:59 AM4/26/04
to jha...@omnihotels.com, ja...@pobox.com, perl5-...@perl.org
Jay Hannah <jha...@omnihotels.com> writes:
>
>Would defining the return of sort() in scalar context (the number of elements
>in the array that would have been sorted) be an improvement to sort()?

It would not make return from your method any more inutitive.
Defining as min() would make most sense, but we have discussed
that on p5p before.

Nick Ing-Simmons

unread,
Apr 26, 2004, 8:28:05 AM4/26/04
to stho...@efn.org, Jay Hannah, perl5-...@perl.org
Yitzchak Scott-Thoennes <stho...@efn.org> writes:
>On Thu, Apr 22, 2004 at 01:11:03PM -0500, Jay Hannah <jha...@omnihotels.com> wrote:
>> hubristically suggesting a change to an explicitly documented nonexistant feature in the bedrock of perl...
>
>Not so hubristic. One of the barriers had been that people have
>wanted void context sort(@a) to sort @a in place more efficiently than
>@a = sort @a would do -- but as of 5.8.4, @a = sort @a is optimized to
>be more efficient, so now is a good time to reopen the sort
>can-o-worms.
>
>Things to think about:
>
>scalar sort { mangle($a,$b) } LIST may have side effects; should they
>take place? (i.e. should sort do anything other than just return the
>number of items in LIST)?

The "obvious" (to me) thing for scalar(sort(...)) to return is the

1st element of the sorted list - but do it just be one pass to find
the value.


>

Nick Ing-Simmons

unread,
Apr 26, 2004, 10:31:39 AM4/26/04
to perl5-...@ton.iguana.be, perl5-...@perl.org

I can. Suppose you have a method like the original poster's which
returns a sorted list. I might want to call it in a void context
for its side effects and not care about return value.

Randal L. Schwartz

unread,
Apr 26, 2004, 12:12:48 PM4/26/04
to perl5-...@perl.org
>>>>> "Nick" == Nick Ing-Simmons <ni...@ing-simmons.net> writes:

Nick> The "obvious" (to me) thing for scalar(sort(...)) to return is the
Nick> 1st element of the sorted list - but do it just be one pass to find
Nick> the value.

The "obvious" thing for scalar sort to return for me is the *last*
element of the sorted list... the one that is the "most" of whatever
the sort comparison function is asking for.

What we need is for Larry to say what the "obvious" thing for him is.
After all, it's his language. :)

Rafael Garcia-Suarez

unread,
Apr 26, 2004, 12:20:20 PM4/26/04
to perl5-...@perl.org
Horsley Tom wrote:
> > Nick> The "obvious" (to me) thing for scalar(sort(...)) to return is the
> > Nick> 1st element of the sorted list - but do it just be one pass to find
> > Nick> the value.
> >
> > The "obvious" thing for scalar sort to return for me is the *last*
> > element of the sorted list... the one that is the "most" of whatever
> > the sort comparison function is asking for.
>
> The "obvious" things for me is "min" and "max" functions that are
> called with comparison functions just like "sort" but merely
> return the obvious result rather than being hidden in some
> non-obvious weird scalar context side-effect that modifies
> the meaning of "sort". (Actually, they would even make sense
> in array context if there were duplicates, they could return
> all of 'em).

As far as I'm concerned, I'm quite happy with sort being a noop in
scalar context, as a quite rude but documented (and warned about)
optimization.

Horsley Tom

unread,
Apr 26, 2004, 12:17:26 PM4/26/04
to perl5-...@perl.org

David Nicol

unread,
Apr 26, 2004, 1:01:19 PM4/26/04
to perl5-...@perl.org

speaking of sorting optimizations and min/max functions when
that is all you want, in my opinion a way to do that would
be with a TIEARRAY interface.

tie my @Sorted, Tie::Array::LazySorter => @ary,
sub {$_[0]->hairlength <=> $_[1]->hairlength};
print "",(shift @Sorted)->name, " has the shortest hair ";
print "while ",(pop @Sorted)->name, " has the longest.";

Tie::Array::Lazysorter would do only enough comparisons to
find the required information, while caching intermediate
results it "gets for free." I know that several sorts can
be efficiently interrupted after finding minima and maxima,
for instance heap sort can do this.

Has anyone got such a toy built yet?

Is the interface to the magic sort variables $a and $b available
so that a pragma might be put in place to make the syntax prettier?

use lazysort;
@Sorted = lazysort { $b <=> $a } (@ary);

sure beats the tie syntax.


--
david...@pay2send.com.
I know you, junk mail. Gonna miss you when you're gone

Robert Spier

unread,
Apr 26, 2004, 8:27:03 PM4/26/04
to perl5-...@perl.org
> Is the interface to the magic sort variables $a and $b available
> so that a pragma might be put in place to make the syntax prettier?
> use lazysort;
> @Sorted = lazysort { $b <=> $a } (@ary);
> sure beats the tie syntax.

No interface or anything needed. $a and $b are ignored by strict
'vars', and are passed in via scope.

#!perl -l
use strict;
use warnings;

sub lazysort (&@) {
my $sub = shift;
sort $sub @_;
}

print lazysort { $a <=> $b } (qw[3 2 1]);
print lazysort { $b <=> $a } (qw[1 2 3]);

Ok.. ok.. that was too lazy.

sub bubblesort (&@) {
my $cmp = shift;
local(@_) = @_;
my $alt=1;
while($alt) {
$alt=0;
for (my $i=0, my $j=1; $j < @_ ; $i++, $j++) {
local ($a,$b) = ($_[$i], $_[$j]);
if ( $cmp->() == 1 ) {
($_[$i],$_[$j]) = ($_[$j],$_[$i]);
$alt = 1;
}
}
}
@_;
}

print bubblesort { $a <=> $b } (qw[3 2 1]);
print bubblesort { $b <=> $a } (qw[1 2 3]);

Ton Hospel

unread,
Apr 27, 2004, 5:33:19 AM4/27/04
to perl5-...@perl.org
In article <20040426143...@llama.elixent.com>,

Nick Ing-Simmons <ni...@ing-simmons.net> writes:
> Ton Hospel <perl5-...@ton.iguana.be> writes:
>>In article <2004042612...@llama.elixent.com>,
>> Nick Ing-Simmons <ni...@ing-simmons.net> writes:
>>> The "obvious" (to me) thing for scalar(sort(...)) to return is the
>>> 1st element of the sorted list - but do it just be one pass to find
>>> the value.
>>>
>>But until it does something like that, make it an error instead of a
>>warning. I cannot imagine any current use that isn't an error.
>
> I can. Suppose you have a method like the original poster's which
> returns a sorted list. I might want to call it in a void context
> for its side effects and not care about return value.
Well, I was thinking about a compile time error, which wouldn't
be applicable to something that's potentially the last line in a
sub anyways (you don't know the context until runtime), so that case
doesn't apply. It's only for lines "in the middle" that I think it should
be an error.
0 new messages