Change 17685 by [EMAIL PROTECTED] on 2002/08/05 22:42:09
Subject: Re: mention of "use sort" botched in perlfunc? + PATCH
From: "John P. Linderman" <[EMAIL PROTECTED]>
Date: Sun, 21 Jul 2002 12:13:32 -0400 (17:13 BST)
Message-id: <[EMAIL PROTECTED]>
Affected files ...
.... //depot/perl/lib/sort.pm#9 edit
.... //depot/perl/lib/sort.t#8 edit
Differences ...
==== //depot/perl/lib/sort.pm#9 (text) ====
Index: perl/lib/sort.pm
--- perl/lib/sort.pm#8~16286~ Tue Apr 30 12:03:34 2002
+++ perl/lib/sort.pm Mon Aug 5 15:42:09 2002
@@ -1,6 +1,6 @@
package sort;
-our $VERSION = '1.01';
+our $VERSION = '1.02';
# Currently the hints for pp_sort are stored in the global variable
# $sort::hints. An improvement would be to store them in $^H{SORT} and have
@@ -33,6 +33,30 @@
$hints |= $sort::mergesort_bit;
} elsif ($_ eq 'stable') {
$hints |= $sort::stable_bit;
+ } elsif ($_ eq 'defaults') {
+ $hints = 0;
+ } else {
+ require Carp;
+ Carp::croak("sort: unknown subpragma '$_'");
+ }
+ }
+}
+
+sub unimport {
+ shift;
+ if (@_ == 0) {
+ require Carp;
+ Carp::croak("sort pragma requires arguments");
+ }
+ local $_;
+ no warnings 'uninitialized'; # bitops would warn
+ while ($_ = shift(@_)) {
+ if (/^_q(?:uick)?sort$/) {
+ $hints &= ~$sort::sort_bits;
+ } elsif ($_ eq '_mergesort') {
+ $hints &= ~$sort::sort_bits;
+ } elsif ($_ eq 'stable') {
+ $hints &= ~$sort::stable_bit;
} else {
require Carp;
Carp::croak("sort: unknown subpragma '$_'");
@@ -63,6 +87,8 @@
use sort 'stable'; # guarantee stability
use sort '_quicksort'; # use a quicksort algorithm
use sort '_mergesort'; # use a mergesort algorithm
+ use sort 'defaults'; # revert to default behavior
+ no sort 'stable'; # stability not important
use sort '_qsort'; # alias for quicksort
@@ -70,11 +96,11 @@
=head1 DESCRIPTION
-With the sort pragma you can control the behaviour of the builtin
-sort() function.
+With the C<sort> pragma you can control the behaviour of the builtin
+C<sort()> function.
In Perl versions 5.6 and earlier the quicksort algorithm was used to
-implement sort(), but in Perl 5.8 a mergesort algorithm was also made
+implement C<sort()>, but in Perl 5.8 a mergesort algorithm was also made
available, mainly to guarantee worst case O(N log N) behaviour:
the worst case of quicksort is O(N**2). In Perl 5.8 and later,
quicksort defends against quadratic behaviour by shuffling large
@@ -98,16 +124,78 @@
does fewer comparisons than quicksort, so it may be better when
complicated comparison routines are used. Mergesort also takes
advantage of pre-existing order, so it would be favored for using
-sort to merge several sorted arrays. On the other hand, quicksort
-is often faster for small arrays, and on platforms with small memory
-caches that are much faster than main memory. You can force the
+C<sort()> to merge several sorted arrays. On the other hand, quicksort
+is often faster for small arrays, and on arrays of a few distinct
+values, repeated many times. You can force the
choice of algorithm with this pragma, but this feels heavy-handed,
so the subpragmas beginning with a C<_> may not persist beyond Perl 5.8.
+The default algorithm is mergesort, which will be stable even if
+you do not explicitly demand it.
+But the stability of the default sort is a side-effect that could
+change in later versions. If stability is important, be sure to
+say so with a
+
+ use sort 'stable';
+
+The C<no sort> pragma doesn't
+I<forbid> what follows, it just leaves the choice open. Thus, after
+
+ no sort qw(_mergesort stable);
+
+a mergesort, which happens to be stable, will be employed anyway.
+Note that
+
+ no sort "_quicksort";
+ no sort "_mergesort";
+
+have exactly the same effect, leaving the choice of sort algorithm open.
=head1 CAVEATS
-This pragma is not lexically scoped : its effect is global to the program
-it appears in. This may change in future versions.
+This pragma is not lexically scoped: its effect is global to the program
+it appears in. That means the following will probably not do what you
+expect, because I<both> pragmas take effect at compile time, before
+I<either> C<sort()> happens.
+
+ { use sort "_quicksort";
+ print sort::current . "\n";
+ @a = sort @b;
+ }
+ { use sort "stable";
+ print sort::current . "\n";
+ @c = sort @d;
+ }
+ # prints:
+ # quicksort stable
+ # quicksort stable
+
+You can achieve the effect you probably wanted by using C<eval()>
+to defer the pragmas until run time. Use the quoted argument
+form of C<eval()>, I<not> the BLOCK form, as in
+
+ eval { use sort "_quicksort" }; # WRONG
+
+or the effect will still be at compile time.
+Reset to default options before selecting other subpragmas
+(in case somebody carelessly left them on) and after sorting,
+as a courtesy to others.
+
+ { eval 'use sort qw(defaults _quicksort)'; # force quicksort
+ eval 'no sort "stable"'; # stability not wanted
+ print sort::current . "\n";
+ @a = sort @b;
+ eval 'use sort "defaults"'; # clean up, for others
+ }
+ { eval 'use sort qw(defaults stable)'; # force stability
+ print sort::current . "\n";
+ @c = sort @d;
+ eval 'use sort "defaults"'; # clean up, for others
+ }
+ # prints:
+ # quicksort
+ # stable
+
+Scoping for this pragma may change in future versions.
=cut
==== //depot/perl/lib/sort.t#8 (text) ====
Index: perl/lib/sort.t
--- perl/lib/sort.t#7~16286~ Tue Apr 30 12:03:34 2002
+++ perl/lib/sort.t Mon Aug 5 15:42:09 2002
@@ -28,7 +28,8 @@
use Test::More tests => @TestSizes * 2 # sort() tests
* 4 # number of pragmas to test
+ 1 # extra test for qsort instability
- + 3; # tests for sort::current
+ + 3 # tests for sort::current
+ + 3; # tests for "defaults" and "no sort"
# Generate array of specified size for testing sort.
#
@@ -158,5 +159,25 @@
use sort qw(_qsort stable);
is(sort::current(), 'quicksort stable', 'sort::current for _qsort stable');
main(0);
+};
+die $@ if $@;
+
+# Tests added to check "defaults" subpragma, and "no sort"
+
+eval q{
+ no sort qw(_qsort);
+ is(sort::current(), 'stable', 'sort::current after no _qsort');
+};
+die $@ if $@;
+
+eval q{
+ use sort qw(defaults _qsort);
+ is(sort::current(), 'quicksort', 'sort::current after defaults _qsort');
+};
+die $@ if $@;
+
+eval q{
+ use sort qw(defaults stable);
+ is(sort::current(), 'stable', 'sort::current after defaults stable');
};
die $@ if $@;
End of Patch.