Beefy Boxes and Bandwidth Generously Provided by pair Networks
Problems? Is your data what you think it is?
 
PerlMonks  

What is an ordinary statement?

by ntj (Novice)
on Jun 04, 2019 at 17:26 UTC ( [id://11100959]=perlquestion: print w/replies, xml ) Need Help??

ntj has asked for the wisdom of the Perl Monks concerning the following question:

As delving into the documentation of Perl regarding syntax, I've found a paragraph that I'm unable to understand. I've got several question with the hope to understand these holy writings.

https://perldoc.perl.org/perlsyn.html last paragraph of Declarations
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.

Questions

  1. What is an ordinary statement?
  2. What are the run- and compile-time effects of this statement?
  3. Are there more compile-time steps in perl than in C/C++ when defining a variable?

(Guess on (2) and (3))

  • Based on what some of the languages do, I would guess that when a variable is defined, it is inserted into the symbol table, which is used by the semantic parser. When the grammar is correct, the code containing the variable is inserted into the output.
  • There are N other passes that generate the binary.
  • Then, when the binary is executed, the variable is used so has run-time effects.

Is that correct?

Replies are listed 'Best First'.
Re: What is an ordinary statement?
by Fletch (Bishop) on Jun 04, 2019 at 17:57 UTC

    For item 1, I think what it's trying to convey is that a declaration statement is just like what it calls "Simple Statements" a couple lines on (e.g. my $foo; is of a kind with say "Fnord."). It may be setting that up to contrast with "Compound Statements" (those which create a new scope with a block), but I'm not sure.

    You're pretty much close on your guesses WRT item the second. A declaration has the compile time effect of adding to the symbol table (which affects the subsequent parsing with things like strict). The runtime effect depends on the declaration type (e.g. local $foo = q{bar} would generate opcodes which save off the existing value in the package variable $foo then initialize it to the new value). You can use something like B::Concise to peek under the hood at the generated opcodes.

    As for the last question my gut answer is "they're probably about the same, but it depends". A C++ compiler especially is going to be doing a bit more work for things like type checking, but with things like attributes perl could be doing "more" work.

    The cake is a lie.
    The cake is a lie.
    The cake is a lie.

      Thanks for the wisdom!

      It's great to know it's possible to analyze the opcodes of declarations.

Re: What is an ordinary statement?
by AnomalousMonk (Archbishop) on Jun 04, 2019 at 19:56 UTC
    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:  <%-{-{-{-<

      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?

      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.)

Re: What is an ordinary statement?
by Eily (Monsignor) on Jun 04, 2019 at 20:12 UTC

    From the context I'd say that ordinary statement means executable statement. Unlike #define or even just plain variable declaration in C, which define some new words for the compiler to understand later statements, but are not translated into instructions.

    Because variables in perl are quite more complicated than C variables (basically, there is some C structure that holds the variable information, that structure must be initialized), they act as ordinary statements by being translated into instruction that are executed at a given time (before some statements, and after others). As far as I can tell, the only place where this is relevant is in explaining why statements such as: my $variable = 'value' unless /condition/; lead to undefined behaviour, because the executable (run-time) part of the my statement could be understood as being skipped if /condition/ is met. The compile time effect of my $variable would be to declare (well...) the existence of $variable to the compiler.

    I would guess that when a variable is defined, it is inserted into the symbol table
    I'm a little less confident about what I'm about to say after seeing other replies, but here it is: That's almost never true(*). First, to be sure that we agree on the vocabulary, the thing that makes a variable start to exist is its declaration(*) (telling the compiler "I'm going to use that name at some point"). The definition is giving it a value. In perl, variable declaration can be explicit (eg: using my), or in some cases implicit (most of the time, when strict is not used), when something that looks like a variable is being used while never explicitly declared (eg you write $name = 'ntj' when there never was a my $name), in those cases, defining the variable will mean adding it to the symbols table. But the main reason why declaring a variable does not insert it in the symbols table, is that only package variables are in the symbols table. Perl accesses the package variables' values by looking for their name in the correct package's symbols table. If the variable has a full name (eg $My::Package::variable) the package is the one explicitly mentioned, otherwise if the variable as a simple name (eg $variable) and has not been declared with my, the correct package is the current one.

    On the other hand, you can consider that perl forgets the names of lexical (my) variables after compiling, and it basically uses placeholders instead of the name ("the tool in my left hand" rather than "Eily's screwdriver"). This is why symbolic references (using a string with the name of a variable to get its value) do not work on lexical variables. That's also why a package variable is the same for different functions (several people using Eily's screwdriver would be using the same tool), while lexical variables only have a specific meaning in the scope in which they are declared ("The tool in my left hand" is not the same tool for different people). And that's why local only works on non lexical variables, because it temporarily changes a variable at a specific name.

    (*)This depends on your exact interpretation of "declaration" is in perl. You might consider that all package variables are actually always declared, but are used or unused. In which case package Hello; our $world; does not declare the variable $Hello::world which always existed, but instead only declares $world, which is a lexical alias to $Hello::world;

Re: What is an ordinary statement?
by holli (Abbot) on Jun 04, 2019 at 20:23 UTC
    I would say it simply means that you can put a my pretty much wherever (wether it makes sense or not) you can put any other (ordinary) statement. For example you can write
    perl -e "use strict; print 1 if (my $x = 1) > (my $y = 0);"
    In contrast to other languages where a declaration must stand on its own, like in C or Visual Basic.


    holli

    You can lead your users to water, but alas, you cannot drown them.
Re: What is an ordinary statement?
by karlgoethebier (Abbot) on Jun 05, 2019 at 12:56 UTC
    "...an ordinary statement"

    Ordinary in the sense of simple - in contrast to compound statements. This is less ore more described in the Camel Book Chapter 4. Statements and Declarations.

    From 4.1 Simple Statements: A simple statement is an expression evaluated for its side effects. Every simple statement must end in a semicolon, unless it is the final statement in a block. In that case, the semicolon is optional--Perl knows that you must be done with the statement, since you've finished the block. But put the semicolon in anyway if it's at the end of a multiline block, because you might eventually add another line.

    From 4.2. Compound Statements: A sequence of statements within a scope is called a block...Compound statements are built out of expressions and BLOCKs. Expressions are built out of terms and operators. In our syntax descriptions, we'll use the word EXPR to indicate a place where you can use any scalar expression. To indicate an expression evaluated in list context, we'll say LIST....

    Please see ibidem for more details. Still a good read.

    Best regards, Karl

    «The Crux of the Biscuit is the Apostrophe»

    perl -MCrypt::CBC -E 'say Crypt::CBC->new(-key=>'kgb',-cipher=>"Blowfish")->decrypt_hex($ENV{KARL});'Help

Re: What is an ordinary statement?
by ikegami (Patriarch) on Jun 08, 2019 at 10:19 UTC

    What is an ordinary statement?

    "Like an ordinary statement" means "like any other statement". The documentation is signaling that variable declarations are not special like they are in some other languages. For example, C used to require them to precede any other statements.

    What are the run- and compile-time effects of this statement?

    The make-belief version: my declares the variable at compile-time, and allocates it at run-time.

    The true version: my declares and effectively allocates the variable at compile-time, and pushes a directive on the stack at run-time. When that directive is popped from the stack on scope exit, the variable is either cleared (if it doesn't contain an object and the sub owns the only reference to it), or it's abandoned[1] and re-allocated (otherwise).


    1. By this, I mean the reference count of the variable is decremented, possibly freeing it.

Re: What is an ordinary statement?
by shmem (Chancellor) on Jun 21, 2019 at 10:43 UTC
    Questions

    Answers:

    1. What is an ordinary statement?
      An ordinary statement is an expression calculated for the sake of its side effect. The result of the calculation is discarded.
    2. What are the run- and compile-time effects of this statement?
      At compile time, structures are allocated for the statement to be successful at runtime. At runtime, these structures come to life with content.
    3. Are there more compile-time steps in perl than in C/C++ when defining a variable?
      They are different. Perl is implemented in C, so all compile-time concepts of C apply for the perl binary. But perl has its own compile-time rules and optimizers. Linkage rules are different, and there is no compilation into assembly and machine language.

    The answers are a bit terse and might need further explanation.

    Ad 1, a perl expression (EXPR) may be a simple expression or a compound expression. The moment for an expression to be evaluated is marked with a semicolon (;) at the end of the expression, which makes it into a statement. Regarding side effect - take this simple statement:

    print "Hello, world!\n";

    The side effect of this statement is the appearance of the string Hello, world! on the terminal (or at whatever output channel STDOUT is, or whatever has been selected). The calculated value is either 1 or nothing, depending on whether the print succeeds or not. It is discarded. If you capture the result of print into a variable

    $success = print "Hello, world!\n";

    then the print "Hello, world!\n" part is a subexpression of the statement; the two side effects are: output of string, storage of the result from print in a variable; but the main effect is the result of the variable assignment operation, which happens to be the value of the variable $success. This final result is also discarded.

    Ad 2, rules for BEGIN blocks and use statements apply.

    use strict; use warnings; my $x; $x = 'bar'; BEGIN { print "\$x in first BEGIN block: '$x'\n" } print "runtime: \$x = '$x'\n"; BEGIN { $x = 'foo'; print "\$x in second BEGIN block: '$x'\n"; } print "done.\n"; __END__ Use of uninitialized value $x in concatenation (.) or string at foo.pl + line 4. $x in first BEGIN block: '' $x in second BEGIN block: 'foo' runtime: $x = 'bar' done.

    In the second line of the above snippet, $x is allocated - uninitialized - on the scope's PAD (not in the symbol table, since it is a my variable. Line 3: $x the assignment operation is compiled and stored in the execution path (the optree). After that, the BEGIN block is compiled and executed. The variable $x is still uninitailized, hence the warning. Compiling goes on, the print operation is compiled, but not executed. After that, the second BEGIN block is compiled and executed, so $x is assigned a value. But at runtime, line 3 is executed, (assignment), thus $x is 'bar' at line 5.

    (Guess on (2) and (3))
    • Based on what some of the languages do, I would guess that when a variable is defined, it is inserted into the symbol table, which is used by the semantic parser. When the grammar is correct, the code containing the variable is inserted into the output.
    • There are N other passes that generate the binary.
    • Then, when the binary is executed, the variable is used so has run-time effects.
    Is that correct?

    Not quite.

    • perl compiles the directives of a program into an internal representation, called the execution stack, consisting of stack frames. Only variables declared as such (package globals) are allocated in the symbol table, others pertain to its stack frame and are local to that frame. Only if the setup of this execution stack succeeds according to the perl grammar, perl switches to runtime. Structures of the variables contents are created at runtime.
    • there are some passes over the execution tree, optimisation and such, e.g. to weed out code which will never be executed. No binary is created except the internal binary representation of the program.
    • since there is no binary, there is no execution of a binary. Instead, at runtime, the internal execution stack is walked.
    perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'
Re: What is an ordinary statement?
by xiaoyafeng (Deacon) on Jun 06, 2019 at 01:06 UTC
    Just a reminder, Please use perldoc.pl or perldoc.perl.org. perldoc.perl.org is getting retired.




    I am trying to improve my English skills, if you see a mistake please feel free to reply or /msg me a correction

      Why is there a Beta release of https://perldoc2.perl.org/ then?

      map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
      perldoc.perl.org is getting retired

      You sound certain. Do you have a link to an announcement? TIA

      I reckon we are the only monastery ever to have a dungeon stuffed with 16,000 zombies.
      what?
Re: What is an ordinary statement?
by Anonymous Monk on Jun 04, 2019 at 22:42 UTC
    Perl is an interpreter, not a compiler. There is no "compile time" as you think of it – only the superficial translation of the source code into "perlguts." There is no "generate the binary." Once the source code is translated into a runtime data structure the runtime interpreter takes over.
      Perl is an interpreter, not a compiler. There is no "compile time"

      And yet the document the OP linked refers to "compiler" and "compile time" numerous times itself, including the bit that the OP quoted.

      Please stop trying to pretend like you're an expert. TIA.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://11100959]
Front-paged by haukex
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others having a coffee break in the Monastery: (3)
As of 2024-03-29 01:51 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found