in reply to runtime "use" statements via string eval

Well, I can't say whether or not it's completely ideal, but I've started using something like this to ensure that I've got all the modules I need:

#!/usr/bin/perl -wT use strict; $|++; eval( "use MIME::Lite;" ); die "Module Configuration Error: $@" if $@; # and so on.

Since I'm writing scripts for servers that I don't have have access to, I'm forced to test them on my personal resources, get them working, and then toss them into the Black Hole known as "Security Testing" in the company I work for.

Personally, I like being able to tell the "experts" that they need to "tail their error log" in order to tell me what what wrong. *grin*

A recent check via CB seemed to think this was an okay approach. As always, YMMV...

Update: In reply to geektron's reply below:

Ah, I get you. Yeah, that feels weird. To my mind, you should localize your uses and your uses/requires into a configuration section before doing any work. If it's gonna fail, get it to do so before you waste any time...unless you have a problem with people, like, y'know, deleting modules from underneath you. (And if that's going on, well, friend, you've got more issues than concurrency ones, if you know what I mean.)

I spent about an hour poring over various perldoc entries and the closest I can find to anything that's documented is from perlmod,

"You can switch into a package in more than one place; it merely influences which symbol table is used by the compiler for the rest of that block."

Not entirely related, but if you read it obliquely, I think it suggests that there's no real benefit to using the module multiple times...unless (for some strange reason) you're modifying values in the module itself. Even then, I can't see how this would possibly make any difference. If you've used the module once, you've got to have a little bit of faith that it still exists within a few clock cycles.

Thoughts? Feedback?

--f

Update #2: Fixed a rather nasty typo that damian1301 caught. (Thanks.)

Replies are listed 'Best First'.
Re: Re: runtime "use" statements via string eval
by epoptai (Curate) on Apr 04, 2001 at 07:44 UTC
    I've come to similar solutions as footpad with slight variations.

    In the first case a required module isn't installed and the script dies with a link to the dist on CPAN:

    eval("use XML::Simple 'XMLin'"); # required xml parser if($@){&install_xml_simple(); exit} sub install_xml_simple { print header; print qq~Install <a href='http://search.cpan.org/search?dist=XML-Simple'>XML::Simple</a +>~; }
    Second case just causes some form buttons and text to not be printed later:
    my$trade = 0; eval("use Compress::Zlib"); unless($@){$trade = 1} # if installed enable export/import
    And another switch if the script doesn't find a self-created data file:
    use vars qw($xpdat1 $dat1); my($xpdata,$data,$md,$nodat) = 0; # vars for next block my$df = 'some.data'; if(-e $df){ if(eval "require '$df'"){ $md = (stat($df))[9]; $xpdata = $xpdat1; $data = $dat1; } } else{ $nodat = 1 }
Re: Re: runtime "use" statements via string eval
by geektron (Curate) on Apr 04, 2001 at 05:08 UTC
    there's one major difference, and i guess it wasn't quite clear from the first post.

    you're still useing the modules at the beginning, even though they're wrapped in an eval. and they're wrapped in an eval for a reason -- you're handing the scripts off to folks who may or may not have that resource.

    the issue, with more context:

    sub do_stuff { ### some stuff eval "use Foo::Bar::Baz;"; die if $@; ## do stuff with the imported functions }
    in some cases, the same  eval "use Foo::Bar::Baz;"; will end up in a different sub, same module. . .

    there's no 'hand off to client' - these are all internally-developed modules. . .

    i know that it's perfectly legal perl syntax . . . . it just doesn't sit quite right with me . .

    UPDATE: the thing is, and i haven't made it clear, is that the module being used in the eval string is NOT being used on 'initialization' ( for lack of a better word ). there's no 'use Foo:Bar::Baz;' at the beginning for the module. . .

    and i've been looking to see if there were any other issues than 'bad style'.

      First of all I think that external dependencies like that should be up front and obvious.

      Secondly each string eval ties up memory. If this is called in a tight loop, you will have a serious memory leak.

      A better way to do it is:

      require Foo::Bar::Baz; Foo::Bar::Baz->import();
      and leave out the second line if it is not necessary.