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

Newbie programmer here, still learing Perl and programming in general. I am having some trouble with programming styles. There are certain things I am doing that, although the program is working as expected, seem to be a little unconventional. As I have no programming experience at all I am unsure if I am going about things the right way. For example:
I have been working on my first real application and have 2 pm file which contain things like connection information, functions and variable message strings. In one of these files I have a function &ParseString. In here I pass a string from another Perl script and parse it. But then, depending on what results are in the string I am setting global variables e.g:
if(substr($string64[$count],0,2) eq "MY") {our $message_64 = substr($s +tring64[$count],2);
Then, when &ParseString returns the result (back in the original Perl sctipt) I use the $message_64 string in an if clause etc.
I suppose what I am wondering about is: is it correct to assign a global variable like that, in a funtion, and then use it elsewhere? Or is it better practise to define it first somewhere, then change it later etc.?
Sorry for the newbie question, but like I said, I am new to the whole programming game!

Replies are listed 'Best First'.
Re: More than one way......
by ELISHEVA (Prior) on Jan 31, 2011 at 20:38 UTC

    What is correct with global variables really depends on the larger picture of what you are trying to do. Generally you want to try as much as possible to return values rather than set global variables. Perl lets you return lists of variables so you aren't limited to a single return value.

    sub myFunc { return (1,2,3); } my @aReturnValues = myFunc();

    Second best is passing in an array or reference as a parameter and stuffing generated values into the array or hash parameter. Although this isn't as easy to maintain as a return value, a parameter at least keeps the data and the thing that changes it closely related. As long as you document that the parameter will be modified, you shouldn't have problems from this. But keep in mind, it is easy to forget to read documentation and also not so easy to keep documentation and code in sync. A return value is better.

    The only read/write things that should go into global variables are configuration data that your whole program needs. If possible these should be gathered into larger data structures, e.g. a configuration hash or an application object. You should try to keep the number of read/write global variables very small. You should also carefully limit the functions that can change the global data and give the setter functions names that are easy to search for. If you don't, your code will become hard to maintain because you won't be able to keep track of what functions change which variables.

    A final closing question: do you have lots of variables ending in $stringN or $messageN where N is some number? If so, perhaps you should consider putting them into an array of arrays (see perldsc). They would be much easier to keep track of and work with that way:

    my @strings; my @messages; #process first 65 strings # loop through the numbers 0 thru 64 inclusive for my $i (0..64) { if(substr($strings[$i][$count],0,2) eq "MY") { $messages[$i] = substr($strings[$i][$count],2); } }
Re: More than one way......
by locked_user sundialsvc4 (Abbot) on Jan 31, 2011 at 21:20 UTC

    For whatever it may be worth ... when any project that I am working with starts to grow to encompass “multiple .PM files,” I try to start thinking in terms of “Perl objects.”

    If I construct my “Perl module” in terms of “it creates and defines a Perl object,” I know that I will get a whole lot of advantages, all at once ...

    • I have “a very easy means to get my hands on a very convenient handle” (namely, the object instance...) which gives me simultaneous access both to operative code and an associated, per-instance, block of data.   Every sub that I define now becomes “a method of an object,” which will automagically be given a reference to that object-instance as its first parameter.   This gives tremendous flexibility with regard to how you manage storage, and it also greatly reduces the coupling, or unwanted interference, between the various modules.
    • I virtually eliminate the need to mess with “globals,” which of course are probably (IMHO) the single biggest source of “coupling.”   In this scenario, every object has its own private play-pen.   From a purely pragmatic, bug-reducing perspective, that is huge.
    • I can coin just as many instances of a particular object as I want, and every one of them will be distinct.