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

I'm having trouble changing the reference of a subroutine.   Here is how I start.
$localfile = 'customer'; $ulocalfile = ucfirst($localfile); $newdir = "$path/$localfile"; MakeDir(); # # SECOND GET THE FILE LAYOUT AND INITIALIZE FILE MANAGEMENT TOOLS # $getfile = "Read$ulocalfile"; $updatefile = $guestfile = "Write$ulocalfile"; $deletefile = "Delete$ulocalfile"; require "$path/files/$ulocalfile"; require "$path/processes/GuestBook";
In just a little bit I set $updatefile = 'ProcessGuestBook';

The main script calls the subroutine by &$updatefile. So far so good. Now when I get into the ProcessGuestBook subroutine I have a need to change &$updatefile to refer to it's orginal value. I thought I could just reset it by $updatefile = $guestfile and then invoke the subroutine &$updatefile. What I get is an error letting me know that the script can't find the subroutine.

Any way to change the reference on the fly?
UR

janitored by ybiC: Retitle from "anonymous subroutine", minor format tweaks for legibility

Replies are listed 'Best First'.
Re: Symbolic reference to a subroutine
by sauoq (Abbot) on Dec 19, 2003 at 21:30 UTC

    Have you checked the actual value of $guestfile to be sure it is what you think it is? Do you really want three separate subroutines for each possible value of $localfile?

    What you are trying to do should work fine (though I wouldn't recommend it.) Here's an example to prove it:

    $ perl -le 'sub foo { print "foo" } sub bar { print "bar" } $s = $t = +"foo"; &$s; $s = "bar"; &$s; $s = $t; &$s' foo bar foo

    You really should consider doing this differently though. Using symbolic references usually results in difficult to maintain code and it is almost never necessary. If you must, consider using hashes and hard references to create a jump table. But, it seems to me that your problem would be adequately solved by passing the name of the file as a parameter rather than as part of the subroutine name.

    -sauoq
    "My two cents aren't worth a dime.";
    
Re: Symbolic reference to a subroutine
by Zaxo (Archbishop) on Dec 19, 2003 at 21:56 UTC

    I'll second sauoq's recommendation that you redesign this. You are hitting the kind of maintainance problems that will make this a nightmare, and it's not even written yet.

    Wherever you want to use a symbolic reference (sub foo;$bar="foo"; &$bar), use a real one instead (sub foo;$bar=\&foo;). That solves the problem of not finding the sub from a name. If you want to select them with strings, put them into a hash keyed by the name.

    If you want to change your program logic by changing the meaning of subroutines, there are formal methods to help you. OO has you do it by calling generic methods of an object and relying on the object to know its own implementations. State machines would have you carefully define the allowed combinations of function and make transitions between function sets all at once, with guarantees that intermediate and invalid states are not accessible.

    Some procedural logic may be the best way to simplify this code, too. I confess that I have no firm idea what your code is supposed to do. Am I right that you want a subroutine to know what what the invoking references to it used to point to? That threw me.

    After Compline,
    Zaxo