24783

How can a function pass all the arguments it received transparently to another function?

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.

<hr>

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.

Recommend

  • How to configure PhpUnit in Xampp?
  • Channel mix with Pillow
  • How can I install and use latest Git on Mac OS X 10.9?
  • Amazon ec2 linux Imagemagick issues
  • Installing ocropus-0.4.4
  • Antialias on clipPath on layout
  • Writing an RDA to CSV in R
  • Restructure php contact form
  • ionic plugin add phonegap-plugin-push results in a 404 Not Found Error
  • FOSUserBundle force user to write a different password
  • “undefined symbol: SQLAllocEnv” error in Java [duplicate]
  • Why are `colMeans()` and `rowMeans()` functions faster than using the mean function with `lapply()`?
  • Convert a 12 hour time format to 24 hour time format (keeping record of the day) in python
  • Objective-C : getting error on console while trying to display app on ipad device?
  • How can I selectively modify the src attributes of script tags in an HTML document using Perl?
  • Using ActiveRecord and Rails to insert Data into postgresql database get this error: RuntimeError: E
  • Error while importing scikits.talkbox
  • 'include' of functions in groovy scripts
  • How to configure Cygnus in relation to Orion and Cosmos
  • Query pkg-config variable through autotools
  • Can XOR be expressed using SKI combinators?
  • user data scripts fails without giving reason
  • Interpreting STRACE output - pipes and forks
  • cell spacing in div table
  • Write output of for loop to multiple files
  • XSLT foreach repeating nodes to flat
  • How to create a 2D image by rotating 1D vector of numbers around its center element?
  • Error in installing package: fatal error: stdlib.h: no such file or directory
  • Casting between Interfaces and Classes
  • Thread 1: EXC_BAD_ACCESS (code =1 address = 0x0)
  • Debugging VB6 Code From Visual Studio 2010
  • cygwin cannot exec 'git-add--interactive' permission denied
  • error importing numpy
  • What and where is mdimport
  • How do I open a C file with a relative path?
  • Allowing both email and username for authentication
  • Get one-time binding to work for ng-if
  • How do you troubleshoot character encoding problems?
  • Google cloud sdk not working when python points python3
  • Django query for large number of relationships