Beefy Boxes and Bandwidth Generously Provided by pair Networks
Just another Perl shrine

Re: Are global variables "bad"?

by samtregar (Abbot)
on Apr 21, 2009 at 16:32 UTC ( [id://759048] : note . print w/replies, xml ) Need Help??

in reply to Are global variables "bad"?

What you're looking for is called a "singleton" - an object which naturally has a single instantiation which is shared by everyone that needs it. This is common for DBI handles for example. You might take a look at Class::Singleton for a tiny bit of implementation help but personally I'd just code the interface myself.

As to whether it's "bad" - no, but it does come with some danger. In the case of DBI handles the fact that they're often shared by disparate modules can make agreeing on DBI options hard - one part needs a particular RootClass, another requires RaiseError to be off, etc. It can cause "action at a distance" problems too.


Replies are listed 'Best First'.
Re^2: Are global variables "bad"?
by doom (Deacon) on Apr 21, 2009 at 22:57 UTC
    Maybe I'm missing something, but how does wrapping a $dbh handle in a singleton avoid action at a distance? If you've got code flipping AutoCommit on and off don't you have the same potential problems?
      It doesn't. I was mentioning it as a problem inherent to singletons.


Re^2: Are global variables "bad"?
by eric256 (Parson) on Apr 21, 2009 at 18:40 UTC

    I like the singleton idea. I've used it for DBI connections and config files and it makes it easy to have global behaviour without the downsides of having global variables. At least thats how I see it.

    Eric Hodges

      After having worked with code that had made extensive use of Singletons, I think I would have to disagree. I'd say that Singletons have all of the advantages of global variables with all of the disadvantages of globals.

      The only advantage I've seen is in grouping a set of variables (or behavior) into one Singleton object, instead of scattering them around. But, you can do that without Singletons, as well.

      I try to avoid Singletons, because they've been the source of lots of trouble for me.

      On the other hand, in a standalone script global variables can often simplify the code. The practice does tend to put an upper limit on how much the code can safely do.

      G. Wade
Re^2: Are global variables "bad"?
by jpearl (Scribe) on Apr 21, 2009 at 17:14 UTC
    I have read a bit about singletons, though to be honest my only exposure was basically checking out globals and why they might be bad. For instance when reading this there was a link to this. Kind of a programming culture of fear :-P

    Thank you for the links, I'll definitely check out Class::Singleton Though you are probably right on just creating my own solution.

      I don't actually see any particular reason to use a singleton in this case: You are parsing a file, and want to store it someplace. There is no particular reason (from what you've said) why parsing a different file, or even reparsing the file should be prevented. (Besides the fact of memory useage/speed, which to me isn't a reason for a singleton, just a reason to keep using the same object.)

      Basically, it's extra complexity to prevent future uses. I don't see why either would be something you want.

        Agreed. The singleton is, when you get right down to it, really just a hack to add global variables to Java in an "object-oriented" way, dignified with a fancy name and notable mainly for being the design pattern people are by far the most likely to be able to remember off the tops of their heads.

        There are very few cases where singletons add value in a language like Perl. If your code is worth the effort of moving away from global variables, it's worth the effort of generalising completely (for example, allowing people to have multiple data sets open at once).

      If one expects the file format to change over time to accommodate new research data or evolving use cases, using class methods or a singleton object would be a good idea. OOP architecture makes it much easier to support multiple file formats in parallel.

      Without objects, you have three options for supporting two file formats:

      1. Define a second set of parsing functions with ugly names like parse_blah2. Then go all over your existing code inserting if...else statements to select the right set of functions.
      2. Define the functions for format II in a new package. Now go back to the consumer code and replace all of your calls to parse_XXX(...) with eval("${sParserPackage}::parse_XXX").
      3. Define a second set of parsing functions and create a dispatch table. Now go all over your code and replace the direct calls to parsing functions with calls to dispatch table members. You've gotten rid of the bulky if...else and eval(...) statements, but you are still making massive code changes. You've also lost some debugging ease since dispatch table methods are going to show up in standard debugging tools as anonymous code references rather than named functions. You simply aren't going to get error messages like Can't locate object method "parse_blah" via package "MyModules::Parse2" Instead you'll get an obscure message about Use of uninitialized value in subroutine entry

      Or you could define your parsing process in an object. The only change that would need to be made in your program would be a small bit of code to check the version number and retrieve the correct parser. Any other code using the parser methods would stay the same since it only cares that statements like $oFoo->parse_blah and $sParserClass->parse_blah() behave in a predictable fashion.

      Classes and objects, even singleton objects, give one the ability to override and redefine methods without changing a byte of consumer code.

      Best, beth

      Explanatory note: in Perl, a class method is just a package subroutine whose first parameter is a class name. Calling Foo->fribilate(...) tells Perl to pass "Foo" as the first parameter and to allow overloading. It also lets one use a variable for the package name. ${somevar}::fribilate(...) generates complaints about bare words where operators were expected. That is why we had to use eval(...) in non-object option 2.