Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When does BEGIN actually start (or is run)?

This is related to this issue in the Perl 6 documentation repo

It's not too clear the phase in which BEGIN blocks are actually run. Documentation says "compile time", but Perl is precompiled, so that might actually be precompile time. As a matter of fact, let's use this code

unit module Beginner;

BEGIN {
    say "This is where all started";
}

from here

require Beginner;

say "Begun";

in a fresh directory (rm -rf .precomp run). It outputs:

This is where all started
Begun

By now, the .precomp directory that holds the cache has already been created.

So let's use it from here:

use Beginner;
say "Already started";

And it obviously returns just Already started. (Same happens if we run the first program). This might be a problem, because the user might not know in advance if precompilation might take place or not, which in turn means that it's not certain when "compile time" is taking place. Anyway, the question is: how can we formulate this correctly to explain it in the documentation? Also, should the use of BEGIN be encouraged (since values computed there are going to be stored in the precompilation cache and thus effectively eliminated from runtime) or discouraged? Is there some good use case for this?

like image 585
jjmerelo Avatar asked Dec 18 '18 18:12

jjmerelo


2 Answers

BEGIN happens at compile time, and as you have observed correctly, this can be precompilation time.

I don't see any problem with that, as long as you don't assume compilation happens at script startup. Just like C++ templates are evaluated at compilation time, which is usually very different from execution time.

Also, should the use of BEGIN be encouraged (since values computed there are going to be stored in the precompilation cache and thus effectively eliminated from runtime) or discouraged

Everything should be encouraged for their appropriate use cases, and discouraged for everything else.

If you want to run something at program startup, use INIT, not BEGIN.

Is there some good use case for this?

Lots of meta programming can (and should) be done at compile time, for example creating a list of methods and attributes based on a fixed list of names. Doing that at every program startup would be a waste, and other parts of the program might need the complete type at compilation time.

like image 78
moritz Avatar answered Nov 03 '22 21:11

moritz


What Moritz wrote (and you accepted).

But I feel like cooking up an analogy.

how can we formulate this correctly to explain it in the documentation?

Possibly with an analogy. Here's one off the top of my head. Perhaps it'll help clarify things for readers of this SO. It is woefully inadequate in a manner I'll mention at the end. So don't use it in the docs. But perhaps it'll help inspire a decent analogy for adding to the docs.


A program is like a recipe for a cake. In our analogy it mixes instructions for preparing it and baking it.

Compiling a program is following the instructions for preparing the cake.

Running a program is following the instructions for putting the cake in the oven and baking it.

Precompilation is like preparing a cake and putting it in the fridge to be baked another day.

BEGIN time is preparation time. If an instruction starts with BEGIN then that instruction must be followed as soon as it's encountered by someone reading the recipe during preparation of the cake.

Preparation time can be immediately before baking the cake or on a prior day.

Normally the instructions (program) need to work fine whichever strategy is chosen (prepare and immediately bake or prepare, put in fridge, and bake later) by the chef (the compiler and the person using the compiler).

Also, should the use of BEGIN be encouraged (since values computed there are going to be stored in the precompilation cache and thus effectively eliminated from runtime) or discouraged?

Being prepared is generally a good thing. Most of the time, the work to be done for preparing a cake for baking is the same regardless of whether the prepared cake is stored in a fridge for a while or baked immediately after its preparation.

So I'd say encouraged. Certainly not discouraged, at least not in general.

But occasionally it makes sense to defer some work that might be called "preparation" until after the baking has begun. In which case don't use BEGIN for that because BEGIN specifically means compile-time in the sense of before run-time, as explained next.

Is there some good use case for this?

A constant is a good candidate for sorting out as part of "preparation".

A constant representing Christmas Day 2018 is a good candidate for defining at compile-time.

A constant representing Christmas Day is probably a good candidate for defining at run-time.

(Corny witticism about baking a Christmas cake intentionally omitted.)


This analogy sucks because as soon as you bake a cake (run a program) the prepared cake (precompilation cache entry) is gone.

The notion of cooking something needs to be replaced with a process that involves preparing (compiling) something that can then be copied any number of times to use it (run it). It'll also need to analogize well in explaining how sometimes "preparation" ought happen at run time.

Extra marks if the analogy has the same oddity that the tool used is called a "fooer" even though it's used to both "foo" ("compile") and "bar" ("run") the thing (program).

like image 40
raiph Avatar answered Nov 03 '22 22:11

raiph