in reply to Re^3: Designing a DWIMish interface for generator function
in thread Designing a DWIMish interface for generator function

Did you have a look at the code I linked to? It keeps the state, by using the ref of the iterator-variable as key:

use strict; use warnings; { my %lists; sub deal { my $aref=shift; my $id= \$_[0]; #print $aref,$id; $lists{$id}=$aref if (! exists $lists{$id} ); if (@{$lists{$id}}){ for(@_) { $_=shift @{$lists{$id}}; } return 1; } else { delete $lists{$id}; return 0; } } } $\="\n"; #--------- here we go while (deal [1..9] => my ($a,$b,$c) ){ print $a,$b,$c; while (deal [a=>1,b=>2] => my ($a,$b) ){ print $a,$b; } } #--------- print "EXIT"; __DATA__ 123 a1 b2 456 a1 b2 789 a1 b2

But I have to admit that till now I haven't thought about last, that's indeed a problem...

Cheers Rolf

Replies are listed 'Best First'.
Re^5: Designing a DWIMish interface for generator function
by ikegami (Patriarch) on Feb 01, 2010 at 05:53 UTC
    • You assumed that the iterator variable will be created at the same memory address every pass of the loop. It's a bad assumption. For example, the following code is an infinite loop:

      my @x; while (deal [1..9] => my ($a,$b,$c) ){ print $a,$b,$c; push @x, \$a; }

      Well, maybe not infinite, since deal is leaking memory every pass of the loop...

    • You assumed that the loop will receive a new iterator each time. It's a bad assumption. For example, deal starts at the wrong number the second and third pass of the outer loop in the following code:

      for (1..3) { while (deal [1..9] => my ($a,$b,$c) ){ print $a,$b,$c; last; } }

    Just like you need to call keys before each, you'd need to reset the iterator before entering the loop. You'd need

    init_deal my ($a,$b,$c) while (deal [1..9] => ($a,$b,$c) ){ ... }
      Hi

      As I already admitted last is really an unexpected problem... 8(

      (Hmm ... maybe there's a way by trying to catch the destruction of the iterator variable... )

      Talking about positional subs and leaking I already found a nice workaround by using code-blocks!¹ 8)

      sub noleak (&$) { my $cr=shift; $_[0]=$cr } my @a; for (0..9) { noleak {0,5} my $a; push @a,$a; print $a }

      The code-reference seems - as expected - to be precalculated at compile time and is fix!

      /usr/bin/perl -w /home/lanx/B/PL/PM/iter_leak.pl CODE(0xa099b48)CODE(0xa099b48)CODE(0xa099b48)CODE(0xa099b48)CODE(0xa09 +9b48)CODE(0xa099b48)CODE(0xa099b48)CODE(0xa099b48)CODE(0xa099b48)CODE +(0xa099b48)

      Or do you have an idea to break this approach?

      Cheers Rolf

      UPDATE:

      ARGHH it only works when using fixed values...

      sub noleak (&$) { my $cr=shift; $_[0]=$cr } my ($start,$end)=(1,20); my @a; for (0..9) { $start++; noleak {$start,$end} my $a; push @a,$a; print $a }

      output

      CODE(0x8e29760)CODE(0x8e47ca8)CODE(0x8e47d08)CODE(0x8e47d68)CODE(0x8e4 +7dc8)CODE(0x8e47e28)CODE(0x8e47e88)CODE(0x8e47ee8)CODE(0x8e47f48)CODE +(0x8e47fa8)

      ... but commenting out the push produces:

      CODE(0x81f7760)CODE(0x81f7760)CODE(0x81f7760)CODE(0x81f7760)CODE(0x81f +7760)CODE(0x81f7760)CODE(0x81f7760)CODE(0x81f7760)CODE(0x81f7760)CODE +(0x81f7760)

      and there is no need to propagate the coderef outside the sub...

      UPDATE

      ¹) I ran some tests, better forget it...it really only seems to work reliably with constant values in the code-block ...seems to be an optimization issue.

      UPDATE I'm going to run some tests with state.