The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

BEGIN::Lift - Lift subroutine calls into the BEGIN phase

SYNOPSIS

  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') }

DESCRIPTION

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.

Modules loaded at runtime?

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

FUNCTIONS

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.

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.

CAVEATS

All arguments to lifted subroutines must be BEGIN time safe

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( 1, 1 );

While this version is not safe because it relies on the @args variable being initialized at runtime.

  my @args = (1, 1);
  add( @args );

PARSING ISSUES

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.

Non-void context

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.

Expression context

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.

Statement modifier context

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.

SEE ALSO

Devel::BeginLift

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.

AUTHOR

Stevan Little <stevan@cpan.org>

COPYRIGHT AND LICENSE

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.