http://www.perlmonks.org?node_id=113695

Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

#!/usr/bin/perl -w use strict; my $foo_text .= $_ while (<DATA>); print "$foo_text\n"; __DATA__ foo wears foo shoes at the foo store.
produces the following error:
Use of uninitialized value at foo.pl line 4, <DATA> chunk 1 (#1)
Any one know what's going on here? Please, to aid in my learning/understanding of Perl a reason why this does not work and not a solution would be very much appreciated.

-Steven Woodard

Replies are listed 'Best First'.
Re: while modifier
by suaveant (Parson) on Sep 21, 2001 at 00:52 UTC
    you must first initialize $foo_text when using -w... try the following
    #!/usr/bin/perl -w use strict; my $foo_text = ''; $foo_text .= $_ while (<DATA>); print "$foo_text\n"; __DATA__ foo wears foo shoes at the foo store.

                    - Ant
                    - Some of my best work - Fish Dinner

      Another way to look at it would be that $foo_text is being re-declared every iteration. The declaration is scoped within the while loop. Yes, it is a statement modifier, but it's also a looping construct with its own scope. For example:
      my $x = 0; do { my $y = $x + 3; print "$x => $y\n"; $x++; } while ($x < 10);
      A little explanation - do (essentially) says to treat the following block as a single statement. Thus, you can use statement modifiers like post-whiles and post-foreachs. Now, $y is very obviously scoped within the confines of the while-loop. It's the same concept for while-modifiers.

      ------
      We are the carpenters and bricklayers of the Information Age.

      Don't go borrowing trouble. For programmers, this means Worry only about what you need to implement.

        Hi Dragonchild, actually this isn't quite right

        Yes, it is a statement modifier, but it's also a looping construct with its own scope.

        In fact modifiers of all kinds do not have their own scope. They execute in the scope of their enclosing block. This can be seen by my $x=1 if $y;$x++; where usage of the the $x after the if does not raise an exception.

        The reason it seems like they do when you use the do BLOCK pseudo-function is because in this case the block itself has its own scope. This is illustrated by the code below where the only variable usage that throws use strict; is the one declared inside of a do block.

        Another interesting point with the do usage is that the block gets executed an extra time, ie before the first evaluation of the conditional. This can be seen by the output line Do's pre-evaluation:DO{}while

        The compound statement forms of the modifiers are different in that they have their own scopes and scoping rules (for instance the for my $i (0..10) {} where the my's scope is actually the contents of the block.

        use strict; use warnings; use Tie::Cycle; tie my $cycle, 'Tie::Cycle', [ 1..3,0,reverse (1..3),0 ]; $\=":stmt while\n"; print my $statement=$_ while ($_=$cycle)>0; print defined($statement) ? "Defined" : "Notdefined"; $_="Do's pre-evaluation"; $\=":do{}while\n"; do { print my $do = $_ } while ($_=$cycle)>0; eval 'print defined($do) ? "Defined" : "Notdefined";'; print $@ if $@; $\=":stmt while 0\n"; print my $while="Test" while 0; print defined($while) ? "Defined" : "Notdefined"; $\=":stmt if\n"; print my $if="Test" if 0; print defined($if) ? "Defined" : "Notdefined"; $\=":stmt for\n"; print my $for=$_ for 0; print defined($for) ? "Defined" : "Notdefined"; __DATA__ 1:stmt while 2:stmt while 3:stmt while Notdefined:stmt while Do's pre-evaluation:do{}while 3:do{}while 2:do{}while 1:do{}while Global symbol "$do" requires explicit package name at (eval 1) line 1. :do{}while Notdefined:stmt while 0 Notdefined:stmt if 0:stmt for Notdefined:stmt for
        Notice that in the non do {} simple statement form, even when the condition is 0 and one might expect Perl to optimize it away the variable is created in the outside scope.

        Yves
        --
        You are not ready to use symrefs unless you already know why they are bad. -- tadmc (CLPM)

      my $foo_text; # this also works
      $foo_text is not being initialized to $_ ?

      I thought
      my $foo_text .= $_ while (<DATA>);
      was the same as a declaration/initialization statement
      my $foo_text = "text";
        Well, the first time it is undef, so it is undef .= $_... every time after that it has a value... it is a warning not an error.

                        - Ant
                        - Some of my best work - Fish Dinner

Re: while modifier
by stefp (Vicar) on Sep 21, 2001 at 01:27 UTC
    I don't think that while as a modifier can set $_.
    nope the problem is not there. the following line works as expected
     perl -e 'print $_ while <>'

    The problem must be with peculiarities of lexical declared with a modifier in the same statement.

    Anyway you could write:

    #!/usr/bin/perl -w use strict; my $foo_text; while ( <DATA> ) { $foo_text .= $_; } print "$foo_text\n"; __DATA__ foo wears foo shoes at the foo store
    or
    #!/usr/bin/perl -w use strict; my $foo_text; { local $/; undef $/; # see perlvar $foot_text = <DATA>; # slurps contents after __DATA_ } print "$foo_text\n"; __DATA__ foo wears foo shoes at the foo store

    -- stefp