
The title of this post says it all. The point is that the calling function X
should be agnostic about the signature of the called function Y
. IOW, X
should just pass to Y
, en masse, all the arguments it (X
) received, at leave it up to Y
to complain if the signature is off.
I thought this was just a matter of
sub X {
return Y( @_ );
}
...but apparently not:
sub getpwuid_wrapper {
return getpwuid( @_ );
}
The wrapper above is doing more than merely wrapping:
DB<7> p getpwuid( 5 )
gamesx560games/usr/games/usr/sbin/nologin
DB<8> p getpwuid_wrapper( 5 )
daemonx11daemon/usr/sbin/usr/sbin/nologin
The next bit gives a clue to what may be going on:
DB<9> p getpwuid( 1 )
daemonx11daemon/usr/sbin/usr/sbin/nologin
I figure that getpwuid( @_ )
is getting interpreted as getpwuid( scalar @_ )
, for reasons beyond my comprehension.
<strong>NOTE:</strong> getpwuid
is just an example to illustrate the problem. In practice one needs this sort of pass-through functionality primarily when the function that will be called is not known until runtime; e.g. when this function is a callback.
Answer1:
The problem you are facing is because getpwuid
has a prototype of $
, which causes it to interpret its parameter in scalar context.
You can see this from the following one-liner:
perl -e 'print prototype("CORE::getpwuid"), "\n"'
...which prints $
.
So when you pass @_
to getpwuid
, you are correct; it's being taken in scalar context and passing a count of how many elements @_
contains.
One solution is to use the subroutine form of goto
, which calls its operand with the same call stack and parameters that were passed to its caller.
Here's an example in the form of a one-liner:
perl -e 'print getpwuid(5), "\n"; print sub{ getpwuid(@_) }->(5), "\n"; print sub { goto &CORE::getpwuid }->(5), "\n";'
In this example, the first and third calls will pass '5' to getpwuid
, but the second call will pass scalar(@_)
, which is 1
in this case.
Another hackish option would be to detect whether the function you are calling has a prototype using the prototype
function, and react accordingly. But that's problematic. First, you already know you're calling getpwuid
-- no need to detect at runtime. And even if you had to detect at runtime for some reason, some CORE::
functions will return undef
for their prototype because they use one that cannot be expressed in terms of the prototype options available to us (system
, for example).
In this specific case since you already know what function you are calling, and already know its prototype, it's probably just easiest to do this:
perl -e 'print sub { getpwuid(shift) }->(5), "\n";'
<strong>Update:</strong> Where the subroutine being called isn't known until runtime goto
may be a good means. One of the things you have to look out for with goto
, however, is that you never return back to the parent sub; the subroutine being gone-to will return directly to the caller of the parent sub.
Another option is to call the target sub with the &
prefix and no parameters. This also serves to pass @_
through to it, but in a way that bypasses prototypes. Here's an example:
perl -e 'print sub { &CORE::getpwuid }->(5)'
This will appear similar to the goto
approach, but will not tinker with the call stack, and will return back to the parent sub.