rick2g has asked for the wisdom of the Perl Monks concerning the following question:

I'm working on a vendor package that requires a certain format for callback hooks into a running server - the format is pretty simple:
$server_object->add_callback("function_name", "comma-separated-param_n +ames");
I've had to write a separate callback 'wrapper' for each function that I want to be able to call dynamically - but that means I have dozens of functions that look like this:
sub callback_wrapper { my ($callback_id, @params) = @_; my ($_err, $callback_data) = actual_function(@params); calback_reply($callback_id, $_err, $callback_data); return $_err; }
... and that's almost exactly the format for every callback - and I have dozens of those taking up lotsa text space and making what should be an elegant, concise file look incredibly bloated and copy/pasted. Is there anyway to dynamically generate these functions during compile-time so that I can just create an array with the callback/function names listed, then run thru the array to create the callbacks so that they can be loaded by the server during run-time?

Replies are listed 'Best First'.
Re: Dynamically generating function callbacks
by BrowserUk (Patriarch) on Nov 08, 2011 at 22:03 UTC

    Generating functions at runtime is pretty simple in Perl. And your desire to avoid repetitive source code by doing so is worthy and desirable.

    But I cannot make sense of your example -- which I suspect you've typed into the browser manually given the typo in calback_reply rather than cutting and pasting from actual code.

    • None of the identifiers in your first sample seem to match up with anything in your second. <
    • You show a single string containing "parameter names": "comma-separated-param_names".

      But I cannot relate this to anything in the second sample.

    • Do you actually have a subroutine called: callback_wrapper()?

      Or is that a 'placeholder' for a name that would need to be generated?

    Basically what I'm saying is: Yes, what you want to do is both possible and a good idea, but if you want some help on how to do it, then you're going to have to post some real examples of the subs you want to generate -- even if you feel the need to change the function and parameter names a little to "protect the innocent" -- so we can get a feel for the pattern involved.


    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
Re: Dynamically generating function callbacks
by graff (Chancellor) on Nov 09, 2011 at 08:17 UTC
    In addition to the questions raised in the first reply, I'm was wondering about this part:

    Is there anyway to dynamically generate these functions during compile-time so that I can just create an array...

    As BrowserUk mentioned, it's easy to write perl code that will create new subroutines at run-time, but I'm not sure what it means to create subs dynamically at compile-time. My understanding is that the latter simply doesn't happen (unless you get into evil things like code filters...) ... and AnonyMonk's reply below has cleared this up for me. (Thanks, AM! -- I had forgotten about that attribute of the BEGIN block. But now I'm still wondering if that's what the OP really wants.)

    Here's an example that might help, but since it's as vague as the snippets originally shown in the OP, it might confuse rather than illuminate, and/or might not resemble what you're trying to accomplish...

    #!/usr/bin/perl use strict; use warnings; sub callback_reply { print "callback_reply got " . scalar @_ . " args: @_\n\n"; } my ( %callback_sub, %callback_wrapper ); for my $i ( 1 .. 4 ) { my $subname = "function_$i"; $callback_sub{$subname} = sub { print "args passed to $subname: @_\n"; my $err_value = ( rand > 0.5 ) ? 1 : 0; my $rtn_value; $rtn_value += $_ for ( @_ ); return ( $err_value, $rtn_value ); }; $callback_wrapper{$subname} = sub { my ( $cb_id, @params ) = @_; my ( $_err, $cb_data ) = $callback_sub{$subname}->( @params ); callback_reply( $cb_id, $_err, $cb_data ); return $_err; } } for my $i ( 1 .. 4 ) { my @parms; for my $j ( 0 .. 1 + int( rand( 4 ))) { push @parms, sprintf( "%5.3f", $i + rand ); } printf( "Calling wrapper %d with %d params: %s\n", $i, scalar @parms + 1, "$i @parms" ); $callback_wrapper{"function_$i"}->( $i, @parms ); }
    (updated subroutine creation loop to use $subname instead of repeating "function_$i" throughout the loop)