Lazer
Lazer

Reputation: 94800

Why can't I use the diamond operator with an array in Perl?

Code

$ cat test1
hello 
i am 
lazer

nananana
$ cat 1.pl
use strict;
use warnings;

my @fh;
open $fh[0], '<', 'test1', or die $!;

my @res1 = <$fh[0]>;  # Way1: why does this not work as expected?
print @res1."\n"; 

my $fh2 = $fh[0];
my @res2 = <$fh2>;    # Way2: this works!
print @res2."\n";

Run

$ perl 1.pl
1
5
$

I am not sure why Way1 does not work as expected while Way2 does. Aren't those two methods the same? What is happening here?

Upvotes: 11

Views: 1442

Answers (4)

runrig
runrig

Reputation: 6524

Because of the dual nature of the <> operator (i.e. is it glob or readline?), the rules are that to behave as readline, you can only have a bareword or a simple scalar inside the brackets. So you'll have to either assign the array element to a simple scalar (as in your example), or use the readline function directly.

Upvotes: 14

hobbs
hobbs

Reputation: 239652

Because from perlop:

If what's within the angle brackets is neither a filehandle nor a simple scalar variable containing a filehandle name, typeglob, or typeglob reference, it is interpreted as a filename pattern to be globbed, and either a list of filenames or the next filename in the list is returned, depending on context. This distinction is determined on syntactic grounds alone. That means <$x> is always a readline() from an indirect handle, but <$hash{key}> is always a glob().

You can spell the <> operator as readline instead to avoid problems with this magic.

Upvotes: 14

Eric Strom
Eric Strom

Reputation: 40142

Anything more complex than a bareword (interpreted as a file handle) or a simple scalar $var is interpreted as an argument to the glob() function. Only barewords and simple scalars are treated as file handles to be iterated by the <...> operator.

Basically the rules are:

<bareword> ~~  readline bareword
<$scalar>  ~~  readline $scalar
<$array[0]> ~~ glob "$array[0]"
<anything else> ~~ glob ...

Upvotes: 8

Eugene Yarmash
Eugene Yarmash

Reputation: 149726

It's because <$fh[0]> is parsed as glob($fh[0]).

Use readline instead:

my @res1 = readline($fh[0]);

Upvotes: 6

Related Questions