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

I've been experimenting with ideas to allow people to create their own Perl objects via a web application. The objects will execute in a server framework (becoming application components).

As people may refine and redefine methods within these objects, I have come up with the following way to "refresh" the existing objects on the fly. (The Everything engine uses eval liberally, but that imposes performance constraints I wish to avoid, if at all possible.) Is there a better way than this?

#!/usr/bin/perl -w -I"/home/chromatic/perl" use strict; use Sub; my $tester = Sub->new(); $tester->name; { local *OUTPUT; open(OUTPUT, ">>/home/chromatic/perl/Sub.pm") || die "Can't append +: $!\n"; print OUTPUT "\nsub game {\n"; print OUTPUT " print \"Hi, this is the game subroutine.\\n\";\n"; print OUTPUT "}\n"; print OUTPUT "1;"; close OUTPUT || die "Can't close: $!\n"; } require "/home/chromatic/perl/Sub.pm"; $tester = Sub->new; $tester->game;
and the Sub.pm file is, initially:
#!/usr/bin/perl -w package Sub; use strict; sub new { my $class = shift; my $this = {}; $class = ref($class) || $class; bless($this, $class); return $this; } sub name { print "Hi, this is the name subroutine.\n"; } 1;
This seems to work (aside from having extra 1; statements in the code :), but I get "Subroutine ___ redefined" errors. That makes sense... but is there a better way to do it?

Replies are listed 'Best First'.
RE: Redefining Subroutines on the Fly in a Persistent Application
by Anonymous Monk on Feb 23, 2000 at 03:46 UTC
    The 'require' is going to end up evaling the source contained in the Sub.pm file anyway, you might as well skip writing to disk and just do the eval yourself. To get rid of the "subroutine redefined" errors, you might want to try undefining the existing subroutine first (undef &a).
Re: Redefining Subroutines on the Fly in a Persistent Application
by btrott (Parson) on Feb 23, 2000 at 03:25 UTC
    But require has to do an eval anyway. Which means that, in the case of writing the sub out to the file, then require-ing it back in, you're doing both an eval *and* filesystem operations (the latter of which are, of course, pretty slow).

    So in my mind, at least, it seems that you'd get faster results using eval.

    I don't know exactly how you're using this code, but you might also want to implement some sort of package naming scheme (ie. so that they're not all in the Sub package)--perhaps come up w/ a unique numbering mechanism or something like that (so that you don't have the namespace issues like "Subroutine ____ redefined")?

    Finally, this seems conceptually similar to what the Apache modules do, particularly Apache::Registry. You may want to take a look at that to see how it's implemented--perhaps you could get some tricks from there? From the perldoc I read (very quickly), it sounds like they're taking the source, eval-ing it, then keeping the compiled code around in memory so that it can be invoked as a handler.

      The difference is, I expect to use the objects many many more times than I edit them. Thus, a require plus the cost of file access once out of ten or more hits is probably more efficient than an eval on each hit.

      Apache::Registry had a lot of good information in there... but they called a couple of mysterious XS functions in the mod_perl code itself, which is slightly beyond the scope of my project at this point. (Now I'm off to see if I can freeze an object, redefine part of its class, thaw it, and have everything work okay!)

Re: Redefining Subroutines on the Fly in a Persistent Application
by stephen (Priest) on Mar 09, 2000 at 22:39 UTC
    Hmmm... There's no way to get around the eval. You might be able to avoid the "subroutine x redefined" messages by using a hash of anonymous subs to store your actual routines, then either use the autoload function to execute them on demand, or implement a bunch of stub subroutines that just call whatever they're named after. Don't know if this might be leaky, though-- does Perl do garbage collection of dereferenced anonymous subs? It should. This is probably similar to what Apache::Registry does.

    stephen

Re: Redefining Subroutines on the Fly in a Persistent Application
by Anonymous Monk on Feb 25, 2000 at 07:32 UTC
    Well, you could do it the way Slash does it, which is pull blocks of code from a SQL server using the Perl::DBI interface, then eval those blocks of code.

    Of course, I'm playing devil's advocate here. You shouldn't do it that way.

    Cryptnotic