Beefy Boxes and Bandwidth Generously Provided by pair Networks
go ahead... be a heretic

Avoiding Global Vars

by Melly (Hermit)
on Sep 22, 2009 at 16:05 UTC ( #796743=perlquestion: print w/replies, xml ) Need Help??
Melly has asked for the wisdom of the Perl Monks concerning the following question:

Hi Monkees,

I like using global vars when they are genuinely global, but I often end up with unintended global vars, and they bug me.

I was wondering what tricks you use to avoid them or, alternatively, how I might cure my anal retentiveness...

For example, how would I avoid the global $vrx in the following simplified example(yet still allow a persistent value)?

use strict; my $vrx; while(<DATA>){ $vrx = $1 if /^10*(\d*)/; print $vrx . $1 . "\n" if /^20*(.*)/; } __DATA__ 1000100 2001foo 2002bar 300badline 2003hello 1000200 2001bish 2002bash
map{$a=1-$_/10;map{$d=$a;$e=$b=$_/20-2;map{($d,$e)=(2*$d*$e+$a,$e**2 -$d**2+$b);$c=$d**2+$e**2>4?$d=8:_}1..50;print$c}0..59;print$/}0..20
Tom Melly, pm (at) cursingmaggot (stop) co (stop) uk

Replies are listed 'Best First'.
Re: Avoiding Global Vars
by Tanktalus (Canon) on Sep 22, 2009 at 17:39 UTC

    Seriously, what global $vrx?

    First, it's "my". It's lexical. So, perhaps it's lexical to the whole file, but that's not the same as global. Not entirely.

    Second, your example code is merely a long version of a one-liner. I realise you're trying to simplify to show your point, but I'm not sure where the point is. If it's something to do with a simple script that doesn't even have need of sub's, then I think you're missing the point of the "GLOBALS ARE EV1L!!!!111" camp. The point of this camp is that action-at-a-distance is unmaintainable. And I agree. Your $vrx variable has no significant distance. It covers 4 lines, that's a very narrow scope for a variable.

    Third, as a one-liner, your example could be rewritten just slightly to put all your code into a sub main { ... }, and then a single call to main() would call it, without any functional or even semantic change. Since this is perl, and TMTOWTDI applies, we just ignore the main() routine that other languages force on you, and allow you to just put it all out in the open. That doesn't make your variables global.

    What makes a variable global is the intention for, and actual use of, given variables in various scopes. That is, if you have $vrx and it's used by sub foo, and sub bar, then it's an evil global variable. Your example doesn't show that.

    Your anal retentiveness is fine. It's just not anal enough: you're applying it to anything and everything, instead of anally selecting which variables are actually global. :-P

Re: Avoiding Global Vars
by bv (Friar) on Sep 22, 2009 at 16:17 UTC

    You could wrap it in a block:

    { my $max; while(<>) { $max = ($max >= $_ ? $max : $_); print "Max seen: $max\n"; } }

    Or use a state variable (Perl 5.10 or 6 only, I believe)

    print pack("A25",pack("V*",map{1919242272+$_}(34481450,-49737472,6228,0,-285028276,6979,-1380265972)))
Re: Avoiding Global Vars
by Porculus (Hermit) on Sep 22, 2009 at 22:24 UTC

    <java>Simple: use a singleton! Then you can bask in the pleasure of knowing that your code is Object-Oriented, and uses a Genuine GoF Design Pattern, and contains a bunch of unnecessary complexity that does absolutely nothing to improve encapsulation and just makes it more fragile to maintain.</java>

    Seriously, worrying about global variables is not the Perl way. If you want to improve your code, don't do it by running down a checklist of "bad" constructs -- do it by reading the code itself and asking which bits could be easier to understand. It is different for every bit of code. I've certainly seen programs rendered treacherous by the abuse of global state, but they were nothing to some of the spaghetti nightmares I've encountered in languages that don't even have global variables.

      Thanks all - and apols for the wrong terminology (i.e. global <> "my", just because "my" outside of a block is lexical to the whole file)

      One point to clarify is that the reason it bugs me, apart from wanting vars to only live within the scope where they are needed, is that I might re-use the name $vrx later, with possible side-effects.

      bv's suggestion (use a bare-block) seems the most economical and least confusing, but I will also bear in mind that I shouldn't sweat the details....

      map{$a=1-$_/10;map{$d=$a;$e=$b=$_/20-2;map{($d,$e)=(2*$d*$e+$a,$e**2 -$d**2+$b);$c=$d**2+$e**2>4?$d=8:_}1..50;print$c}0..59;print$/}0..20
      Tom Melly, pm (at) cursingmaggot (stop) co (stop) uk
        One point to clarify is that the reason it bugs me, apart from wanting vars to only live within the scope where they are needed, is that I might re-use the name $vrx later, with possible side-effects.

        If you use warnings, you'll get a warning if you redefine a new my $vrx in the same scope as the first. If it's not in the same scope, then it'll be a different $vrx, so there should be little to no chance of unintended side-effects.

        Of course, the better way to deal with it would be to use a more meaningful/distinctive name so that it's unlikely that you'll have cause to re-use the name...

        I find that if I want to use a bare block, it's either unnecessary or I should be using a new sub instead.
Re: Avoiding Global Vars
by Bloodnok (Vicar) on Sep 22, 2009 at 16:56 UTC
    Your specific example doesn't reference $vrx outside the scope of the while loop, so there's no need to declare it globally - hence there's nothing to avoid ... esp. if the variable is declared inside the loop.

    That being said, I'm a big fan of 'horses for courses' so, if a global is needed, then by all means use one and as recommended in PBP, ensure the name is capitalized.

    Problems arise thro' the over extensive/unthinking use of globals.

    A user level that continues to overstate my experience :-))

      But if I only declare $vrx within the while loop, then I will lose its value when I need to print it...

      Try it with the data I supplied, and look at the different output...

      1001foo 1002bar 1003hello 2001bish 2002bash


      1foo 2bar 3hello 1bish 2bash

      So, it's not a question of whether I reference it outside the loop - rather the opposite, since if I did reference it elsewhere, then it would be global, and it wouldn't bug me... if you see what I mean.

      map{$a=1-$_/10;map{$d=$a;$e=$b=$_/20-2;map{($d,$e)=(2*$d*$e+$a,$e**2 -$d**2+$b);$c=$d**2+$e**2>4?$d=8:_}1..50;print$c}0..59;print$/}0..20
      Tom Melly, pm (at) cursingmaggot (stop) co (stop) uk

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://796743]
Approved by MidLifeXis
Front-paged by Tanktalus
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others making s'mores by the fire in the courtyard of the Monastery: (2)
As of 2018-02-19 02:47 GMT
Find Nodes?
    Voting Booth?
    When it is dark outside I am happiest to see ...

    Results (258 votes). Check out past polls.