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

Dear monks,

I'm trying to do something that should be really simple, but it's not Doing What I Mean.

Somewhere in the code I am calling a $parser, and pass it, among other things, a file handle to read from (at least, that's the idea):
open(FH, $opts{-file}); $opts{-handle} = \*FH; $parser->from_handle(%opts);
So, I have a hash %opts, that contains a file path under the -file key. I open the file, create a reference to the handle, assign that to $opts{-handle} and send the whole %opts hash to the $parser->from_handle method. Then, over in the from_handle method, the following happens:
sub from_handle { my $self = shift; my %opts = @_; while (<$opts{-handle}>) { #... and here we're supposed to read from FH } }
Okay, so in the "while" loop I was hoping $_ would contain the contents of $opts{-file}, one line at a time. Instead, it contains "GLOB(0x18660a8)". I've read perldata and perlref but I'm not quite sure what is expected of me. I tried *FH{IO} and desparate permutations with or without slashes in front of *FH, but they don't give me what I want.

I am obviously doing something wrong, but I don't quite know what The Right Way is. Any help and code examples are greatly appreciated. Thanks!

Replies are listed 'Best First'.
Re: Passing a file handle to a sub. I still don't get it.
by tlm (Prior) on Jun 09, 2005 at 18:43 UTC

    From perlop

    If what the angle brackets contain is a simple scalar variable (e.g., <$foo>), then that variable contains the name of the filehandle to input from, or its typeglob, or a reference to the same. For example:

    $fh = \*STDIN; $line = <$fh>;
    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.

    the lowliest monk

      tlm is correct. So you need to do the following:

      sub from_handle { my $self = shift; my %opts = @_; my $fh = $opts{-handle}; while (<$fh>) { #... and here we're supposed to read from FH } }

      -derby
Re: Passing a file handle to a sub. I still don't get it.
by Roy Johnson (Monsignor) on Jun 09, 2005 at 19:03 UTC
    Try using readline instead of the shorthand <>.

    Caution: Contents may have been coded under pressure.
Re: Passing a file handle to a sub. I still don't get it.
by QM (Parson) on Jun 09, 2005 at 19:13 UTC
    How do you know what $_ really is in your program?

    What you saw is the stringification, which is not necessarily the same thing. For instance:

    my $x = \*FH; print "plain glob ref: <$x>\n"; # prints: plain glob ref: <GLOB(0x1d6c660)> open ($x, "<","somefile") or warn "error\n"; print "open FH ref: <$x>\n"; # prints: open FH ref: <GLOB(0x1d6c660)>
    But if instead I use x to peek at the globref in the debugger, it looks like this:
    my $x = \*FH; x $x # prints: #0 GLOB(0x1d6c408) # -> *main::FH open ($x, "<","somefile") or warn "error\n"; print "open FH ref: <$x>\n"; # prints: 0 GLOB(0x1d6c408) -> *main::FH FileHandle({*main::FH}) => fileno(6)
    ...which is much more interesting.

    What do you get in your code?

    -QM
    --
    Quantum Mechanics: The dreams stuff is made of

      How do you know what $_ really is in your program?

      I can see that get printed on milk cartons one day :) (Talk to your children! A message from the government of Canada.)

      Anyway, all kidding aside, here's what I'm doing, and now It Just Works, so thank you all for your thoughts and input. The calling sub:
      #... blah blah blah open(FH, $opts{-file}); $opts{-handle} = *FH; return $parser->from_handle(%opts); #... la dee da
      And the callee:
      #... stick out left leg while ( readline($opts{-handle}) ) { if ( $_ ) { # ... frobnicate } } # return right leg
        It may work for you now, but do you know why? You've fixed it, but can you duplicate it in other contexts?

        I notice that you no longer take a reference to a glob, but the glob directly. My quick check shows that this works (though the glob reference shows more info in the debugger with the x command).

        -QM
        --
        Quantum Mechanics: The dreams stuff is made of

Re: Passing a file handle to a sub. I still don't get it.
by mifflin (Curate) on Jun 09, 2005 at 18:44 UTC
    try IO::File
    use IO::File; $opts{-handle} = IO::File->new($opts{-file}) or die $!; $parser->from_handle(%opts); sub from_handle { my $self = shift; my %opts = @_; while (<$opts{-handle}>) { #... and here we're supposed to read from FH } }
      Thank you both for your replies. So, I tried IO::File, and now $_ in the while loop contains "IO::File=GLOB(0xa1f08c4)". I hope I'm not being terribly dim here - I really appreciate your help, but this doesn't quite get me there yet. Any other hints?
        What tlm neglected to mention was what you should do :)

        Because <> can do two different things, readline and glob (and in your case is doing the wrong one), you should explicitly say while(readline($opts{-handle})).

        What exactly do you have in the <> brackets? Can you post the code?

        Also, now that you're using IO::File you can use its getline method instead of angle brackets to do linewise input. This eliminates the ambiguity with file globbing. See the docs for IO::File parent class, IO::Handle.

        the lowliest monk