2

I have a set of 3 or 4 separate Perl scripts that used to be part of a simple pipeline, but I am now trying to combine them in a single script for easier use (for now without subroutine functions). The thing is that several variables with the same name are defined in the different scripts. The workaround I found was to give different names to those variables, but it can start to become messy and probably it is not the correct way of doing so. I know the concept of global and local variables but I do not quite understand how do they exactly work.

Are there any rules of thumb for dealing with this sort of variables? Do you know any good documentation that can shed some light on variable-scope or have any advise on this?

Thanks.

EDITED: I already use "use warnings; use strict;" and declare variables with "my". The question might actually be more related to the definition of scoping blocks and how to get them to be independent from each other...

PedroA
  • 1,803
  • 4
  • 27
  • 50
  • 2
    You need to give an example of what you are faced with. But it is important that you understand what you are doing rather than relying on *rules of thumb*. What is it that you *"do not quite understand"* about variable scoping? You should *always* `use strict` and use lexical variables throughout by declaring them with `my`. You can forget about any other sort of variable unless you are doing something esoteric. It sounds like there's some refactoring that needs to be done as well: you shouldn't just concatenate all the programs together without understanding all of them individually. – Borodin Dec 15 '13 at 01:25

2 Answers2

5

The rule of thumb is to put your code in subroutines, each of them focused on a simple, well-defined part of the larger process. From this one decision flow many virtuous outcomes, including a natural solution to the variable scoping problem you asked about.

sub foo {
    my $x = 99;
    ...
}

sub bar {
    my $x = 1234;  # Won't interfere with foo's $x.
    ...
}

If, for some reason, you really don't want to do that, you can wrap each section of the code in scoping blocks, and make sure you declare all variables with my (you should be doing the latter nearly always as a matter of common practice):

{
    my $x = 99;
    ...
}

{
    my $x = 1234;  # Won't interfere with the other $x.
    ...
}
FMc
  • 41,963
  • 13
  • 79
  • 132
  • I believe that's a very bad rule of thumb. Making a subroutine out of several scripts and putting them into one file is unlikely to have a good result. I see too many Perl programs that look like `sub main { ... }; main();` and this suggestion is even worse. Perl subroutines are mostly useful for [*abstraction*](http://en.wikipedia.org/wiki/Abstraction_%28computer_science%29), and arbitrarily chopping up code is rarely a good idea. – Borodin Dec 15 '13 at 01:37
  • 3
    @Borodin You are imposing a strange interpretation on my advice: "put your code in subroutines, each of them focused on a simple, well-defined part of the larger process" -- in other words, basic problem decomposition and modular design. Not sure why you would equate that with "arbitrarily chopping up code", which (of course) would be a bad idea. – FMc Dec 15 '13 at 01:50
  • 5
    @Borodin: if the code started out in separate scripts, it isn't an arbitrary separation. – ysth Dec 15 '13 at 02:12
  • @FMc: If you saying that each of the constituent programs should form a subroutine in the compilation, then I think that's highly unlikely to lead to a well-constructed piece of code. If you're making the general recommendation to "use subroutines" then I don't think you've said anything very useful. – Borodin Dec 15 '13 at 03:18
  • @ysth: The divisions are arbitrary in the context of the new program. A good place to separate a pipeline of processes is very unlikely to be a good place to divide a program into subroutines. A pipeline requires that each program serializes its output, and that is very much *not* a a useful model within a program. – Borodin Dec 15 '13 at 03:24
  • @FMc this was what I would like to know, how do variables with the same name won't interfere with each other. Are while or foreach loops also considered independent scoping blocks? – PedroA Dec 15 '13 at 18:18
  • 1
    @PedroA Yes, `while` and `for` loops do create independent scoping blocks, just as subroutines do -- but only for lexically scoped variables declared with `my` (that's the crucial requirement). If you use package-scoped variables (an entirely separate topic), the lexical scoping boundaries do not apply. Regarding your *how* question ... well, that's an implementation question for the Perl language itself (or really for any programming language that needs to implement lexical scoping behavior). – FMc Dec 15 '13 at 19:36
5

You are likely getting into trouble because of your use of global variables (which actually likely exist in package main). You should try to avoid the use of global variables.

And to do so, you should become familiar with the meaning of variable scope. Although somewhat dated, Coping with Scoping offers a good introduction to this topic. Also see this answer and the others to the question How to properly use Global variables in perl. (Short Answer: avoid them to the degree possible.)

The principle of variable scope and limiting use of global variables actually applies to nearly all programming languages. You should get in the habit of declaring variables as close as possible to the point where you are actually using them.

And finally, to save yourself from a lot of headaches, get in the habit of:

  • including use strict; and use warnings; at the top every Perl source file, and
  • declaring variables with my within each of your sub's (to limit the scope of those variables to the sub).

(See this PerlMonks article for more on this recommendation.)

I refer to this practice as "Perl programming with your seat belt on." :-)

Community
  • 1
  • 1
DavidRR
  • 18,291
  • 25
  • 109
  • 191
  • Great articles you have pointed out, I was also looking for this. Many thanks. – PedroA Dec 15 '13 at 18:23
  • Found also this post that can be useful for the scope of this question: http://stackoverflow.com/questions/19100106/local-and-global-variables-in-perl – PedroA Dec 15 '13 at 22:09