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'

Attachment: signature.asc
Description: Digital signature

Reply via email to