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_prototypedeclare 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