On 27/06/2013 11:58, lee wrote:
Shlomi Fish <shlo...@shlomifish.org> writes:

lee <l...@yun.yagibdah.de> wrote:

the following example doesn't compile:

use strict;
use warnings;

sub test {
     print $counter . "\n";
}

my $counter = 0;
while($counter < 5) {
     test();
     $counter++;
}


It says "Global symbol "$counter" requires explicit package name ...".
When I put the subroutine after the 'while' loop, it works just fine, so
what's the problem?

The subroutine does not see the lexical $counter variable because it was
declared after its scope.

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.

For more information, see:

* http://www.plover.com/FAQs/Namespaces.html

Ok, so perl has a totally broken design with variables :(  What's the
solution to this problem?  I do not want to:


+ define the subroutines after the program

+ carry the needed variables all over the place as parameters to every
   function that might need it

+ declare the variables on top of the program because that increases
   their scope too much


Reading [1] would indicate that it is an extremely bad idea in perl to
have global (package) variables because they cannot be local to the
program that uses them because all programs are packages the variables
of which can be accessed from other packages.  You also cannot use a
package name and use that for variables like $Mypackage::counter because
in case you ever change the name of the package, you'll have to go
through all the code and adjust the names of such variables.  It
wouldn't really solve the problem, either, because the variables could
still be accessed from outside the program.  So now I don't want to have
global (package) variables, either.


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?

I don't think it's possible to satisfy your wishes Lee. You want a subroutine that's declared *before* a variable to have access to that variable, yet you don't want to "declare the variables on top of the program because that increases their scope too much".

Surely, giving a subroutine access to a variables that are yet to be declared also "increases their scope too much"?

It is certainly a bad idea to predeclare everything, but a Perl variable must be declared before all the code that accesses it. The usual way is to declare variables immediately before their first point of use (as in your sample code) and put subroutine definitions at the end of the program. Since you particularly object to putting subroutine declarations you should look at another language, although none come to mind that allow a variable to be accessed prior to its declaration.

There are other solutions depending on the program's control flow. In this case the variable should clearly be a parameter anyway, and the code should look like this

    use strict;
    use warnings;

    sub test {
      my ($val) = @_;
      print "$val\n";
    }

    for my $counter (0 .. 4) {
      test($counter);
    }

Your description of creating an aggregate data item and passing it everywhere sounds much like using a global variable to me, however it is quite possible. Something like this may help you

    use strict;
    use warnings;

    do_something({ title => 'TEST', value => 42 });

    sub do_something {
      my ($params) = @_;
      print $params->{title}, "\n";
      do_something_else($params) for 1 .. 3;
    }


    sub do_something_else {
      my ($params) = @_;
      print $params->{value}, "\n";
    }

HTH,

Rob










--
To unsubscribe, e-mail: beginners-unsubscr...@perl.org
For additional commands, e-mail: beginners-h...@perl.org
http://learn.perl.org/


Reply via email to