Beefy Boxes and Bandwidth Generously Provided by pair Networks
more useful options
 
PerlMonks  

scope of "use strict"? (needed: "superstrict")

by argv (Pilgrim)
on Jul 07, 2005 at 03:11 UTC ( [id://473005]=perlquestion: print w/replies, xml ) Need Help??

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

it's so hard to do a full search on such a basic question, but I tried my best, so here goes:

Is there any way to impose a "use strict" on modules to which I cannot edit (due to permissions problems)? I suspect a bug in a module somewhere on another machine, but because the number of modules could be enormous due to various hidden inclusions, I figured the quickest way to get to the bottom of this would be to impose a "superstrict" directive that would cause perl to be strict about modules that may not have otherwise directed it.

Or, would it be more efficient to use a perl debugger in some way (that I'm not familiar with)?

  • Comment on scope of "use strict"? (needed: "superstrict")

Replies are listed 'Best First'.
Re: scope of "use strict"? (needed: "superstrict")
by etcshadow (Priest) on Jul 07, 2005 at 04:27 UTC
    Unfortunately, this is not going to help you out. If a module was written without using strict, adding strictures to it, after the fact, will most likely cause it to completely stop working.

    Take CGI.pm for example. It doesn't use strict, and it does work. If you download it from CPAN, and add "use strict;" to the top of it, it'll be all compiler errors and completely stop working.

    Strictures are a tool for writing code, not for debugging code. Granted, code written with strictures is going to be easier to debug... but code written without strictures cannot be debugged by applying strictures. If anything, it will be "bugged" by doing so.

    ------------ :Wq Not an editor command: Wq
      Goind point. What might be off service are warnings. Using -w on the command line will turn on warning for the script AND for modules (unless they explicitely turn them off).
        Using -w on the command line will turn on warning for the script AND for modules (unless they explicitely turn them off).

        Geez--call me stupid... but this doesn't seem to do it for me. I've got a simple perl module Foo.pm that exports a single function, foobar()

        Package Foo; require Exporter; our @ISA = qw(Exporter); our @EXPORT = qw($foo foobar); $foo = "bar"; sub foobar { $blah = "hi"; print "$foo $blah\n"; } 1;

        I wrote a perl script (foo.pl) that imports Foo.pm:

        #!/usr/bin/perl use Foo qw(foobar); $bar = "hi"; foobar();

        I inserted stuff in both the .pl and the .pm files that should generate warnings to test this. (Running foo.pl with no warnings is clean, expectedly.) So, I run:

        perl -w foo.pl

        and sure enough, I get a warning in my foo.pl script, but I do not get a warning for the $blah = "hi"; line in Foo.pm. If I add "use warnings;" to the top of Foo.pm as well, then yes, I do get a warning for Foo.pm. But, this goes against what you said: that "perl -w" should propagate the warnings to all the modules... what am I missing?

        dan

        ps. On another note entirely, "use strict;" in the module complains about $bar, which is exported. This is how the doc says to do it, and I see no other resource that says differently.

      Granted, code written with strictures is going to be easier to debug...

      Indeed, and therein lies my objective. My goal isn't to run the program or even "debug" it, per se. It's to look for specific kinds of error messages that may lead down a very specific path that may pre-empty looking in the wrong direction (for a potentially long time).

        You're missing my point. If the code was written without strictures, you cannot add them without rewriting the code. You're just as likely to introduce new bugs in doing so.

        Take this overly simple example:

        sub blarg { $i = $i+1; return $i; }
        Now, if you think "there's somethng wrong with this code, I'm going to fix it by adding strictures," then your first step would be:
        use strict; sub blarg { $i = $i+1; return $i; }
        Now this will give you errors (use of undefined variable $i). AHA! you say, I'll fix this by declaring $i at the scope at which it is used:
        use strict; sub blarg { my $i = $i+1; return $i; }
        Problem solved, strict warnings are gone. Only now your code is completely and totally broken, because little did you know that blarg() was a sequence generator. $i should have been declared at a broader scope than you did. Notice that your change was not syntactically incorrect, but it was semantically incorrect.

        Another option would be just to declare every variable used in the entire program at as wide a scope as possible, but that would completely defeat the purpose of strictures, all together.

        Last is to try to write something which goes through and adds in a my $var at the "right" scope. The problem with that, however, is that in the general case it is equivalent to The Halting Problem, i.e., writing a program that can analyze and understand the execution of another program, and it is provably IMPOSSIBLE. (Before anyone jumps on me about that being a false statement, about run-time versus structure, I just have one thing to say to you: eval.)

        In the end, code written with strictures is DIFFERENT CODE than code written without strictures. Turning strictures on in code that was written without them will just make things worse (unless you plan on REWRITING the code, COMPLETELY). What you're asking for is tantamount to something like: "Well I think that Java is easier to debug than Perl, so I'll take my perl code and run it through a java compiler." All it will do is produce red-herring errors, and tell you nothing about why your code is not doing what you want. Sorry.

        ------------ :Wq Not an editor command: Wq
Re: scope of "use strict"? (needed: "superstrict")
by davido (Cardinal) on Jul 07, 2005 at 04:57 UTC

    I don't fully understand why you would want to force modules to be compiled under strictures when they weren't designed to do so. As others have pointed out, this has the potential of generating lots of errors, and many of them will point to perfectly legitimate code, since it's possible to create bug-free code that isn't strict-compliant.

    But I thought it sounded like a fun little challenge, so in the spirit of "give them what they ask for" here is a little snippet that will test-compile every module in the dependancy heirarchy of your script with strictures enforced:

    use strict; use warnings; use IO::CaptureOutput qw/capture_exec/; my( $stdout, $stderr ) = capture_exec( 'perl', '-d:Modlist=nocore,stop,path,noversion', $ARGV[0] ); my( @modules ) = split /\n/, $stderr; foreach my $module ( @modules ) { my( $stdout, $stderr ) = capture_exec( 'perl', '-Mstrict', '-c', $module ); print "Module: $module\n\tSTDOUT = $stdout\n\tSTDERR = $stderr\n"; }

    This snippet requires Devel::Modlist, and IO::CaptureOutput. They aren't core, so you'll probably have to install them. Then run it like this:

    perl stricttester.pl yourcode.pl >output.log

    Then examine what you get in output.log. Every module that is strictures-compliant, and that is otherwise free from compiletime problems will compile "ok", and every module that isn't will give you a bunch of error messages.
    It actually works really slick.

    Enjoy!


    Dave

      I don't fully understand why you would want to force modules to be compiled under strictures when they weren't designed to do so.

      call it, "chasing a hunch." It's not my code I'm debugging, it's someone else's, and while I can easily "fix" some of his programming errors, I'm still trying to determine if those errors are the cause for other erratic problems going on.... like variable stomping, etc. So, I want to leave the errors in place and follow other sources to see what they do, and what the effects are. Note that it's not just determining "if" there's a bug, but finding "who" is doing the stomping? A quick examination of the "use strict" output could yield some instantly obvious results since I have an idea of what I'm looking for. Sometimes, it isn't enough to just fix a bug, it's finding out how far and wide its effects are before its fixed that can reveal other useful info one might not have expected.

      With some variations on your excellent script, I think I might find the very culprit I'm looking for.

      Put coderef into @INC, search for file, read in, prepend "use strict; ", eval ...
      In my experience, people dont 'design' modules to only work without strictures. More typically, they dont 'use strict' because, and I quote, 'you just end up with lots of annoying lines getting in the way' (I had an experience somewhat like that today - the developers had a huge script with everything as a global. And to top it all, I gave him a function to do some parsing, which promptly broke when he removed all the 'my's' in front of the lexical variables. A stern talking-to then ensued).

      ...it is better to be approximately right than precisely wrong. - Warren Buffet

Re: scope of "use strict"? (needed: "superstrict")
by tlm (Prior) on Jul 07, 2005 at 03:25 UTC

    You could try

    % perl -Mstrict -wc Suspect_Module.pm
    though you may need to add some more -M inclusions, e.g.:
    % perl -Mstrict -MRequired_Module -wc Suspect_Module.pm

    the lowliest monk

      If I had a "suspect module", I could do that, but as I said, I have no single module to look at. (If so, I could just copy it to my wriable space and debug it directly.)

      My objective is still the same: I want to force "strict" on all the modules that will be loaded.

Re: scope of "use strict"? (needed: "superstrict")
by graff (Chancellor) on Jul 07, 2005 at 05:09 UTC
    I'm no expert on this, so this is probably not an optimal approach, but maybe it's worth a try...

    Run "perl -d" to start a simple script that uses the suspect module(s). Then enter the "M" command to the debugger -- this will list all modules loaded so far, and their paths. (The list will include many that are loaded by "perl -d".

    If you do M at the start of the debugging session, modules that are loaded via run-time "require" statements won't show up yet. So have an executable statement that follows whatever minimal module activity should trigger loading and applying the bad module(s), break on that statement, and issue "M" at that point.

    If you can figure out a way to store the resulting list to a file, you can then easily follow up on the initial reply above: loop over the module files that are suspect and run "perl -cw" on each one. That's just a simple *n*x shell loop, or a simple perl script that runs a system() or backtick subprocess on each module file in the list.

    But as others have pointed out, the stricture issue by itself may be of indeterminate (and inadequate) worth for finding the particular bug you're looking for. Still, knowing how many modules are involved, and all their path names, is bound to help in some way.

    (Update: FWIW, using the debugger this way differs slightly from davido's excellent suggestion, in that it works without having to install the non-core Devel::Modlist module, in case that happens to be an issue for you.)

      BTW, I concede that in retrospect, this may not have been the best way to go about what I was after, but my having brought it up certainly unearthed some interesting information, and definitely a very helpful perl script (by davido) that may serve a better purpose elsewhere.
Re: scope of "use strict"? (needed: "superstrict")
by leriksen (Curate) on Jul 07, 2005 at 12:59 UTC
    Maybe the easiest solution is to copy the modules to an area where you can edit them, then use something like

    find . -name \*\.pm -exec perl -i -ne 'if (/^package/) {print $_ . "use strict\n;"} else  {print}' {} \;
    which searches for .pm files in the current directory and down (and which is where you copied them), looking for the 'package XXX;' lines and replacing them with

    package Foo; use strict;

    It assumes that the 'package Foo;' lines have no leading spaces - adjust if necessary...

    then you can run code that loads the modules and see what pops out, making sure to run the code as

    perl -I<path to root of strict versions> nameOfScript.pl

    good luck!

    ...it is better to be approximately right than precisely wrong. - Warren Buffet

Re: scope of "use strict"? (needed: "superstrict")
by Anonymous Monk on Jul 07, 2005 at 15:27 UTC
    While it's not at all clear that adding 'use strict' will magically turn up the bug (it's more likely that adding 'use strict' will fail to compile large sections of the code that don't contain the bug your looking for, and that the bug, if at all present, will persist, even if you make it up to stricts standards), adding 'use strict' is quite simple.

    Just copy the module(s) to a directory where you do have write permission, add 'use strict' in the copy, and put the directory in your PERL5LIB environment variable, then run your program. It should now pick up your copy (with 'use strict') instead of the original. And since 'use strict' only has compile time effects, all you need to do is run 'perl -c' on the (copy of the) module - don't even need to run your program.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others pondering the Monastery: (4)
As of 2024-04-16 18:45 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found