in reply to Re^4: Access a global variable from a subroutine when used as "for" iterator
in thread Access a global variable from a subroutine when used as "for" iterator

The full story is that I'm parsing some documents in Excel spreadsheets and I just wanted to simplify the expresions, so the list c('A1'),c('A'),c('B') just means that the value at the constant cell A1 is followed by the values of columns A and B at the "current row" in the details area, without having to include the iterator variable as in c('A',1),c('A',$i),c('B',$i) (which is also supported). The problem was that I always got the values at a fixed row based on the previous value of the iterator variable when it was not explicit as an argument, either as c('A',$i) or c("A$i").

Of course, there are also some helper functions to get formated values. For instance, d('A',1) internally calls c(@_) and returns a date properly formatted (and not an epoch number). As there could be many levels of nested functions, I decided to use a global variable and avoid the optional parameter.

Now I know that for over lists does a special treatment on the iterator variable, probably because of a perl 4 inheritance, and I should use a C-like for or a while construct when using a global variable as iterator from subroutines called from the loops, but for the moment, I'm using this construct:

my $row = 0; for (2..10) { $row = $_; gen(d('A1'), c('A'), c('B'), t('C'), c('D')+c('E')); }

I think it is much more clear and easy to maintain when the spreadsheet changes than:

my $row = 0; for ($row = 2, $row <= 10; $row++) { gen(d('A',1), c('A',$row), c('B',$row), t('C',$row), c('D',$row)+c(' +E',$row)); }

Now I see that if I had declared the global variable without an initial value of zero, an error should have been raised and saved many hours trying to identify why I got wrong values from the spreadsheet. >:-(

Replies are listed 'Best First'.
Re^6: Access a global variable from a subroutine when used as "for" iterator
by LanX (Saint) on Dec 21, 2023 at 20:51 UTC
    OK, there are some ambiguities in your description, so I'm not sure I understand your intentions in total.

    Your perception of my as global is also wrong !

    In your case I'd suggest using package vars, because you can easily access the vars after exporting the subs.

    The following demo is explicitly using two packages to fake an import situation. you can simplify it in a one-file-for-all situation. But it should help you grasp the differences between different var types.

    use v5.14; use warnings; { package _csv; # some package name our $row; our $col; sub c { my $c = shift // $col // die "col undefined"; my $r = shift // $row // die "row undefined"; say "c:$c r:$r"; } say "--- inside same scope"; for $row (1..3) { c("A"); } } package main; BEGIN { *c = \&_csv::c } # fake import for demo say "--- one default"; for $_csv::row (1..3) { c("B"); } say "--- two defaults"; for $_csv::col ("C".."D") { for $_csv::row (4..5) { c(); } } say "--- explicit local "; { local $_csv::row = 10; c("E"); c("F"); } say "--- defaults were localized inside loop"; c("G");

    perl ~/perl/cell_dsl.pl --- inside same scope c:A r:1 c:A r:2 c:A r:3 --- one default c:B r:1 c:B r:2 c:B r:3 --- two defaults c:C r:4 c:C r:5 c:D r:4 c:D r:5 --- explicit local c:E r:10 c:F r:10 --- defaults were localized inside loop row undefined at /home/lanx/perl/cell_dsl.pl line 12.

    But frankly, if I were you, I'd rather define multiple subs with special explicit behavior instead of overloading one with implicit DWIM.

    Or at least, use them both together and let the implicit one call the explicit ones.

    Cheers Rolf
    (addicted to the Perl Programming Language :)
    see Wikisyntax for the Monastery

      Your perception of my as global is also wrong !
      Only special variables like $_, $a, $" are really global (they always belong to the main:: namespace).

      It is clear that I don't know how to call a variable that could be accessed from everywhere within the script's (main?) scope. I'm not sure if "public" is a better name. There is no intention to share it with modules in order to use "our", at least at this stage of the development.

      (maybe I should start writing a tutorial instead of preaching again and again ;)

      That could be very useful for people like me, if that tutorial is well indexed by search engines (or the Super Search). :-D

        Perl has two different kinds of variables, private variables declared with my and package variables (usually) declared with our

        • a lexical scope in Perl is anything from declaration till end of enclosing { block }
        • the biggest possible lexical scope outside a block is the file, aka file-scope
        • lexical ( i.e. "as you read" the static code ) is opposed to "dynamic" (i.e. run-time effects)
        • main:: and other package s are namespaces not scopes, think of them as hashes of variables and functions
        • my variables do not belong to namespaces, our vars do
        • global means accessible everywhere, all namespaces including vars and subs are global as long as you use the *fully::qualified::name
        • special variables always belong to main::

        for sources, e.g. "Scoping" see

        Update

        And an excellent overview can be found in

        Cheers Rolf
        (addicted to the Perl Programming Language :)
        see Wikisyntax for the Monastery