BEGIN::Lift - Lift subroutine calls into the BEGIN phase
package Cariboo; use strict; use warnings; use BEGIN::Lift; sub import { my $caller = caller; BEGIN::Lift::install( ($caller, 'extends') => sub { no strict 'refs'; @{$caller . '::ISA'} = @_; } ); } package Foo; use Cariboo; extends 'Bar'; # functionally equivalent to ... # BEGIN { @ISA = ('Bar') }
This module serves a very specific purpose, which is to provide a mechanism through which we can "lift" a given subroutine to be executed entirely within the BEGIN phase of the Perl compiler and to leave no trace of itself in the RUN phase.
BEGIN
RUN
If a package that uses this module is loaded at runtime (perhaps via the require builtin), it will still work correctly (to the best of my knowledge that is).
require
install( $package, $keyword_name, $keyword_handler )
This will install a lifted subroutine named $keyword_name into the specified $package. All calls to this the lifted subroutine will execute the $keyword_handler immediately after parsing it.
$keyword_name
$package
$keyword_handler
If this subroutine is called outside of the BEGIN phase, an error will be thrown. If there already exists a typeglob for $keyword_name then an error will be thrown.
This means they require no runtime initiatlization or access to runtime initialized variables (as they won't be initialized).
For instance, given a lifted subroutine called add, this code is BEGIN time safe because the arguments are numeric literals.
add
add( 1, 1 );
While this version is not safe because it relies on the @args variable being initialized at runtime.
@args
my @args = (1, 1); add( @args );
Ideally we can (eventually) detect these situations and error accordingly so that this is no longer a burden to the user of this module, but instead just part of the normal operation of it.
If, for instance, a lifted sub is called such that the return value is to be assigned to a variable, such as:
my $x = my_lifted_sub();
It will not behave as expected, since my_lifted_sub is evaluated entirely at BEGIN time, the resulting value for $x at RUN time is undef.
my_lifted_sub
$x
undef
If, for instance, a lifted sub is called within an expression where the return value is important, such as:
if ( my_lifted_sub() && 10 ) { ... }
It will not behave as expected, since my_lifted_sub is evaluated entirely at BEGIN time and has the value of undef at runtime, the conditional will always fail.
If, for instance, a lifted sub call is guarded by a statement modifier, such as:
my_lifted_sub() if 0;
It will not behave as expected, since the lifted sub call is evaluated entirely at BEGIN time the statement modifier has no affect at all and <my_lifted_sub> will always be executed.
This does a similar thing, but does it via "some slightly insane perlguts magic", while this module has much the same goals, it will (hopefully) accomplish it with less insanity.
Stevan Little <stevan@cpan.org>
This software is copyright (c) 2017 by Stevan Little.
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.
To install BEGIN::Lift, copy and paste the appropriate command in to your terminal.
cpanm
cpanm BEGIN::Lift
CPAN shell
perl -MCPAN -e shell install BEGIN::Lift
For more information on module installation, please visit the detailed CPAN module installation guide.