in reply to Re^2: best practice when using XML::Parser and strict.
in thread best practice when using XML::Parser and strict.
If you declare named subroutines within other subroutines, the value of lexical variables declared in the outter subroutine will not necessarily stay in sync with the value of that variable in the inner subroutine (if you ran this code with warnings, you would get a message saying "Variable $indent will not stay shared"). From perldoc perldiag:
When the inner subroutine is called, it will probably see the value of the outer subroutine's variable as it was before and during the *first* call to the outer subroutine; in this case, after the first call to the outer subroutine is complete, the inner and outer subroutines will no longer share a common value for the variable. In other words, the variable will no longer be shared.
Furthermore, if the outer subroutine is anonymous and references a lexical variable outside itself, then the outer and inner subroutines will never share the given variable.
This problem can usually be solved by making the inner subroutine anonymous, using the sub {} syntax. When inner anonymous subs that reference variables in outer subroutines are called or referenced, they are automatically rebound to the current values of such variables.
This may not be a problem with the code you posted, since handle_start and handle_end will (in theory) always be called in pairs and never be called except by XML::Parser. However, doing this in other parts of your code could result in unexpected results. For example this code:
produces the following output:use strict; use warnings; print "calling outter from main:\n"; outter(); print "calling inner from main:\n"; inner(); print "calling outter from main:\n"; outter(); sub outter { my $var = 0; print " outter: $var\n"; print " calling inner, should increment 0 -> 1\n"; inner(); sub inner { print " inner: $var -> "; $var++; print "$var\n"; } }
Variable "$var" will not stay shared at sub_in_sub.pl line 23. calling outter from main: outter: 0 calling inner, should increment 0 -> 1 inner: 0 -> 1 calling inner from main: inner: 1 -> 2 calling outter from main: outter: 0 calling inner, should increment 0 -> 1 inner: 2 -> 3
Notice that when inner() is called from main, the value of $var is still 1, and the second time outter() is called the inner() sub starts with a value of 2 for $var instead of 0, as you might expect.
Arunbear's suggestion declared the $indent variable and both handler subs inside a bare block. This limited the scope of $indent to just those two subs, but it doesn't suffer from the sharing problem described above. If you really want to declare subs within subs, look into closures.
Thanks to tye for helping me find the reference to this in the docs.
HTH
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re^4: best practice when using XML::Parser and strict.
by reasonablekeith (Deacon) on Mar 01, 2005 at 09:38 UTC |