zzspectrez has asked for the wisdom of the Perl Monks concerning the following question:
I am looking for a little enlightenment about typeglobs. I am writing module that stores a filehandle in an object. The filehandle is actually a filehandle to a socket but lets pretend it is just a file. This can be done doings something like the following.
sub foo { my $self = shift; my $filename = shift; open FH, $filename or die "Can not open file: $!\n"; $self->{'fh'} = \*FH; }
This has worked fine. However, now I need to store multiple filehandles in the object and I want one subroutine to handle opening the files and returning the filehandle. Since a typeglob holds an entire symbol table entry, I know that trying to open all the files with FH and returning a typeglob will not work.
So I do what I allways do when Im not sure what will hapen, I make a test applications. This is what I get.
package FOO; use diagnostics; sub new { my $class = shift; my $self = { blahh => 'blah', }; my (%opts) = @_; return unless (exists $opts{'input'} && exists $opts{'output'}); %$self = ( %$self, %opts ); bless $self, $class; $self->{'inp_fh'} = $self->_open_read; $self->{'out_fh'} = $self->_open_write; return $self; } sub read_line { my $self = shift; my $fh = $self->{'inp_fh'}; return <$fh>; } sub write_line { my $self = shift; my $data = shift; my $fh = $self->{'out_fh'}; print $fh $data; } sub _open_read { my $self = shift; { local *FH; open FH, $self->{'input'} or die "Couldn't open: $!\n"; return \*FH; } } sub _open_write { my $self = shift; { local *FH; open FH, ">$self->{'output'}" or die "Couldn't open file: $!\n"; return \*FH; } } sub DESTROY { my $self = shift; close ($self->{'inp_fh'}); close ($self->{'out_fh'}); } package main; use strict; my $data; my $foo = FOO->new('input'=>"inp.dat", 'output'=>"out.dat") || die ("Error creating new FOO!!\n"); for my $key (keys %$foo) { print "KEY: $key \tVAL: $foo->{$key}\n"; } while ($data = $foo->read_line) { $foo->write_line($data); }
This works fine, making a duplicate of the file, and returning data like the following:
KEY: out_fh VAL: GLOB(0x1a75098) KEY: inp_fh VAL: GLOB(0x1a75038) KEY: input VAL: inp.dat KEY: blahh VAL: blah KEY: output VAL: out.dat
Making slight modifications. Changing _open_read() and _open_write() so that the return is return *FH. I run this and the program has the same desired results.. The output of the filehandle keys changes to:
KEY: out_fh VAL: *FOO::FH KEY: inp_fh VAL: *FOO::FH
In my mind, I did not think this would work. Since FH goes out of scope at the end of the block, you would think you would need a reference to the typeglob to maintain access to it. Secondly, in the second example the object appears to have two references to the same filehandle *FOO::FH. However although they are opened as the same filehandle, the code operates on two seperate filehandles. How is this working?
Lastly, I remember reading an article by Mark-Jason Dominus in Perl Journal on the uses of local. At the time I did not understand much about typeglobs or the diferences between local and my so I only glanced at the article. Looking back at the article I find an interesting tidbit that relates
The article sugests using the following construct to get a glob that is disconected from the symbol table: $fh = do { local *FH };. Then you use $fh as if it was a filehandle.
So I modify my test program like the following:
sub _open_write { my $self = shift; my $fh = do { local *FH }; open $fh, ">$self->{'output'}" or die "Couldn't open file: $!\n"; return $fh; }
This works great! However, once again Im a little confused about how this trick works. First step I open my camel book and refresh reading about do. Ok, I feel stupid, I didnt know that a do block return the value of the last expression evaluated. This brings a little enlightenment. However, once again Im confused on how the block can return the value of *FH which loses scope once the block exits.
I guess part of the confusion is, what exactly is being returned?!? According to the print of my hash, both variables point to the same glob *FOO::FH which was local in scope.
Thanks!
zzSPECTREz
|
---|
Replies are listed 'Best First'. | |
---|---|
Re: typeglobs and filehandles
by Dominus (Parson) on Dec 20, 2000 at 23:15 UTC | |
by zzspectrez (Hermit) on Dec 21, 2000 at 12:51 UTC | |
by extremely (Priest) on Dec 21, 2000 at 17:19 UTC | |
by fundflow (Chaplain) on Dec 20, 2000 at 23:27 UTC | |
by Trimbach (Curate) on Dec 20, 2000 at 23:44 UTC | |
by snax (Hermit) on Dec 21, 2000 at 07:13 UTC | |
by Dermot (Scribe) on Dec 20, 2000 at 23:41 UTC | |
by ambiguous (Novice) on Dec 21, 2000 at 02:52 UTC | |
Re (tilly) 1: typeglobs and filehandles
by tilly (Archbishop) on Dec 20, 2000 at 23:08 UTC | |
Re: typeglobs and filehandles
by Dominus (Parson) on Dec 20, 2000 at 22:48 UTC |