Search code examples
perlreferencesubroutinefilehandle

Reading from a filehandle reference in a subroutune


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.


Solution

  • 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>) ...