http://www.perlmonks.org?node_id=217158

Juerd has asked for the wisdom of the Perl Monks concerning the following question:

my $inlinetag = do { our $acc = qr/(?> \{ (?: (?> \\. | [^\\{}]+ | (??{ $acc }) ) )* + \} )/x; qr/ \{ (\w+): ( (?: (?> \\. | [^\\{}]+ | (??{ $acc }) ) )* +) \} /x; };
If I make $acc lexical, which is what I want, the regex no longer matches the same string that does match when it is a global variable. Even if it's declared before any assignment (my $acc; $acc = qr/.../;).

Because of this, I suspect that (??{ $variable }) doesn't play the normal Perl scoping game. If it were evaluating the variable when used, it should die (because that scope has no $acc), right?

Is Perl passing by name here? Why does strict not help me out here? :)

- Yes, I reinvent wheels.
- Spam: Visit eurotraQ.

Replies are listed 'Best First'.
Re: (??{ lexical variable })
by jryan (Vicar) on Dec 03, 2002 at 09:43 UTC

    The solution becomes clear when one realizes that qr// regexes are nothing but strings (albiet special string), and that they are not interpolated until runtime. Consider:

    my $inlinetag = do { my $acc = qr/(?> \{ (?: (?> \\. | [^\\{}]+ | (??{ $acc }) ) )* + \} )/x; qr/ \{ (\w+): ( (?: (?> \\. | [^\\{}]+ | (??{ $acc }) ) )* +) \} /x; };

    In this modified snippet, the $acc regex is constructed, and scoped lexically to the do block. Next, the unnamed regex is constructed. Note that both of these pass strict checking since $acc was created in the same block, and thus exists. Since the second regex was the last statement in the do block, it is returned, and is assigned to $inlinetag. I believe this is the behavior you expected.

    So what is the problem? The problem is that when $inlinetag is expanded at runtime, $acc no longer exists since it went out of scope when the do block returned the unnamed regex and assigned it to $inlinetag. A potential solution is just to get rid of the do block:

    my $acc = qr/(?> \{ (?: (?> \\. | [^\\{}]+ | (??{ $acc }) ) )* + \} )/x; my $inlinetag = qr/ \{ (\w+): ( (?: (?> \\. | [^\\{}]+ | (??{ $acc }) ) )* +) \} /x;

    Or, if you're really worried about cluttering your namespace, you can do some closure magic:

    my $inlinetag = sub { my $acc = qr/(?> \{ (?: (?> \\. | [^\\{}]+ | (??{ $acc }) ) )* + \} )/x; qr/ \{ (\w+): ( (?: (?> \\. | [^\\{}]+ | (??{ $acc }) ) )* +) \} /x; };

    However, you must now use it like this: qr/(??{$inlinetag->()}/ rather than like qr/$inlinetag/ with the first method.

      Wonderful explanation. Thanks!

      - Yes, I reinvent wheels.
      - Spam: Visit eurotraQ.
      

Re: (??{ lexical variable })
by Zaxo (Archbishop) on Dec 03, 2002 at 09:01 UTC

    Would a closure be close to what you want?

    { my $acc = ''; sub inlinetag { # ... whatever this does } }
    I haven't figured out just what this is supposed to do, but it may help to note that (??{}) are done like quoted eval, compiled in an interlude during runtime.

    A lexical is not constructed until the my statement declaring it hits its semicolon.

    After Compline,
    Zaxo

      Would a closure be close to what you want?

      Not really, as the snippet I pasted is part of a larger whole:

      { my %exlinx; my $link = qr/ \[ (?: ([^|\]]*) \| )? ([^\]]*) \] /x; # 1: u +rl 2: text my $inlinetag = do { our $acc = qr/(?> \{ (?: (?> \\. | [^\\{}]+ | (??{ $acc }) ) )* + \} )/x; qr/ \{ (\w+): ( (?: (?> \\. | [^\\{}]+ | (??{ $acc }) ) )* +) \} /x; }; # 1: tag 2: text my $overig = qr/(?: (?> \\. | [^{\[\\]+ ) )*/sx; # -: text my $stuff = qr/(?> $overig ) | (?> $link ) | (?> $inlinetag ) +/x; my $paratag = qr/(\w+):\s*/; my $n = qr/\n\s*\n/; # These return html-ified versions of the input sub inlineparse { ... } sub paraparse { ... } sub colorize { ... } }

      it may help to note that (??{}) are done like quoted eval, compiled in an interlude during runtime.

      That does help a little, but why doesn't it give me the famous Global symbol "$acc" requires explicit package name, then? I have no $acc declared in the scope where $inlinetag is being used.

      - Yes, I reinvent wheels.
      - Spam: Visit eurotraQ.