in reply to Re: Multiple uses of (?{ code }) do not appear to be called
in thread Multiple uses of (?{ code }) do not appear to be called

Yep. Adding a print pos() inside the (?{code}) block shows that it does give the right pos values:
sub foo { my $window = "a b X20 c X5 d e X17 X12"; my @o = (); my @m = ($window =~ m/(X\d+(?{print ">pos:",pos();push @o, pos()}) +)/g); print "Matches: @m"; print "Offsets: @o"; print " "; } __END__ >pos:7 >pos:12 >pos:20 >pos:24 Matches: X20 X5 X17 X12 Offsets: 7 12 20 24 >pos:7 >pos:12 >pos:20 >pos:24 Matches: X20 X5 X17 X12 Offsets: >pos:7 >pos:12 >pos:20 >pos:24 Matches: X20 X5 X17 X12 Offsets:

Moving the declaration of @o outside of sub foo makes it clear:

my @o = (); sub foo { my $window = "a b X20 c X5 d e X17 X12"; my @m = ($window =~ m/(X\d+(?{print ">pos:",pos();push @o, pos()}) +)/g); print "Matches: @m"; print "Offsets: @o"; print " "; } __END__ >pos:7 >pos:12 >pos:20 >pos:24 Matches: X20 X5 X17 X12 Offsets: 7 12 20 24 >pos:7 >pos:12 >pos:20 >pos:24 Matches: X20 X5 X17 X12 Offsets: 7 12 20 24 7 12 20 24 >pos:7 >pos:12 >pos:20 >pos:24 Matches: X20 X5 X17 X12 Offsets: 7 12 20 24 7 12 20 24 7 12 20 24

In other words, the @o in the (?{code}) block has been closed over, while the one in the print statement is a fresh array. The closed array is no longer accessible outside the regexp.

A naughty solution might be the following (abusing something of a bug in perl; this may break in future versions):

sub foo { my $window = "a b X20 c X5 d e X17 X12"; my @o = () if pos; # conditional declaration makes @o "static" @o = (); # reset it always my @m = ($window =~ m/(X\d+(?{push @o, pos()}))/g); print "Matches: @m"; print "Offsets: @o"; print " "; } __END__ Matches: X20 X5 X17 X12 Offsets: 7 12 20 24 Matches: X20 X5 X17 X12 Offsets: 7 12 20 24 Matches: X20 X5 X17 X12 Offsets: 7 12 20 24

Replies are listed 'Best First'.
Re^3: Multiple uses of (?{ code }) do not appear to be called
by bsdz (Friar) on Dec 29, 2006 at 13:01 UTC
    Ha ha, looks like you and I were on the same path. I think I'll avoid using the bug though it is useful to know.
      Glad you're going to avoid that "feature" :-) (see e.g. Re: static-like persistence of my variable due to trailing conditional and How does my work with a trailing conditional for previous discussions)

      I'd like to give you two reasonable workarounds. The first is simply using the global variable, with my added suggestion to enclose it in an anonymous block:

      { # limit scope my @o; sub foo { my $window = "a b X20 c X5 d e X17 X12"; @o = (); my @m = ( $window =~ m/(X\d+(?{push @o, pos()}))/g ); print "Matches: @m"; print "Offsets: @o"; print " "; } }
      This will make sure that only foo() can see @o.

      The second workaround is basically a rewrite of your code. It doesn't solve the general issue, but it avoids the use of the complicated (?{BLOCK}) feature for your particular case:

      sub foo { my $window = "a b X20 c X5 d e X17 X12"; my( @o, @m ); while( $window =~ m/(X\d+)/g ) { push @m, $1; push @o, $+[0]; } print "Matches: @m"; print "Offsets: @o"; print " "; }
        Thanks for the further suggestions. It seems blazar has given a better solution in using "local our" modifiers to avoid declaring a global variable.

        Your code will break if execution ever proceeds past the my(@o) line. That is, if you put a foo() call at the end of your script. It is always bad style to use my() variables with (?{...}) and (??{...}). Don't do it.

        ⠤⠤ ⠙⠊⠕⠞⠁⠇⠑⠧⠊