Beefy Boxes and Bandwidth Generously Provided by pair Networks
Pathologically Eclectic Rubbish Lister
 
PerlMonks  

(??{ lexical variable })

by Juerd (Abbot)
on Dec 03, 2002 at 08:39 UTC ( #217158=perlquestion: print w/ replies, xml ) Need Help??
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.

Comment on (??{ lexical variable })
Select or Download Code
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.
      

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://217158]
Approved by robartes
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others chilling in the Monastery: (7)
As of 2015-08-01 02:49 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    The top three priorities of my open tasks are (in descending order of likelihood to be worked on) ...









    Results (285 votes), past polls