Rainer Weikusat said:
Dave Saville said:
Please why does this throw an error?
[T:\tmp]cat try.pl
use strict;
use warnings;
foo("Hello World");
exit;
{
my $bar = 1;
sub foo
{
my $a = shift;
print "$bar $a\n"; # <== line 12
return;
}
}
[T:\tmp]try.pl
Use of uninitialized value in concatenation (.) or string at try.pl
line 12.
Hello World
Because $bar = 1 is never executed: The compiler compiles this, then
the program invokes the foo subroutine and exits before the $bar =
1.
Additional explanation: Generally, running a Perl program is comprised
of two phases: A compilation step where the Perl compiler reads all
the source code files and transforms the code into some internal
representation (AFAIK called 'an optree') and an execution phase where
the Perl interpreter evaluates/ executes this 'optree'. This means any
statement in a Perl program may have run time or compile time effects
or both and the run time effects aren't visible during compile
time. For this example, this means the compiler creates a compiled
subroutine 'foo' which refers to the $bar defined in the outer block
because 'creating my variables' has the compile-time effect of making
the corresponding names visible to the compiler (so that it can
generated code accessing the proper objects). But the assignment to
$bar does not happen at compile-time, it happens at run-time when the
corresponding statement is executed. An execution of the 'content' of
a file is top-to-bottom: By the time the foo("...:") is executed, a
subroutine referencing the proper $bar has been created but the value
of $bar hasn't yet been set.
So-called 'BEGIN block' can be used to execute Perl code at
compile-time and alternatively, so-called 'INIT blocks' can be used to
run Perl code after the compilation phase has finished and before any
of the 'general' code ran (details are in the perlmod manpage).