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.
> "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.
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!
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
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
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 @_ } >).
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.
:-)
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.
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...
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
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!
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.
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).
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;
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/
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.
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.
>
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.
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. :)
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.
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
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]);