On Thu, Jun 27, 2013 at 12:58:38PM +0200, lee wrote: > The subroutine is never called before $counter is declared, so > it is always available to the subroutine. There should be an > error only for instances when the subroutine is called before > $counter is declared.
Much like in C or C++ (and many other languages), the variable does not exist until its declaration is seen. If you want that variable to be visible to the above subroutine then the solution is simple: move the variable declaration before the subroutine declaration. #!/usr/bin/perl use strict; use warnings; my $counter = 0; sub test { # This can see the above declaration. It wouldn't be able to # see the one below. print $counter, "\n"; } #my $counter = 0; while($counter < 5) { test(); $counter++; } __END__ The whole point of lexical variables (those created with my) is to limit their scope. It's more meaningful to be able to limit the scope even within the file then not. It's pretty typical for variables at the file scope to be declared at the top of the file anyway. Keeping them all close together makes it easier to find them and make sense of them. > I do not want to: > > > + define the subroutines after the program A common practice is to wrap the core of the program into a subroutine, much like is required by C or C++. For example, you might write a main subroutine and invoke that from the global scope. I often do it this way, particularly when the program is non-trivial. #!/usr/bin/perl exit(main(@ARGV)); sub main { my @args = @_; # ... return 0; } > + carry the needed variables all over the place as parameters > to every function that might need it That is actually an ideal world to live in. Sure, it requires a bit of extra typing and a bit of forethought, but it forces you to design the software better (or live with the consequences). You end up needing to plan what information needs to flow to which parts of the system. Also, when you find yourself passing things to parts of the program that you don't think need them you can recognize it as a design flaw and rethink things. With globally accessible data you end up not being able to see these design flaws and it results in bad code. Most people think that this is harder to do and requires too much effort, but I think that you'll find that it is easier in the long run. See the following video for an excellent explanation of why global state is bad in all forms: http://youtu.be/-FRm3VPhseI. I hope I got that URL right. :) The title should be, «The Clean Code Talks - "Global State and Singletons"». The discussion is Java-centric, but it applies to all forms of software equally. > + declare the variables on top of the program because that > increases their scope too much You don't seem to be making sense to me. You seem to be annoyed that your variable isn't accessible to a previously defined subroutine, but you simulatenously don't want to make the variable accessible to the previously defined subroutine. It seems like you just want variables to magically exist where you want them and magically not exist where you don't. It's up to you to write the code and organize where each variable can be accessed from. I would argue that file-scoped variables are bad practice and should be avoided in favor of lexicals scoped inside of subroutines that get passed around. Sometimes it is acceptable to use file-scoped variables though, particularly when the program is short and simple. > In the particular application I have this problem with, I could > create a hash holding all the information that might be needed > by subroutines and carry that all over the place in their > parameters. In C, I would create a structure containing the > needed information and simply carry a pointer to the structure. > That would be much more efficient than handing over a hash, > effectively copying all the data the hash may contain every > time. > > How do you do that in perl? Storing the entire program state in a structure and passing a pointer/reference to it to every subroutine is no different than using global variables. You've just wrapped the wolf in wool. A better approach would be to organize related data into structures or objects and pass those only to subroutines that really deserve to have them (in other words, pass small parts of the program state instead of the whole thing; when possible pass copies or immutable objects so the data cannot be accidentally modified). You certainly can group data together (for example, the attributes of an employee) rather than passing each piece separately. However, just throwing everything into a single structure accomplishes nothing. That said, you can take references to data in Perl and pass those instead. The idea is very similar to pointers in C or references in C++. You could do this to avoid the overhead of copying the structure each time you pass it. See `perldoc perlref' for a start on how references work. Regards, -- Brandon McCaig <bamcc...@gmail.com> <bamcc...@castopulence.org> Castopulence Software <https://www.castopulence.org/> Blog <http://www.bamccaig.com/> perl -E '$_=q{V zrna gur orfg jvgu jung V fnl. }. q{Vg qbrfa'\''g nyjnlf fbhaq gung jnl.}; tr/A-Ma-mN-Zn-z/N-Zn-zA-Ma-m/;say'
signature.asc
Description: Digital signature