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

Re: [PATCH] [ID 20010813.010] List::Util::first fails on Array of Arr ayrefs

Thread Previous
From:
Graham Barr
Date:
August 17, 2001 09:49
Subject:
Re: [PATCH] [ID 20010813.010] List::Util::first fails on Array of Arr ayrefs
Message ID:
20010817174757.U7667@pobox.com
I think this patch is just hiding the problem in this particular
case. I think there is a problem with how the stack is being
handled. Try this, it fails both before and after the patch

sub add {
  my($aa, $bb) = @_;
#warn join(",",@_);
  return $aa + $bb;
}

my $sum = reduce { print "$a $b\n"; 0+add($a, $b) } 3, 2, 1;

print "Sum is '$sum'\n";


For me it gives '10', but if you uncommant the warn statement
it gives '7'

Graham.

On Fri, Aug 17, 2001 at 09:33:02AM -0700, Wilson, Doug wrote:
> 
> > 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 Previous


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About