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

There are a few excellent Perl programmers who don't care for strict. However, most seem prefer it because it prevents silly tyops (sic) and all manner of poor programming constructs. There are many reasons why you don't want to use strict, but from what I can see from the average Perl programmer's work, these situations are the exception rather than the rule. One problem with failing to use strict stems from all variables being global. The larger the program, the more likely problems will arise from misspelled globals, globals being munged in unexpected places or a programmer simply forgetting what the globals are for.

Much of the problem with globals can be solved merely with the vars pragma.

#!/usr/bin/perl $foo = 'bar'; $baz = 'qux';

The above code will not run under strict. You have a couple of options. One, that I've seen used far too often is prepending the package name.

#!/usr/bin/perl use strict; $main::foo = 'bar'; $main::baz = 'qux';

While having use strict; at the top of your code looks nice, one of the finest benefits of strict is lost: prevention of typos.

#!/usr/bin/perl use strict; $main::foo = 'bar'; $main::baz = 'qux'; $main::foo .= $main::bza;

The vars pragma will catch this:

#!/usr/bin/perl use strict; use vars qw/ $foo $baz /; $foo = 'bar'; $baz = 'qux'; $foo .= $bza;

Now we get a compile time warning that $bza requires an explicit package name. This doesn't solve all of the problems, but it's a nice start.

But what do we do about globals declared in other packages? From what I can tell, you can't use our or vars for globals in another package. Personally, I wouldn't care for that if I could do that because I think it obscures what's going on.

If it's an object-oriented module, we could subclass it and write get and set methods for the globals. That's what I did with CGI::Safe for $CGI::DISABLE_UPLOADS and $CGI::POST_MAX (to be fair, I only wrote a set method and that was at Lincoln Stein's request). This is a nice, clean method, but it doesn't work if you can't inherit.

Another way of dealing with that is to tie a variable to the global and just use the new variable. This is a fairly universal solution and doesn't have any expectation that the global(s) in question are in an OO module. However, like the above solution, it seems like a lot of work for minimal gain.

Neither of these solutions seem practical unless there are a lot of globals to worry about. Is there an easy solution to this? Is there too little return on the work invested? Naturally, with proper programming, this is not a problem that will crop up often, but I'm dealing with a lot of legacy code here that we're slowly working the kinks out of and I think a clean solution would be nice.

Cheers,
Ovid

Join the Perlmonks Setiathome Group or just click on the the link and check out our stats.

Replies are listed 'Best First'.
Re: Using strict with globals
by suaveant (Parson) on Jan 04, 2002 at 00:31 UTC
    What about exporting the global? I mean, it's by no means ideal, but wouldn't that work?

                    - Ant
                    - Some of my best work - (1 2 3)

Re: Using strict with globals
by dragonchild (Archbishop) on Jan 04, 2002 at 00:51 UTC
    I believe you asked about this a few months back. How's the project going?

    What about placing all the globals into a separate module and exporting from there? That's what I did in a project I worked on for my previous employer and that worked out quite nicely.

    ------
    We are the carpenters and bricklayers of the Information Age.

    Don't go borrowing trouble. For programmers, this means Worry only about what you need to implement.

      dragonchild wrote:

      I believe you asked about this a few months back. How's the project going?

      Did I? Sheesh. Early Alzheimer's, I guess.

      I was pulled from that project to work on projects for which we're actually getting paid. We have an impending rewrite of the original project and my mind wanders back to the original problem without seeming to get anywhere. The code is such an absolute mess that finding clean solutions seems to be a problem. You and suaveant have both suggested a nice solution, but I don't know that it's always practical.

      Let's say we download a module from the CPAN, or have received from a vendor, that has periodic updates. If I don't want to keep reapplying a patch to those modules, I need another solution. I suppose I could write modules that grabs those globals and exports them into my namespace without necessarily requiring that I change the original code. I'd like to fix these programs one at a time without risking my breaking anything by adding code to all of the shared modules.

      If I have about 40 programs, this seems a bit better because I can convert everything one-by-one without worrying about who's working on what. The problem is that all of those 40 or so programs use globals in %main::. It doesn't matter what package these variables are declared in, they're usually, but not always, qualified as being in %main::. For those programs that don't use strict, a given global might be in main, in might be in that module's namespace.

      I suppose I'm just looking at this new project with dread and am ranting here. I've been trying to find a quick and easy solution to a mess of code and I need to just knuckle down and start digging in. I have to just face the fact that there is no magic bullet that will kill this beast. No point in continuing this thread :(

      Cheers,
      Ovid

      Join the Perlmonks Setiathome Group or just click on the the link and check out our stats.

        You will be happy to know that you're wrong. In fact, that they all refer to $main::foo is going to be a saving grace for you. :-)

        Consider this:

        1. You create a module called Globals.pm
        2. It inherits from Exporter
        3. You do a global find for all references to $main::foo
        4. You replace all those with references to the exported variable $foo
        5. You run the program and it breaks somewhere during compilation (cause you wisely turned on strict).
        6. You track those last buggers down within an hour or two.
        Then, once they're all in one module, you can start the refactoring with an idea of how bad the situation really is. It could be as simple as under 100 variables or it could be 1000's. You simply don't know right now.

        As for modules ... CPAN modules don't use %main:: and vendor-supplied modules don't use %main::. (Well, if the latter do, then the vendor should go out of business, proving my point. *grins*) So, you shouldn't have to patch over every time for these. In-house modules ... well, shoot the author and you're good. :-)

        ------
        We are the carpenters and bricklayers of the Information Age.

        Don't go borrowing trouble. For programmers, this means Worry only about what you need to implement.

Re: Using strict with globals
by jlongino (Parson) on Jan 04, 2002 at 02:14 UTC
    You point out an interesting aspect of strict & vars I didn't realize:

    . . . one of the finest benefits of strict is lost: prevention of typos.

    #!/usr/bin/perl use strict; $main::foo = 'bar'; $main::baz = 'qux'; $main::foo .= $main::bza;
    I hate to nitpick, but your next sentence:

    The vars pragma will catch this:

    Did you mean strict will catch this? Apologies if I'm mistaken (since I don't know much about vars), if I'm wrong could you expand on that point, as I feel I need to understand why.

    Good post!

    --Jim

    Update: Ah yes, the synergy of the two makes more sense. Thanks, Ovid.

      Nitpick away! I don't mind at all :) I should have said Using strict and vars together will catch this.

      As for the vars pragma, it merely allows you to use globals in your program without the need to specify the current package name. Thus, strict catches errors in global misspellings that it wouldn't catch if you use fully-qualified variable names -- e.g. $main::foo can be misspelled as $main::Foo and strict doesn't care one bit, though you may have trouble finding the error in your code.

      Further elaboration on nitpicking. I've said it before and I'll say it again: let me know when I'm being a moron! I'm a PerlSaint in name only. I often wind up with weird conceptual blocks, or sometimes make downright stupid mistakes (like reposting nodes - grr!!!), so I want to hear the nitpicking. Like most everyone else here, I want to learn, and learn, and learn...

      Cheers,
      Ovid

      Join the Perlmonks Setiathome Group or just click on the the link and check out our stats.