Beefy Boxes and Bandwidth Generously Provided by pair Networks
Keep It Simple, Stupid
 
PerlMonks  

The 'eval "require $module; 1"' idiom

by sedusedan (Monk)
on Apr 19, 2014 at 05:04 UTC ( #1082861=perlquestion: print w/ replies, xml ) Need Help??
sedusedan has asked for the wisdom of the Perl Monks concerning the following question:

Could someone refresh me on why the ; 1 part is necessary again? In other words, why is this idiom safer/better/more correct than just eval "require $module", especially in the context of using the expression in conditional (e.g.: eval "require $module; 1" or warn "Can't load $module";). I've used this idiom for years, and recently even submitted a patch to Log::Log4perl related to this. But for the love of heaven, I forgot why it's needed in the first place. Let's consider the cases:

Case 1. Module cannot be not found on the filesystem. require dies with message "Can't locate $module in @INC ...", eval traps it and sets $@ and returns undef. ; 1 part in idiom is not needed (unreached).

Case 1b. Like case 1, but previous attempt has been made. Ditto.

Case 2. Module has compile errors. require dies with compile error message, eval traps it and sets $@ and returns undef. ; 1 part in idiom is not needed (unreached).

Case 2b. Like case 2, but previous attempt has been made. After the first attempt, the entry in %INC is set to undef. At the second attempt, require will die with message "Attempt to reload $module aborted", eval traps it, sets $@, and returns undef. ; 1 part in idiom is not needed (unreached).

Case 3. Module is loaded successfully and returns a true value (in other words, the normal success case). require will return 1. ; 1 part in idiom is not needed.

Case 3b. Like Case 3, but previous loading has been made. require will return 1. ; 1 part in idiom is not needed.

Case 4. Module is loaded successfully but returns a non-true value. require will die with message "$module did not return a true value ...". eval traps it, sets $@, and returns undef. ; 1 part in idiom is not needed (unreached).

Case 4b. Like case 4, but previous attempt has been made. Ditto.

There are other cases possible (like a permission error when reading source file, require() being overriden, etc) but the above are the common/majority cases. So what cases does the ; 1 part cover? Does this have something to do with older versions of perl (I'm testing this on 5.18.2).

Comment on The 'eval "require $module; 1"' idiom
Select or Download Code
Re: The 'eval "require $module; 1"' idiom
by davido (Archbishop) on Apr 19, 2014 at 05:40 UTC

    This is a generalized idiom, in the form of:

    eval "something_that_might_fail(); 1;" or die "Message.";

    In the general case, it makes sense because "something_that_might_fail()" could be some expression where "false" or "undef" are not out of band for success (ie, are perfectly valid return values even for a successful call).

    In the specific case of "eval "require Some::Module; 1;" or die "Message.", your "Case 3" and "Case 3b" observations are accurate; require will return 1 on success. In this specific case, the 1; is redundant, though semantically it does maintain eval's return value to not be tied to the return value of the primary "thing that might fail."

    On the one hand, one might say that "eval "require Foo; 1;" or die "Message";" is cargo culted. On the other hand, the idiom as a general tool is useful, and probably doesn't need to be optimized further just because this specific application doesn't need the 1;. It's healthy to decouple the thing that might fail's return value from the success sentinel, which is what the idiom does.

    By the way; this is a very well researched question. Kudos.


    Dave

        I wish the grep.cpan.me supported lookaheads and lookbehinds, which would allow me to search a little more specifically for situations where the idiom is used outside of the "require" and "use" use case. If it did, I might try something like:

        if \(eval ["'](?!require|use).+?;\s*1;?["']

        Dave

Re: The 'eval "require $module; 1"' idiom
by tobyink (Abbot) on Apr 19, 2014 at 09:14 UTC

    I generally consider it to be cargo cult. There's no situation where require lives but returns false.

    That said, your case 3 is incorrect. Require doesn't (always) return "1". It returns whatever the module returned.

    $ cat Foo.pm package Foo; 2; $ perl -E'say eval "require Foo"' 2

    Case 3b is correct though - if a module has already been loaded, require just returns 1.

    $ perl -E'say eval "require Foo" for 1..3' 2 1 1
    use Moops; class Cow :rw { has name => (default => 'Ermintrude') }; say Cow->new->name

      I generally consider it to be cargo cult. There's no situation where require lives but returns false.

      So the threshold for "cargo cult programming" is one character?

      I don't think you can ever determine if this idiom is caro-cult based on this idiom, especially in isolation

        As per your own link, cargo cult programming is the ritual inclusion of code or program structures that serve no real purpose. This is code that serves no real purpose. I don't have a character threshold. If it were possible to include code or program structures using zero characters, and that code or structure served no purpose, then I'd argue that to be cargo cult too.

        This kind of thing is what gives newcomers to Perl the impression that it's full of magical incantations, and they'd be better off using Python. (I grant you that this is a very minor and seemingly insignificant example, but it does all add up!)

        use Moops; class Cow :rw { has name => (default => 'Ermintrude') }; say Cow->new->name
      Yup, I miswrote. Case 3 is when the module returns true and likewise require returns true too (which is whatever true value that the module returns). Thanks for clearing that part up.
      I generally consider it to be cargo cult.

      I intentionally put the "; 1" into this exact construct not out of some worship of practices that I have observed and not understood.

      I put the "; 1" to show that I am explicitly checking for whether or not the code inside of the eval dies.

      To a lesser extent, I also do it just to short-circuit the reader having to contemplate if there are any ways where require could not die but also not return a true value. I believe that the 'die' behavior of require is quite well understood.

      However, the return value from require is almost never used. It isn't even really documented. You can infer likely return value behavior from Perl code included in the require documentation but that code is marked "Has semantics similar to the following subroutine:" (emphasis added), so such conclusions seem wise to treat with a certain level of skepticism.

      The primary interface for require is that it loads the module or it dies. So it makes sense to use a construct that tests for whether or not the require died. That is what the "; 1" does. Leaving off the "; 1" requires the reader to try to find and understand information about a bit of behavior that is nearly useless and is poorly documented. That is not an improvement.

      - tye        

        ++

        ...which is why, as an idiom, it's wise to disconnect the success flag from the return value of the thing_that_may_fail(). I'm glad I'm not alone in seeing merit in the clarity that comes from decoupling the thing that may fail from the idiom that tests it.

        The point to "eval "possible_failure(); 1"" is that we're not concerned with possible_failure()'s return value, we're concerned whether or not it threw an exception. We shouldn't have to look up and infer what its return value will be, we should simply test whether it threw an exception or not. That's where 1;" or warn "Woops!"; comes in.


        Dave

Re: The 'eval "require $module; 1"' idiom
by Anonymous Monk on Apr 19, 2014 at 12:45 UTC

      Yes, polluting the UNIVERSAL namespace by adding a method that can impact every single other class used is so much better than writing one simple, well-understood line of Perl code.

      So, when I run across a line of code like:

      if( $module->require() ) {

      in some Perl code, I'll likely suspect what it might be doing. But, especially the first time, I likely won't be completely sure, especially not on all of the details. So I'm likely to want to go read the documentation for this routine. And it is so easy to imagine having no idea where to find that documentation. Especially if the loading of UNIVERSAL::require was done from some other code file (yay for action at a distance).

      A much less cute interface for this functionality would have been a much better idea. Running into code like:

      use Module::Require qw< could_require >; # ... if( could_require( $module ) ) {

      would make the breadcrumbs from the mystery code to the module that documents it obvious in the typical manner of Perl modules.

      Such an interface would also prevent weird surprises when you misremember a similar method name on some other class and get silent behavior very much different from what you expected and then waste a ton of time trying to figure out what is going on. Because the silent behavior was made possible by the loading of some module by some code that has almost nothing to do with the code you are working on. Action at a distance at its finest.

      - tye        

Re: The 'eval "require $module; 1"' idiom
by Anonymous Monk on Apr 19, 2014 at 21:39 UTC
    The ;1 makes the security hole a little less obvious.
Re: The 'eval "require $module; 1"' idiom
by Anonymous Monk on Apr 19, 2014 at 23:51 UTC

    As plenty of monks have pointed out, in the context of a conditional the ;1 isn't needed.

    In other contexts, consider:

    my $MODULE_WAS_LOADED = eval "require 'bar.pl'"; print "Debug: MODULE_WAS_LOADED=$MODULE_WAS_LOADED\n";

    And in bar.pl:

    # ... module code here ... "For some reason this module has chosen to make its return value some ridiculously long value; perhaps the original author simply forgot to add the usual 1; at the end of the module and this return value is simply whatever the last statement in the module evaluates to. Whatever the case, I'd prefer it not polluting my debug output." #EOF

      Even in that case, I still wouldn't add ";1" to the evaluated string. In your example, use warnings would be complaining about concatenating an undefined value. Instead I'd probably go with

      my $MODULE_WAS_LOADED = !! eval "require 'bar.pl'";

      Or perhaps even:

      my $MODULE_WAS_LOADED = 0+!! eval "require 'bar.pl'";

      (which might look nicer in the debugging output).

      use Moops; class Cow :rw { has name => (default => 'Ermintrude') }; say Cow->new->name
Re: The 'eval "require $module; 1"' idiom
by sundialsvc4 (Monsignor) on Apr 22, 2014 at 21:10 UTC

    I dunno, tye ... I sincerely respect your greater knowledge on this particular subject, but I certainly believe that UNIVERSAL::require has helped me out of quite-a-few tight spots.   It’s a very small bit of source-code, actually, but it sure did grease a lot of hinges.

    Nevertheless, looking-over the OP’s original posting (and never-mind UNIVERSAL at this point ...), I do feel that most of these bullet-points should properly be dismissed as hypothetical ... or as “downright suspicious.”   “Suspicious,” in fact, to the degree that we should not consent to write code that is willing to accomodate them.

    “Suspicious S.O.B. that I am,” I think that it is perfectly reasonable to presume that any module that we might actually wish to consent to require into our systems should be entirely free of compile-errors and should return true.   If it does not, then why-the-heck should we be willing to presume that “the source-file that we are referencing” is, in fact, the legitimate piece of source-code that we (innocently? na´vely?) expected to find?   It could just as easily be a rogue – a malicious imposter – that some Evil Entity™ didn’t quite get quite-right the first time.

    The “stock” implementation of require has a few pragmatic rough-edges that can be fairly glossed-over (e.g. by UNIVERSAL ...), but we should never allow our “suspension of disbelief” to go too-far.   If any situation that we encounter crosses the boundary of healthy suspicion, we should not allow it to proceed.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1082861]
Approved by GrandFather
Front-paged by Desdinova
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others having an uproarious good time at the Monastery: (13)
As of 2014-07-31 18:21 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    My favorite superfluous repetitious redundant duplicative phrase is:









    Results (250 votes), past polls