« first day (132 days earlier)      last day (2267 days later) » 

11:44 AM
@Zanna So, specifically, what I mean by how I suspect that the special syntax of the <> operator applying to readline and glob functionality, and the special behavior of while in checking if their return value is defined rather than checking if is true, goes back to the history of Perl using csh for globbing...
...is that Perl lets you read from (and write to) pipes with filehandles, and I suspect that either this was how Perl used csh for globbing, or that the developers wanted to make it so that it would behave as though it had been implemented that way.
6> open my $f, 'fortune | cowthink |';
$res[4] = 32514

7> while (<$f>) { print "***  $_" }
***   ________________________________________
***  ( Anyone who understands everything that )
***  ( comes out of fortune probably has a    )
***  ( problem                                )
***   ----------------------------------------
***          o   ^__^
***           o  (oo)\_______
***              (__)\       )\/\
***                  ||----w |
***                  ||     ||
$res[5] = ''

8> close $f;
 
@EliahKagan what's $res[0] = ''? while stopped because there was nothing left?
@EliahKagan oh hmm... what's going on there?
 
12:02 PM
Well, because <$f> is a filehandle read (it is itself syntactic sugar for readline $f), while (<$f>) has the special behavior of checking if the result of that filehandle read is defined, which is to say that it behaves similarly to while (defined <$f>). Though not relevant to your specific question, it would be very confusing if I didn't mention that, really, it is not syntactic sugar for that, because it is also assigning the value to $_.
So the specific while loop that while (<$f>) { print "*** $_" } causes to be used could almost be written like this (or maybe exactly, but I am not 100% sure on the specific scoping rules for $_ when it is implicitly assigned in a loop):
while (defined(my $_ = <$f>)) { print "*** $_" }
The last expression evaluated there, stopping to loop, is thus not <$f> or even my $_ = <$f>, but is defined(my $_ = <$f>). That expression returns false.
I am actually pretty totally sure my is not the kind of scoping that automatically assigned $_ uses.
It is closer to:
while (defined($_ = <$f>)) { print "*** $_" }
ek@Io:~$ perl -we 'open my $f, q{fortune | }; while (<$f>) { print; last } print "[$_]\n"'
Oh, the Slithery Dee, he crawled out of the sea.
[Oh, the Slithery Dee, he crawled out of the sea.
]
ek@Io:~$ perl -we 'open my $f, q{fortune | }; while (my $line = <$f>) { print $line; last } print "[$line]\n"'
Name "main::line" used only once: possible typo at -e line 1.
"You are old," said the youth, "and your jaws are too weak
Use of uninitialized value $line in concatenation (.) or string at -e line 1, <$f> line 1.
[]
It is actually exactly that. I know there are rules about how $_ gets reset when you from an inner nested loop that uses it implicitly to an outer nested loop that uses it implicitly, but they are apparently not implemented by giving $_ any special scoping. I will have to look into that. Anyway, the whole thing about the variable is not directly germane to your question.
(Or perhaps those rules don't apply to $_ in a while loop.)
Anyway, if you run perldoc perlop and go down to the I/O Operators section, one of the (many) things it says is:
    The following lines are equivalent:

        while (defined($_ = <STDIN>)) { print; }
        while ($_ = <STDIN>) { print; }
        while (<STDIN>) { print; }
        for (;<STDIN>;) { print; }
        print while defined($_ = <STDIN>);
        print while ($_ = <STDIN>);
        print while <STDIN>;
This command is the C-style for loop, which behaves like while (when used this way, and more generally too, in a slightly weaker sense):
 for (;<STDIN>;) { print; }
So the actual condition of the while loop is the return value of the built-in defined function. That's the last expression to be evaluated. The final time <$f> is evaluated, it returns undef, but when that is passed to defined, you get false, which reply shows as ''.
That is, the empty string isn't from the filehandle read at all. It is instead the way reply displays a false scalar value, when that false value is capable of being readily taken to be of any dynamic type, as is the case of false values that are generated by most Perl expressions to signify falsity.
0> !1;
$res[0] = ''
As for why that is:
29
A: Why does Perl use the empty string to represent the boolean false value?

Chas. OwensThe various logical operators don't return an empty string, they return a false or true value in all three simple scalar types. It just looks like it returns an empty string because print forces a string context on its arguments: #!/usr/bin/perl use strict; use warnings; use Devel::Peek; my ...

@Zanna So... the short answer is that the value shown is the last expression evaluated, which is the loop condition when it stops the loop... but that condition is actually the result of passing the undef return value from the filehandle read to the defined operator, which return a generic false value. That generic false value is then shown as '', even though it is not really the empty string any more than it is really, for example 0.
A more accurate statement would be to say that it is really '' but also really the default value of the other dynamic types a scalar can be. The way Perl lets you often not worry about whether something is, say, a number or a string, is to keep track of whether or not it has a computed value of each of the possible dynamic types that is current, and what a (possibly current) value is for each of them (when there is something that might be current).
That's why it's acceptably fast to, say, read strings from the user and use those strings, repeatedly, as though they were integers, or as though they were floating point values.
 
12:27 PM
@EliahKagan I see :)
 
I want to fix my incomplete (and possibly wrong) understanding of when and how $_ is replaced after the loop in which it is implicitly assigned ends.
Yeah, while just doesn't reset it:
2> for (1..3) { print "---\nOuter: $_\n"; for (11..13) { print "Inner: $_\n" } print "Outer: $_\n" }
---
Outer: 1
Inner: 11
Inner: 12
Inner: 13
Outer: 1
---
Outer: 2
Inner: 11
Inner: 12
Inner: 13
Outer: 2
---
Outer: 3
Inner: 11
Inner: 12
Inner: 13
Outer: 3
$res[2] = ''

3> for (1..3) { print "---\nOuter: $_\n"; while (glob '1{1,2,3}') { print "Inner: $_\n" } print "Outer: $_\n" }
---
Outer: 1
Inner: 11
Inner: 12
Inner: 13
Use of uninitialized value $_ in concatenation (.) or string at reply input line 1.
Apparently that's what perldoc perlop means when it says, "The $_ variable is not implicitly localized. You'll have to put a "local $_;" before the loop if you want that to happen." More fully, talking about how to use the <> operator in scalar context to read the next line from a filehandle, it says:
Ordinarily you must assign the returned value to a variable, but there is
one situation where an automatic assignment happens. If and only if the
input symbol is the only thing inside the conditional of a "while"
statement (even if disguised as a "for(;;)" loop), the value is
automatically assigned to the global variable $_, destroying whatever was
there previously. (This may seem like an odd thing to you, but you'll use
the construct in almost every Perl script you write.) The $_ variable is
not implicitly localized. You'll have to put a "local $_;" before the loop
So... You may be wondering what filehandle is read from when you use readline with no arguments, or the <> operator with no filehandle (i.e., literal <> with nothing inside).
You know about the actual effect of <>, right? That it reads from files that are named in command-line arguments, one after another, almost as though it was one big file that contained the concatenation of each of them, or, if there are no command-line arguments, then it reads from standard input?
 
12:43 PM
if not, I should probably have realised it
 
ek@Io:~$ reply
0> open my $f, '>', 'foo';
$res[0] = 1

1> print {$f} "first line of foo\nsecond line of foo\n";
$res[1] = 1

2> close $f;
$res[2] = 1

3> open my $f, '>', 'bar';
$res[3] = 1

4> print {$f} "first line of bar\nsecond line of bar\nthird line of bar\n";
$res[4] = 1

5> close $f;
$res[5] = 1

6> open my $f, '>', 'baz';
$res[6] = 1

7> print {$f} "first line of baz\nsecond line of baz\n";
$res[7] = 1

8> close $f;
$res[8] = 1

9> exit
ek@Io:~$ cat foo
first line of foo
second line of foo
(The extra newline is because I forgot about how here strings in Bash add a trailing newline automatically: "The result is supplied as a single string, with a newline appended..." Sorry about that.)
 
no problem!
it's clear :)
 
The specific behavior of reading from <> is that command-line arguments, unless they are interpreted as arguments to perl (i.e., the Perl interpreter) itself, are placed automatically in the array @ARGV, before the script's code is run. The first time you read <>, that array is consulted. Arguments from that array are used as the filename. If there are no arguments, it is as if a single - arguments had been passed, causing standard input to be read from.
The old two-argument version of open is used, so special behavior that causes perl do to stuff other than just open files occurs. (Notice that I've used the three-argument version, except when I used the two-argument version with |, which is part of its special syntax.) This has security implications, some but not all of which are mitigated when reading from <<>> instead of <>, but <<>> is only supported in new versions of perl.
ek@Io:~$ perl -we 'while (<>) { print "$ARGV: $_" }' foo bar baz
foo: first line of foo
foo: second line of foo
bar: first line of bar
bar: second line of bar
bar: third line of bar
baz: first line of baz
baz: second line of baz
ek@Io:~$ perl -we 'while (<>) { print "$ARGV: $_" }' <<<$'First\nSecond'
-: First
-: Second
^^^ The special $ARGV variable holds the name used for the file that is currently being read.
ek@Io:~$ perl -we 'while (<>) { print "(@ARGV)\n\t$ARGV: $_" }' foo bar baz
(bar baz)
        foo: first line of foo
(bar baz)
        foo: second line of foo
(baz)
        bar: first line of bar
(baz)
        bar: second line of bar
(baz)
        bar: third line of bar
()
        baz: first line of baz
()
        baz: second line of baz
^^^ Elements of @ARGV (i.e., the filenames) are shifted off the beginning (with shift) before being used.
ek@Io:~$ perl -we '@ARGV = qw(foo bar baz); while (<>) { print "$ARGV: $_" }' <<<$'First\nSecond'
foo: first line of foo
foo: second line of foo
bar: first line of bar
bar: second line of bar
bar: third line of bar
baz: first line of baz
baz: second line of baz
ek@Io:~$ perl -we 'while (<>) { print "$ARGV: $_" }' <<<$'First\nSecond'        -: First
-: Second
^^^ If @ARGV is modified before the first read of <>, then the behavior of <> is altered accordingly. One use of this is to process out command-line options before you then read from <> process the remaining command-line arguments, which you assume to be filenames. For example:
#!/usr/bin/env perl

use strict;
use warnings;
use Getopt::Long qw(GetOptions :config gnu_getopt no_auto_abbrev);

my $verbose = 0;
GetOptions('verbose|v' => \$verbose);

while (<>) {
    if ($verbose) { print "$ARGV: " }
    print;
}
I called that script opt-demo and ran it a few times:
ek@Io:~/pl$ ./opt-demo foo bar baz
first line of bar
second line of bar
third line of bar
first line of baz
second line of baz
ek@Io:~/pl$ ./opt-demo -v foo bar baz
bar: first line of bar
bar: second line of bar
bar: third line of bar
baz: first line of baz
baz: second line of baz
ek@Io:~/pl$ ./opt-demo foo --verbose bar -vv baz
bar: first line of bar
bar: second line of bar
bar: third line of bar
baz: first line of baz
baz: second line of baz
This works because Perl modules that perform automatic option processing, such as Getopt::Long, automatically remove options from @ARGV as they process them. They even remove the operands for the options, if you define any non-medadic options. They leave non-option arguments (specifically, they leave arguments that neither specify options nor are operands of options), and those are used as filenames when reading with <>.
So, as for what filehandle <> (or explicitly calling readline with no argument) is using: it uses the special ARGV filehandle, which provides the behavior of shifting filenames off @ARGV and attempting to open and read from them in sequence. Writing <> has the exact same effect as writing <ARGV>.
The ARGV filehandle is descriped as "magic" in some of the documentation. It is not the only filehandle with special semantics, however. For example, there is special behavior for the filehandles STDIN, STDOUT, an STDERR, which represent the standard streams.
Note that the array @ARGV, the scalar $ARGV, and the bareword ARGV are all different, though they are conceptually related, which is why they are named the same except for the sigils.
 
1:33 PM
@Zanna So, -n and -p both work by enclosing the entire script that the interpreter receives, whether as a file being executed or as the contents of one or more arguments to the -e or -E option, to be enclosed implicitly in while (<>) { ... }. That is, the script goes where I wrote ... there. The -n and -p options differ in what additional code is taken implicitly to be present. The short summary of the difference is that -p prints the line <> read, after each iteration.
 
 
5 hours later…
7:00 PM
@EliahKagan ah good to see what's going on
 

« first day (132 days earlier)      last day (2267 days later) »