Beefy Boxes and Bandwidth Generously Provided by pair Networks
Just another Perl shrine

Re^4: What is an ordinary statement?

by RonW (Parson)
on Jun 06, 2019 at 23:04 UTC ( #11101071=note: print w/replies, xml ) Need Help??

in reply to Re^3: What is an ordinary statement?
in thread What is an ordinary statement?

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.

Replies are listed 'Best First'.
Re^5: What is an ordinary statement?
by haukex (Bishop) on Jun 07, 2019 at 10:13 UTC
    Perl is not as different as you suggest.

    You are of course correct that Perl "bytecode" can be saved and restored (with some limitations), and taken individually, I agree with many of the statements you've made and they are useful additional information. However, in the context of this thread, and because it appears you're presenting them as a counterpoint to what I was saying, I have to strongly disagree.

    the Perl virtual machine (PVM)

    I've never heard the term PVM before and it is used nowhere in the Perl core or documentation. You'll find only a single reference in the Camel: "the Perl virtual machine (which we refuse to call a PVM)".

    In theory, the PVM could be implemented in hardware.

    In theory, any piece of software could be implemented in hardware.

    The optimized C backend attempts to de-compile the Perl ops and operands into C code.

    I think "attempts" is a key word here. Although I admit I haven't worked with this C backend, I am also not aware of any implementation of compiled Perl that is able to do everything that perl can.

    If a Perl program is written to have no "run time side effects" at compile time

    In other words, if I omit exactly those dynamic features that I was making a point of, then I no longer have a point :-P You also make no mention of eval, which is quite significant here as well.

    If I compile a C program, the binary it generates is entirely independent from the compiler, it can be copied onto a machine with no compiler at all, and it is executed directly by the hardware. Perl code is executed by its interpreter, which runs alongside the compiler, so the Perl compiler has the ability to reach directly into the interpreter, and the Perl interpreter has the ability to directly reach into the compiler, simply because it is always there. Of course, in theory it's possible to link a C compiler into a C program, and maybe it's possible to have dynamically compiled C interact seamlessly with previously compiled and currently running C code, and maybe it's possible to have C code affect the complication phase of the surrounding C code, but at some point, I could just as well link perl, lua, python, etc. into my C program.

    To bring this back into the context of the thread: how the compiler and interpreter interact in regards to declarations. Consider this example:

    package Foo; use warnings; use strict; use Exporter 'import'; our @EXPORT = qw/foo $FOO/; sub foo { print @_, "\n" } our $FOO = 'bar';

    use warnings; use strict; use Foo; foo $FOO;

    In, strict is enabled and I make no prior mention of the function foo or the variable $FOO, yet I am able to use them. This is because use Foo; is essentially equivalent to BEGIN { eval ... } - during the compilation phase of, perl loaded another file, compiled it, executed it all the way through, and this execution of affected the further compile time phase of, allowing the compiler to distinguish that both foo and $FOO are valid here.

    Taking it a step further:

    use warnings; use strict; eval( rand() < 0.5 ? q{ sub foo { print "Hello!\n" } sub quz { print "Quz!\n" } } : q{ sub foo { print "Perl!\n" } sub baz { print "Baz!\n" } } ); foo(); # will it print "Hello!" or "Perl!" ? quz(); # will it die or won't it?

    I maintain that this is fundamentally different from how C and similarly compiled languages operate.

    Update: Minor edits to wording.

      True, I didn't mention eval. At least in the case of the "optimized C" back end, I should have. Programs that use eval and want to use this back end would still need to link to perl.dll or to run. Also, there may be other features of Perl impractical to translate without relying on perl.dll/

      As for Perl bytecode requiring a run time interpreter to execute the bytecode, so does Java bytecode.

      As for "run time side effects", I mean does a BEGIN block perform an action that only makes sense at run time.

      For example, suppose there's a Expect::Quick module and you use it like:

      use Expect::Quick Prompt => [ -re => '^\$\s+' ], REMOTE => 'user@examp'; send 'command param1 param2'; my $resp = before; ...;

      The implicit BEGIN block:

      BEGIN { require Expect::Quick Prompt; import Prompt => [ -re => '^\$\s+' ], REMOTE => '' +; }

      will create Expect obj, open a connection to and login as "user".

      If you saved the bytecode then load and run it later, the connection to will not be done.

      On the other hand:

      use Expect::Quick; connect Prompt => [ -re => '^\$\s+' ], REMOTE => ''; send 'command param1 param2'; my $resp = before; ...;

      could be compiled and the bytecode saved. Then later, when loaded and run, it would work correctly.

      The dynamic features of Perl would still be available to use.

      Of course, it is possible for the actual connect and login to be deferred until the first time send is called. My point is that import would have to be written to do that. And any other BEGIN blocks, implicit or not, could not perform actions that need to be performed at run time. But any and all of Perl's compile time magic is still "in play".

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://11101071]
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others romping around the Monastery: (6)
As of 2021-01-25 17:04 GMT
Find Nodes?
    Voting Booth?