class - How to handle external sub prototype with local AUTOLOAD in Perl -
i'm having issue following scenario. i'm writting class uses autoload
somtimes call functions module (not mine). other module use few functions prototypes defined. 1 example this:
sub external_sub (\@$) { ... }
those functions work correctly when imported directly module, calls following:
my @arr = (1..10); external_sub(@arr, 'something else');
now, problem have when requiring external module class @ run time , importing function, can't find way pass right arguments it.
inside autoload
function, count on @_
only, , don't know if there's way in perl tell apart array passed first argument autoload
. so, inside autoload
, options can think far redirect call are:
no strict 'refs'; $sym = *{"externalmodule\::$called_sub"}; *$autoload = $sym; goto &$autoload;
...or like:
no strict 'refs'; return &{"externalmodule\::$called_sub"}(@_);
or several similar things using symbol table. however, problem how pass arguments call. if in code have:
package main; use strict; use mymodule qw(:some_external_subs); # import *names decide later modules take actual code refs # here have imported sub 'external_sub' symbol won't loaded until mymodule::autoload decides external module use import code function: @arr = ('some', 'values'); $result = external_sub(@arr, 'other_argument');
then, that's point autoload
in module require external module , pass call actual prototyped sub external_sub(\@$)
. problem pass received arguments @_
, @arr
, 'other_argument'
part of single list.
is there way resolve situation this? there way detect original arguments before becoming @_
?
keep in mind don't have control on external module , fact uses prototyped function.
thanks in advance comments!
to having similar problem, i've found far:
you can define prototypes @ compile time, otherwise ignored.
if know name of function @ compile time plan on loading code symbol later (at run time), can define prototype without code:
sub some_sub(\@$);
if don't know name of function can dynamically ar compile time, can use
scalar::util::set_prototype
declare local prototype only:package mymodule; use strict; use scalar::util qw(set_prototype); $protos; begin { # compile time @functions; # imagine load here @functions hashrefs containing name , proto values. no strict 'refs' $i (@functions) { # defines prototype without defining sub set_prototype \&{"mymodule::$i->{name}"}, $i->{proto}; # if want recall name/proto later in autoload: $protos->{$i->{name}} = $i->{proto}; } }
since declaration of prototype ready not definition of subroutine itself, when subroutine called first time trigger autoload
subroutine, can proceed assign actual coderef symbol. coderef use must have same prototype 1 declared name or receive error of prototype mismatch
. it's possible assign same prototype coderef using set prototype
if necessary, before assigning coderef real symbol.
for example:
sub autoload { our $autoload; $name = substr $autoload, rindex($autoload, ':') + 1; # here process , decide i'll call othermodule::some_sub name in $autoload no strict 'refs'; $coderef = *{"othermodule::some_sub"}{code}; # prototypes must match! unless (defined(prototype $coderef) , $protos->{$name} eq prototype $coderef) { set_prototype(\&$coderef, $protos->{$name}); } *$autoload = $coderef; goto &$autoload; }
if else knows of actual way alter prototypes @ runtime , have them work expected after that, i'll more happy know it!
meanwhile, hope helps facing similar situation in future.
Comments
Post a Comment