in reply to What is an ordinary statement?

A statement sequence may contain declarations of lexically-scoped variables, but apart from declaring a variable name, the declaration acts like an ordinary statement, and is elaborated within the sequence of statements as if it were an ordinary statement. That means it actually has both compile-time and run-time effects. [emphases added]

I cannot disagree with Fletch's reply++, but would word my answer slightly differently.

I think the quoted paragraph refers specifically to the distinction between compile-time declaration and run-time assignment for lexical variables. Consider

c:\@Work\Perl\monks>perl -wMstrict -le "func(); ;; my $string = 'hiya'; ;; sub func { print $string; } " Use of uninitialized value in print at -e line 1.
and
c:\@Work\Perl\monks>perl -wMstrict -le "my $string = 'hiya'; ;; func(); ;; sub func { print $string; } " hiya

In the first statement sequence,  $string is declared (and default-initialized to undef) at compile time so  func() can compile correctly under strictures, but the run-time execution order is such that it has no correct assigned value when  func() is invoked at run time.

In the second statement sequence,  $string is both declared (at compile time) and assigned a "correct" value (at run time) before  func() is invoked (at run time), so everybody's happy.


Give a man a fish:  <%-{-{-{-<

Replies are listed 'Best First'.
Re^2: What is an ordinary statement?
by ntj (Novice) on Jun 05, 2019 at 06:44 UTC

    Interesting viewpoint. It was quite surprising that the first statement sequence did compile, however, this makes sense if the default value for a variable declared is undef.

    So this is done in compile-time, and definition at runtime.

    Does the compiler do inlining?

      Does the compiler do inlining?

      Very rarely, because Perl is such a dynamic language, variables and even things such as subroutine declarations can change at any time and at a distance (kind of like volatile variables in C). The only place I can think of inlining off the top of my head is Constant Functions, the rest is optimization that Perl may or may not do internally (such as constant folding), but that should not be visible to the user.

      But in general, it sounds to me like you might be drawing too many parallels between Perl and a truly compiled language such as C/C++, where there are things such as generating a binary and a very clear distinction between compile time and run time. In the Perl interpreter, the lines between the traditional "compile time" and "run time" can be blurred - you can run code at compile time with BEGIN and use, and compile and run code at runtime with eval, do, and require. "Compilation" is really just translating source code into the in-memory opcode tree, that the interpreter then executes (Update: remember that the perl binary is both the compiler and interpreter, which is why it can do the aforementioned flexible compile-/run-time things).

      For example, here's a common mistake:

      our $FOO = 1; use if $FOO, 'SomeModule'; print $FOO, "\n";

      This will compile fine and print 1, but SomeModule won't be loaded! What is going on here is that use is equivalent to a BEGIN block, which is code that will be executed during the compile time of the code. So our $FOO = 1; declares a variable $FOO, so that it can be used in the following use statement, but the assignment $FOO = 1 doesn't actually happen until runtime, at which time the use statement will have already finished executing. To fix this, one needs to write e.g. our $FOO; BEGIN { $FOO = 1 } to move the assignment into the compile time as well, before the use executes.

      May I ask what the background of these questions is - is it just curiosity, or are you trying to implement something specific, or are having problems with something?

        it sounds to me like you might be drawing too many parallels between Perl and a truly compiled language such as C/C++, where there are things such as generating a binary and a very clear distinction between compile time and run time.

        Perl is not as different as you suggest.

        perl compiles Perl code into Perl op codes and operands which are then executed by the Perl virtual machine (PVM).

        In theory, the PVM could be implemented in hardware. Many of the Perl op codes correspond to common CPU opcodes. However, the operands are structures. And many of the op codes are more like "system traps" that call a system API function. The PVM is high level machine.

        But, it is possible to generate a "binary" file. The Bytecode backend writes Perl bytecode to a file, which the ByteLoader can feed into the PVM.

        One of the major problems with this is that if code in BEGIN blocks or in use'd files has "run time side effects", those won't happen when you run the previously compile program.

        Bytecode isn't the only option for saving compiled Perl. The Simple C backend encodes Perl's op codes and operands into C source that, when compiled by a C compiler will produce an executable that feeds the compiled Perl code into the PVM. The optimized C backend attempts to de-compile the Perl ops and operands into C code.

        But, again, any code in BEGIN blocks or in use'd files won't be run.

        If a Perl program is written to have no "run time side effects" at compile time - and only uses modules that are similarly coded, then storing a compiled Perl program in a file for later execution is an option.

Re^2: What is an ordinary statement?
by ntj (Novice) on Jun 06, 2019 at 05:31 UTC
    Interesting viewpoint. It was quite surprising that the first statement sequence did compile, however, this makes sense if the default value for a declaration is undef.

      The first sequence compiles because $string has been declared before func is defined. The compiler doesn't care about the value a variable might contain, it only cares whether it knows about the variable by the time the variable is used. In this sequence, since the compiler already knows about the variable when it compiles the body of func, the compiler generates code to use that variable. If the variable wasn't already known, then it would either emit an error, if strict is in force, or it would auto-declare the variable as a package variable in the current package.

      Of course, when the sequence is run, $string will not have a value assigned. If warnings are in effect, then Perl might complain that $string's value is undefined. However, the value will be treated as "" in this sequence.

      Strictly speaking, Perl should complain the value is uninitialized, but Perl doesn't distinguish between uninitialized and the undefined value. But, at least Perl has the concept of the undefined value. Perl also has the concept of "not a number", or "NaN", which, mathematically, is defined as an "unrepresentable value".

      (The undefined value is useful as an "invalid data" marker in some contexts. Without undefined, you have to use some other value as "invalid data" and hope it doesn't occur in any data set your program processes. I have seen some (non-Perl) programmers use "not a number" as "invalid measurement". Unfortunately for one of those, a data source was using that to indicate calculation errors. In other words, values that are unrepresentable. More importantly, this meant that the field technicians wasted time looking for the wrong problem.)