NAME

Sub::Attribute::Prototype - polyfill for :prototype attribute on older perls

SYNOPSIS

use Sub::Attribute::Prototype;

sub afunc :prototype(&@) {
   ...
}

DESCRIPTION

This polyfill allows a module to use the :prototype function attribute to apply a prototype to a function, even on perls too old to natively support it.

Perl version 5.20 introduced the :prototype attribute, as part of the wider work surrounding subroutine signatures. This allows a function to declare a prototype even when the use feature 'signatures' pragma is in effect.

If a newer version of perl switches the defaults to making signature syntax default, it will no longer be possible to write prototype-using functions using the old syntax, so authors will have to use :prototype instead. By using this polyfill module, an author can ensure such syntax is still recognised by perl versions older than 5.20.

When used on a version of perl new enough to natively support the :prototype attribute (i.e. 5.20 or newer), this module does nothing. Any :prototype attribute syntax used by the user of this module is simply handled by core perl in the normal way.

When used on an older version of perl, a polyfilled compatibility attribute is provided to the caller to (mostly) perform the same work that newer versions of perl would do; subject to some caveats.

Caveats

The following caveats should be noted about the pre-5.20 polyfilled version of the :prototype attribute.

  • Due to the way that attributes are applied to functions, it is not possible to apply the prototype immediately during compiletime. Instead, they must be deferred until a slightly later time. The earliest time that can feasibly be implemented is UNITCHECK time of the importing module.

    This has the unfortunate downside that function prototypes are NOT visible to later functions in the module itself, though they are visible to the importing code in the usual way. This means that exported functions will work just fine from the perspective of a module that uses them, they cannot be used internally within the module itself.

    Because this limitation only applies to the polyfilled version of the attribute for older versions of perl, it means the behavior will differ on a newer version of perl. Thus it is important that if you wish call a prototyped function from other parts of your module, you must use the prototype-defeating form of

    my $result = &one_of_my_functions( @args )

    in order to get reliable behaviour between older and newer perl versions.

  • Perl versions older than 5.20 will provoke a warning in the reserved category when they encounter the attribute syntax provided by this polyfill, even though the polyfill has consumed the attribute. In order not to cause this warning to appear to users of modules using this syntax, it is necessary for this polyfill to suppress the entire reserved warning category. This means that all such warnings will be silenced, including those about different attributes.

  • Because core perl does not have a built-in way for exporter to inject a UNITCHECK block into their importer, it is necessary to use a non-core XS module, B::CompilerPhase::Hook, to provide this. As a result, this polyfill has non-core depenencies when running on older perl versions, and this dependency includes XS (i.e. compiled) code, and is no longer Pure Perl. It will not be possible to use tools such as App::FatPacker to bundle this dependency in order to ship a pure-perl portable script.

It should be stressed that none of these limitations apply when running on a version of perl 5.20 or later. Though in that case there is no need to use this polyfill at all, because the :prototype attribute will be natively recognised.

AUTHOR

Paul Evans <leonerd@leonerd.org.uk>