I'm looking for help regarding the documentation of the new variable
${^GLOBAL_PHASE} in the perl core.
All that variable will do is expose the current global interpreter phase
to Perl space, similar to how things like Devel::GlobalDestruction
currently expose "Am I under global destruction?"
Most of the patch, which I'll attach for your convenience, is already
vetted by p5p. What I'm looking for specifically is a place to document
it. Obviously it needs an entry in perlvar, but I don't think explaining
all the details of it there is appropriate. "BEGIN, UNITCHECK, CHECK,
INIT and END" in perlmod explains many things related to
${^GLOBAL_PHASE}, but it does so from the perspective of a single
module, i.e. one compilation unit, for which most of the behaviour of
the new variable is irrelevant, as that's only concert with global
phases. Also it'd seem somewhat unlikely that anyone would look up
"perlmod - Perl modules (packages and symbol tables)" to read about the
phases of the interpreter.
Also, once a place for documenting this is found, I'd also very much
appreciate suggestions on how to actually document it.
Here's some details of the new variable.
Possible values include:
1. CONSTRUCT
The PerlInterpreter* is being constructed via perl_construct. This
value is mostly there for completeness and for use via the
underlying C variable PL_phase. It's not really possible for Perl
code to be executed unless construction of the interpreter is
finished.
2. START
This is the global compile-time. That includes, basically, every
BEGIN block executed directly or indirectly from during the
compile-time of the top-level program.
This phase is not called "BEGIN" to avoid confusion with
BEGIN-blocks, as those are executed during compile-time of any
compilation unit, not just the top-level program. A new, localised
compile-time entered at run-time, for example by constructs as
`eval "use SomeModule"' are not global interpreter phases, and
therefore aren't reflected by ${^GLOBAL_PHASE}.
3. CHECK
Execution of any CHECK-blocks.
4. INIT
Similar to "CHECK", but for INIT-blocks, not CHECK-blocks.
5. RUN
The main run-time, i.e. the execution of PL_main_root.
6. END
Execution of any END-blocks.
7. DESTRUCT
Global destruction.
Also note that there's no value for UNITCHECK-blocks. That's because
those are run for each compilation unit individually, and therefore is
not a global interpreter phase.
Not every program has to go through each of the possible phases, but
transition from one phase to another can only happen in the order
described in the above list.
The patch also includes some basic tests, if you prefer actual working
examples of how ${^GLOBAL_PHASE} behaves.
My gut reaction is that the values need to be documented in perlvar in
a similar way to how you have listed them here and a mention of it
should be in each paragraph of perlmod that deals with BEGIN, INIT,
etc. I will throw something together tonight.
--
Chas. Owens
wonkden.net
The most important skill a programmer can have is the ability to read.
> I'm looking for help regarding the documentation of the new variable
> ${^GLOBAL_PHASE} in the perl core.
Note that there's a new perlvar in briandfoy/perlvar about to be merged
into blead.
I have attached my first draft of the documentation (they include
brian d foy's changes from last night).
Also attached is a patch that adds a mention of the fact that string
do and require behave the same way as string eval with respect to UNIT
and INIT blocks.
> I have attached my first draft of the documentation (they include
> brian d foy's changes from last night).
You're awesome. Thank you *so* much!
> diff --git a/pod/perlmod.pod b/pod/perlmod.pod
> index d6ddd83..44d5924 100644
> --- a/pod/perlmod.pod
> +++ b/pod/perlmod.pod
> @@ -273,6 +273,11 @@ and such from other files in time to be visible to the rest of the compile
> and run time. Once a C<BEGIN> has run, it is immediately undefined and any
> code it used is returned to Perl's memory pool.
>
> +Inside of a C<BEGIN> block, the C<${^GLOBAL_PHASE}> variable will be set to
> +C<"START">, unless the C<BEGIN> block was executed by C<require>, string
> +C<do>, or string C<eval>. In those cases the C<${^GLOBAL_PHASE}> will be
> +set to the phase the C<require>, C<do>, or string C<eval> was executed in.
I find that rather confusing.
Of course ${^GLOBAL_PHASE} is, during a certain phase, always set to the
phase that's currently running :-)
Saying that a value of "START" will only be present in some BEGIN-blocks
is a little misleading. While that's true, as everything where
${^GLOBAL_PHASE} will have a value of "START" will be run from a
BEGIN-block in the main program, it's easy to get that value from code
which doesn't directly contain such a block. For example
BEGIN { require Foo }
and in Foo.pm
is ${^GLOBAL_PHASE}, "START";
The run-time of Foo.pm happens during the compile-time of the main
program.
I think focusing too much on BEGIN-blocks while trying to explaining
"START" might be a mistake. To avoid this kind of confusion is why I
called the value "START" instead of "BEGIN" in the first place.
> C<UNITCHECK>, C<CHECK> and C<INIT> code blocks are useful to catch the
> transition between the compilation phase and the execution phase of
> the main program.
> @@ -302,15 +310,31 @@ C<UNITCHECK> blocks are run just after the unit which defined them has
> been compiled. The main program file and each module it loads are
> compilation units, as are string C<eval>s, code compiled using the
> C<(?{ })> construct in a regex, calls to C<do FILE>, C<require FILE>,
> -and code after the C<-e> switch on the command line.
> +and code after the C<-e> switch on the command line. So long as the
> +C<UNITCHECK> is not executed by a C<require>, C<do>, or string C<eval>,
> +the value of the C<${^GLOBAL_PHASE}> variable will be set to C<"START">,
> +otherwise it will be set to the phase the C<require>, C<do>, or
> +string C<eval> ran in.
> +
> +Inside of a C<UNITCHECK> block, the C<${^GLOBAL_PHASE}> variable will be
> +set to C<"START">, unless the C<UNITCHECK> block was executed by C<require>,
> +string C<do>, or string C<eval>. In those cases the C<${^GLOBAL_PHASE}>
> +will be set to the phase the C<require>, C<do>, or string C<eval> was
> +executed in.
I'm not sure explaining what values ${^GLOBAL_PHASE} might have in
UNITCHECK-blocks is too useful. It can be any of the possible values,
except for "CONSTRUCT" (as you can't compile code during that phase),
because you can compile code during any phase.
> diff --git a/pod/perlvar.pod b/pod/perlvar.pod
> index d3684a1..f159832 100644
> --- a/pod/perlvar.pod
> +++ b/pod/perlvar.pod
> @@ -503,8 +503,49 @@ Not every program has to go through each of the possible phases, but
> transition from one phase to another can only happen in the order
> described in the above list.
>
> -The patch also includes some basic tests, if you prefer actual working
> -examples of how C<${^GLOBAL_PHASE}> behaves.
> +An example of all of the phases Perl code can see:
> +
> + BEGIN { print "compile-time: ${^GLOBAL_PHASE}\n" }
> +
> + INIT { print "init-time: ${^GLOBAL_PHASE}\n" }
> +
> + CHECK { print "check-time: ${^GLOBAL_PHASE}\n" }
> +
> + {
> + package Print::Phase;
> +
> + sub new {
> + my ($class, $time) = @_;
> + return bless \$time, $class;
> + }
> +
> + sub DESTROY {
> + my $self = shift;
> + print "$$self: ${^GLOBAL_PHASE}\n";
> + }
> + }
> +
> + print "run-time: ${^GLOBAL_PHASE}\n";
> +
> + my $runtime = Print::Phase->new(
> + "lexical variables are garbage collected before END"
> + );
> +
> + END { print "end-time: ${^GLOBAL_PHASE}\n" }
> +
> + our $destruct = Print::Phase->new(
> + "package variables are garbage collected after END"
> + );
> +
> +This will print out
> +
> + compile-time: START
> + check-time: CHECK
> + init-time: INIT
> + run-time: RUN
> + lexical variables are garbage collected before END: RUN
> + end-time: END
> + package variables are garbage collected after END: DESTRUCT
I love that example. Also illustrating what happens when loading code
with `use', both during and outside of the global compile-time phase
might be cool, but I'm not really sure how that could be done.
> diff --git a/pod/perlmod.pod b/pod/perlmod.pod
> index eaa8ba9..d6ddd83 100644
> --- a/pod/perlmod.pod
> +++ b/pod/perlmod.pod
> @@ -311,10 +311,11 @@ in the Perl compiler suite to save the compiled state of the program.
> C<INIT> blocks are run just before the Perl runtime begins execution, in
> "first in, first out" (FIFO) order.
>
> -The C<CHECK> and C<INIT> code blocks will not be executed inside a string
> -eval(), if that eval() happens after the end of the main compilation
> -phase; that can be a problem in mod_perl and other persistent environments
> -which use C<eval STRING> to load code at runtime.
> +The C<CHECK> and C<INIT> blocks in code executed by C<require>, string C<do>
> +, or string C<eval> will not be executed if they occur after the end of the
> +main compilation phase (i.e. they are not in a C<BEGIN> block); that can be
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Again - true, but slightly misleading. They only have to indirectly be
within a BEGIN-block in the main compilation unit, which isn't always
obvious to see.
This is awesome work. Many thanks to both of you! :-)
> On Tue, Nov 02, 2010 at 10:36:25AM -0400, Chas. Owens wrote:
>
> are full of "unless", "So long as" and "In those cases" indicates a
> problem.
>
> The description of BEGIN and UNITCHECK suggests that the documentation
> is approaching the topic from the wrong point of view. I suggest
> removing the above and just saying something like:
>
> BEGIN and UNITCHECK blocks are unrelated to the phase of the
> interpreter. They can be created and executed during any phase.
I like the suggestion, but I'm not sure it's entirely true. "Anything
directly or indirectly run from a BEGIN-block in the top-level
compilation unit" exactly describes when ${^GLOBAL_PHASE} will be set to
"START". That may or may not be a good way to think about the START
phase.
For UNITCHECK it's right.
> I have attached my first draft of the documentation (they include
> brian d foy's changes from last night).
So i've tried to prepare a new branch with the original patch set
rebased against blead and your documentation added. However, I don't
seem to be able to find the changes brian made that you based your work
on.
Where exactly can i find that?
They were made to bleed:
http://perl5.git.perl.org/perl.git/commit/10c97e5d9fc40b1bf201fdd404df828778e564ed
I just realized that I owe you an updated version with things change
per your last email.