develooper Front page | perl.perl5.porters | Postings from August 2001

[PATCH] [ID 20010813.010] List::Util::first fails on Array of Arrayrefs

Thread Next
From:
Wilson, Doug
Date:
August 17, 2001 09:33
Subject:
[PATCH] [ID 20010813.010] List::Util::first fails on Array of Arrayrefs
Message ID:
35A280DF784CD411A06B0008C7B130ADB55102@sdex04.sd.intuit.com

> use strict;
> use List::Util qw(first);
> 
> my @ary = ([qw(a b c)], [qw(d e f)], [qw(g h i)]);
> my $foo = first { $_->[1] le "e" and "e" le $_->[2] } @ary;
> print $foo->[0],"\n";
> 
> After the first call to CALLRUNOPS, the second argument on
> the arg stack is clobbered, and so you get this error on the 
> second call:
> Can't use string ("2") as an ARRAY ref while "strict refs" in 
> use at first.t
> lin
> e 8.

The first op being called in runops was pp_nextstate, which was
setting the top of the stack to the bottom of the stack, thereby
clobbering the arguments to first() if too many things got pushed
on the stack while processing the first argument.

So my guess (after much trial and error) was to just skip the first
op and go to the next op, which seems to work. Someone please check
this and tell me if I'm overlooking something. I've assumed the same
thing could happen with reduce() also, so I'm also patching that.

This should also serve as a warning/lesson to anyone writing a map/grep like
function in XS (which will all become moot in Perl 6 :)

Patch to the Util XS code and the first.t test (should
probably add tests to reduce.t also, but I haven't yet tried to make
that fail under the old code...):
###############################################
--- Util.orig   Fri Aug 17 08:48:22 2001
+++ Util.xs Fri Aug 17 08:49:13 2001
@@ -171,7 +171,7 @@
     SAVESPTR(GvSV(agv));
     SAVESPTR(GvSV(bgv));
     cv = sv_2cv(block, &stash, &gv, 0);
-    reducecop = CvSTART(cv);
+    reducecop = CvSTART(cv)->op_next;
     SAVESPTR(CvROOT(cv)->op_ppaddr);
     CvROOT(cv)->op_ppaddr = PL_ppaddr[OP_NULL];
     SAVESPTR(PL_curpad);
@@ -206,7 +206,7 @@
     }
     SAVESPTR(GvSV(PL_defgv));
     cv = sv_2cv(block, &stash, &gv, 0);
-    reducecop = CvSTART(cv);
+    reducecop = CvSTART(cv)->op_next;
     SAVESPTR(CvROOT(cv)->op_ppaddr);
     CvROOT(cv)->op_ppaddr = PL_ppaddr[OP_NULL];
     SAVESPTR(PL_curpad);

##############################################################
--- first.orig  Fri Aug 17 09:24:27 2001
+++ first.t Fri Aug 17 09:26:49 2001
@@ -10,7 +10,7 @@

 use List::Util qw(first);

-print "1..4\n";
+print "1..6\n";

 print "not " unless defined &first;
 print "ok 1\n";
@@ -23,3 +23,16 @@

 print "not " if defined(first { 0 });
 print "ok 4\n";
+
+my @ary = ([qw(a b c)], [qw(d e f)], [qw(g h i)]);
+
+print "not " unless "d" eq (first {
+    $_->[1] le "e" and "e" le $_->[2]
+} @ary)->[0];
+print "ok 5\n";
+
+print "not " unless "h" eq
+(first {
+    first { $_ eq "h" } @$_;
+} @ary)->[1];
+print "ok 6\n";
########################################################

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