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

Is there a way to call a subroutine by reference ?

I'm writing a set of subroutines which will call other subroutines within them. The first 4 subroutines are always going to be called in the same order to set up the data to be analyzed.

The last nested subroutine would be the actual analysis of the data.

If subroutine calls have to be hard-coded, I'll need to copy and modify a seperate script for each analysis technique applied in that last subroutine. I'd also have to propogate any changes to main script to the copies.

Not a huge problem, but it would be helpful to be able to pass a reference to the desired analysis subroutine, along with the required parameters. I could do that via command-line parameters when running the script, instead of having a different script for each technique.

Is this possible, or am I just asking for trouble ?

Dyslexics Untie !!!

Replies are listed 'Best First'.
Re: Call subroutine by reference ?
by NetWallah (Canon) on May 31, 2013 at 03:23 UTC
    The canonical solution to this issue is to use a "Dispatch table".

    This is typically a hash whose keys are the text that is used to identify which sub to call, and the value is a reference to the sub.

    my %Dispach_table = ( UNO => \&Process_One, DOS => \&Process_Two, TRES => sub { print "This is an example of an in-line subref\n"}, ); sub Process_One{ #whatever } sub Process_Two{ # Some code } my $var = "DOS"; # Invoke the dispatch (after verifying it exists) $Dispatch_table{ $var } or die "ERROR: attempt to dispatch non-existin +g entry: '$val'"; $Dispatch_table{ $var } -> ( #Parameters, if any ); # Here is where the routine gets called.
    Update: Added check for "existence" as recommended by sundialsvc4 (++), below. (Also fixed text typo).

                 "I'm fairly sure if they took porn off the Internet, there'd only be one website left, and it'd be called 'Bring Back the Porn!'"
            -- Dr. Cox, Scrubs

      Yes, and to clarify with-regard-to my previous post, there is no conflict between the two ideas ... they are quite-ordinarily used together, as Perl applications are quite-ordinarily built as systems of packages instead of monolithic and repetitive individual scripts.   If you use a package, the subs in them are (ordinarily ...) visible, both as subroutine_name and, if necessary, as package_name::subroutine_name.   You can build code-references freely, as shown, because everything comes-together in memory (just...) before execution of the whole thing begins.   The dispatch-table idea obviously is clearer and more-expandable than my if..elsif.. structure, which was merely used here for clarity.

      n.b.:   In actual practice, the exists() function should be used to verify that the key being sought actually does exist in the table, before attempting the call.   e.g. die "horribly" unless exists($dispatch_table->{$key}); ... so that the program will react graciously, or at-least die on its own terms instead of puking with “can't use 'undef' as a code reference” or what-not.

      The Dispatch Table appeals to the Organization-OCD side of my brain :)

      I might end up with more than one main script, depending on the modifications I make to the analysis subroutines due to some variations on data content. So I'll need to pay more attention than usual to the code variations.

      Fortunately, I like that kind of project ;)

      Dyslexics Untie !!!
Re: Call subroutine by reference ?
by LanX (Saint) on May 30, 2013 at 23:51 UTC
      Thanks for the link to that node, Rolf. Good discussion there. Not sure which syntax I'll go with yet, I'll have to try them out to see which fits best for me.

      And I got a chuckle out of a couple of really amusing sigs there :)

      Dyslexics Untie !!!
        your welcome! =)

        I normally prefer the arrow dereference, much easier syntax in nested structures like dispatch tables.

        Exceptions are calls w/o arguments (much shorter) or functions with prototypes which insist in a leading ampersand.

        Cheers Rolf

        ( addicted to the Perl Programming Language)

Re: Call subroutine by reference ?
by Anonymous Monk on May 30, 2013 at 23:48 UTC
Re: Call subroutine by reference ?
by locked_user sundialsvc4 (Abbot) on May 31, 2013 at 02:16 UTC

    Taking a slightly less literal viewpoint to your situation ... what I would do is to spin-off the common subroutines into a Perl package that you can then use in any of the scripts that need to refer to them.   Now, any number of scripts can incorporate the code (i.e. “can reference” in the colloquial sense of “can refer to”) without textually including it.

    The different variations of the 4th-stage analysis subroutine can likewise be implemented as additional packages.   Now, each one of them also becomes something that can be “referred to” without textually including it.

    A very short script can now be written, which uses (or on-demand requires), each of these other units, and which contains the logic to invoke their contents in an appropriate sequence.   For example, consider this purely-illustrative (don’t try to run this at home!) sketch:

    use stages_1_thru_3; # common preamble use stage4_huey; # analysis routines use stage4_dewey; use stage4_louie; ... stages_1_thru_3::run_preamble(); # run the common code # now pick a 4th-stage subroutine to run if ( $method eq 'huey') { stage4_huey::huey_analysis(); } elif {$method eq 'dewey') { stage4_dewey::quack(); } ... blah ... else { die "Sorry, I don't know about '$method'"; } ...

    I’ve bent the rules of Perl syntax quite freely for the purposes of illustration.   Any script or package which uses another package immediately gains access to whatever’s in it, in its current version as of the instant that the useing script is run.   Thus, there is no duplication of source-code and no problem with versioning.   “The code that users execute in order to do things” (scripts ...) are now at an arm’s length removed from “the units of code that are common to all of them (packages ... modules...), which are “incorporated by reference” anywhere that they are needed.

    Does my interpretation have anything to do with the other responses previously given?   N-o.   Keep that in mind.   I have assigned a different human meaning altogether to your use of the word, “reference.”   Other responses in this thread have employed a more technical (and Perl-specific) meaning of the same word.   Which one is correct is up to you, but they are apples and oranges.   Don’t read them together.

      I didn't mention this in my original post, but I'm putting the subs in seperate modules. Which is part of the reason for the original questions - the other one being the recent node on limits of nested subroutine calls.

      I'll be processing fairly large ( for me ) data sets, from 85MB up to 200MB or more, in one pass. Nesting seems to be the best path I can think of to break the processing up into smaller chunks of related data.
      Dyslexics Untie !!!