3

I'd like to pass a reference to a file handle to a subroutine, such that code in the sub can read from the file and the position in the file handle changes in the calling environment, rather like using a pointer in C.

This kind of thing:

open my $fh, '<', $somefile or die;

dosomething(\$fh);

sub dosomething
{
  my $fh_ref = shift;

  while (my $l = <$$fh_ref>)
  {
    print $l;
    print "\n";
  }
}

This gives this output instead of writing each line:

 GLOB(0x20b8b38)

Obviously I am dereferencing the file handle reference wrong.

Addendum:

while (my $l = readline($$fh_ref))
{

etc.

seems to do the trick. I am still interested in why the first approach doesn't work.

simbabque
  • 53,749
  • 8
  • 73
  • 136
phlatphish
  • 95
  • 5

1 Answers1

4

The diamond operator <...> has two meanings in Perl -- one corresponding to the readline(HANDLE) function and the other corresponding to glob(EXPR). How does perl decide which function to use?

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(). That's because $x is a simple scalar variable, but $hash{key} is not--it's a hash element. Even <$x > (note the extra space) is treated as glob("$x "), not readline($x).

The workarounds are to either use an explicit readline call

while (my $l = readline($$fh_ref)) ...

or to use a simpler expression inside the brackets.

my $fh42 = $$fh_ref;
while (my $l = <$fh42>) ...
mob
  • 117,087
  • 18
  • 149
  • 283