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

OK, I have some code that could badly do with optimising via SelfLoader.

The program is an admin panel with a bunch of different screens. The structure is more or less like this:

# Do preparatory stuff, then &screens; &{ $screens{ $current_screen } } sub screens{ %screens = ( main => sub { ... main screen subroutine ... }, foo => sub { ... screen for foo ... }, # etc. etc. etc. ); }

Okay, so I am not sure if this was ideal, but it works quite nicely and I am not gonna change it, it's beta tested and all.

My question is, is there anyway to use selfloader so that only the relevant subroutine gets compiled? This would SERIOUSLY speed up the whole thing. I could do it by changing all the hash values to be refs to named subroutines, which would then go after __DATA__, but this would be a big hassle and not v extensible. Any neater tricks?

xxx
dave

PS: I am actually dash2 but have forgot my password and email is slow. Not that you would know who dash2 is.

Replies are listed 'Best First'.
Re (tilly) 1: selfloader and anonymous subroutines
by tilly (Archbishop) on May 10, 2001 at 15:46 UTC
    You could take a tack from CGI and replace your hash of functions with a hash of strings, then eval the one that you want.

    This will lock out the possibility of using techniques like closures though...

Re: selfloader and anonymous subroutines
by grinder (Bishop) on May 10, 2001 at 16:46 UTC

    Why don't you just break out each sub into a separate file. Then, you just

    &main_screen if $screen eq 'main';
    [update: argh, I just read your requirements more closely. Still I think you can slot it right in. As soon as you call &{$screen{$screen}} you'll hit the AUTOLOAD which will proceed as before but instead you'll want to do the file, and assign the results to $screen{$screen}} before executing the sub]

    Then, all you would have to do is to define your AUTOLOAD to requires the desired file, which could be named something like main.screen (long live self-documenting file names), which defines main_screen... and then run that.

    This would bring in the code on demand. If you changed the code in main.screen however, you would have to stop the program and restart it. If this is a problem, you could then start to get fancy, using anonymous subs, and reload the code on the fly if you notice that the file modification time has changed. I have written a Net::IRC bot that does this kind of trickery. I can add new code functionality to the bot whilst it is connected to a channel. The necessary smarts to handle keeping track of files is abstracted into a package.


    --
    g r i n d e r
(tye)Re: selfloader and anonymous subroutines
by tye (Sage) on May 10, 2001 at 21:16 UTC

    Well, if you insist on using SelfLoader, then I'd make the subroutine names the same as the screen names and replace the hash with just an array of screen names (then you could build the hash to preserve the current calling scheme if you like:

    foreach my $screen ( @screens ) { no strict 'refs'; $screens{$screen}= \&$screen; }
    ). It'd be nice if SelfLoader allowed you to grab the list of subroutines that it found, but that feature isn't supported.

    You could look into whether, when using AutoLoader, if you could get your modules Makefile to call AutoSplit in such a way that you end up with a list of subroutines in the installed module so you don't have to add new screen names in two places.

            - tye (but my friends call me "Tye")
Re: selfloader and anonymous subroutines
by stephen (Priest) on May 10, 2001 at 20:01 UTC
    I know that you've beta tested it and everything, but this screams for object-oriented programming. In fact, what you've done is kind of a reimplementation of some of Perl's OO features. :)

    It would be easier to make auto- or self-loading if you could make a class called Screens, then create a method called main, a method called foo, etc. Then you could move them down after __DATA__, and could therefore use the SelfLoader or AutoLoader. See perlman:perltoot for how to do this.

    Once you'd changed to OO syntax, your way of calling this functionality could be:

    my $screen_maker = ScreenMaker->new(); $screen_maker->$current_screen();

    For backwards compatibility, your &screens function could write stub routines to access the screens, like so:

    use ScreenMaker; use Carp qw(carp); sub screens { carp "Using deprecated '&screens' function"; my $screen_maker = ScreenMaker->new(); %screens = ( main => sub { $screen_maker->main() }, foo -> sub { $screen_maker->foo() }, }; }

    That way, currently-running code will still work, but will generate warnings that allow you to transform to OO methods.

    stephen