Reputation: 25217
For example I have code:
my $x = 77;
sub test {
$DB::single = 1;
1;
}
test();
If I run this script with -d flag: perl -d test.pl
, this script execution will be stopped at breakpoint (line 5). From the breakpoint $x
variable is visible. If I try to view via debugger its value it will be undefined. If I change my program like next:
sub test {
print $x;
$DB::single = 1;
1;
}
test();
Then $x
is visible.
Is there any perl debugger option which will allow to disable optimization for non used variables in current scope?
Upvotes: 2
Views: 121
Reputation: 386396
No.
This isn't an optimization; the variable was created, but it simply ceased to exist by the time you decided to inspect it because execution reached the of its scope.
In the case where the sub sees $x
because it uses $x
, it's because the sub captured $x
. Subs only capture the variables they need to capture. Capturing unnecessarily could have very detrimental effects (because destructors wouldn't be called when expected).
There's no way to tell Perl to do otherwise except on a variable-by-variable basis.
First of all, the code you posted doesn't exhibit the problem you describe.
$ perl -d a.pl
Loading DB routines from perl5db.pl version 1.55
Editor support available.
Enter h or 'h h' for help, or 'man perldebug' for more help.
main::(a.pl:1): my $x = 77;
DB<1> r
main::test(a.pl:5): 1;
DB<1> x $x
0 77
DB<2> q
But you would have that problem if the code was part of a module.
Foo.pm
:
package Foo;
my $x = 77;
sub test {
$DB::single = 1;
1;
}
1;
$ perl -d -I. -e'use Foo; Foo::test()'
Loading DB routines from perl5db.pl version 1.55
Editor support available.
Enter h or 'h h' for help, or 'man perldebug' for more help.
main::(-e:1): use Foo; Foo::test()
DB<1> r
Foo::test(Foo.pm:7): 1;
DB<1> x $x
0 undef
DB<2> q
In the future, please ensure that the code you posted actually demonstrates the problem you claim it does.
Say you had
{
my $x = 77;
}
CORE::say $x;
That doesn't work, right? It's not because of an optimization —$x
was created, and 77
was assigned to it— it's because $x
ceased to exist when the lexical scope that enclosed it was exited.
Now let's consider the following:
{
my $x = 77;
sub get_x { $x }
}
CORE::say get_x();
This somehow prints 77
. How is that possible? I just explained that $x
ceased to exist before reaching the last line. Well, it would have ceased to exist except that get_x
captured it. We say that get_x
is a closure. $x
keeps on existing, but only in the closure.
Needless to say, it's takes effort (CPU and memory) to capture a variable, so only variables that need to be captured are captured. Not capturing variables that don't need to be captured is not an optimization; it's simply not doing work that wasn't requested.
What does this have to do with your question? Well, blocks (curlies) aren't the only things that create lexical scopes. File loaded by Perl are executed in a fresh lexical scope.
In other words, the failing test above is roughly equivalent to
BEGIN {
package Foo;
my $x = 77;
sub test {
$DB::single = 1;
1;
}
$INC{"Foo.pm"} = 1;
}
use Foo;
Foo::test();
And that boils down to
{
my $x = 77;
sub test {
$DB::single = 1;
1;
}
}
test();
Given the above, the following question is the one effectively being asked:
Is there a way to tell Perl to have subs capture variables it doesn't use?
The answer is no.
Only captured variable and still-existing variables are available to the sub when it's called. Capturing unnecessary variables would cause variables to continue to exist longer than expected, which means destructors wouldn't be called when expected.
There's no way to tell Perl to do otherwise except on a variable-by-variable basis (e.g. by adding $x if 0;
to the sub).
Addendum: You can experience similar problems with eval EXPR
.
$ perl -e'
my $x = 77;
sub test {
return eval($_[0]);
}
printf "[%s]\n", test(q{$x});
'
[77]
$ perl -e'
{
my $x = 77;
sub test {
return eval($_[0]);
}
}
printf "[%s]\n", test(q{$x});
'
[]
$ perl -e'
{
my $x = 77;
sub test {
$x if 0;
return eval($_[0]);
}
}
printf "[%s]\n", test(q{$x});
'
[77]
Addendum: Captures are very useful! They make callbacks a breeze.
sub any {
my $callback = shift;
for (@_) {
return 0 if $callback->();
}
return 1;
}
my %bad = map { $_ => 1 } qw( foo bar );
die if any(sub { $bad{$_} }, @args); # Captures %bad
Upvotes: 5
Reputation: 25217
thx to @ikegami
Here I rephrase his answer in short:
{ # 1. start scope
my $x = 77; # 2. assign $x value
sub test {
$DB::single = 1;
1; # 5. execution stopped when $x does not exists anymore
}
} # 3. scope is finished, $x is destroyed
test(); # 4. call test sub
Here $x is in its scope.
When I stopped at test
the $x
does not exists anymore.
So this is not optimization, this is circle of life which can not be turned off =)
Upvotes: 0