Tie and Lexical Filehandles or IO::File?

  • Thread starter Veli-Pekka Tätilä
  • Start date
V

Veli-Pekka Tätilä

Hi,
I'm playing around with tied filehandles at the moment. Now that I'm finally
beginning to grasp the basics of Perl OOP, tying doesn't seem all that
difficult. The only problem is, I cannot, for the life of me, figure out how
to tie lexically scoped handles or IO::File objects. I'd like to hold my
file handles in lexically scoped scalars be them globrefs or objects. I've
read perltie and perlref, browsed the Perl FAQ and Googled both the groups
and the Web with little success.

In the interest of simplicity, I won't be showing my real code here, but a
short test script demonstrating the problem. Here's a very basic tied handle
example slightly adapted from the perltie man-page (I had to add one my in
it):

use strict; use warnings;
package Shout;
sub TIEHANDLE { print "<shout>\n"; my $i; bless \$i, shift }
sub PRINT
{
no warnings 'uninitialized'; # $\ tends to be undef.
my $r = shift; $$r++;
print join($,,map(uc($_),@_)),$\
}
sub CLOSE { print "CLOSE called.\n" }
sub DESTROY { print "</shout>\n" }

And now the test program (actually in the same file):

package main;
# Only the first sub is succesful, the rest attempt calling TIESCALAR and
die.
oldschool(); lexical(); oop();

The first of the Strategies looks like this:

sub oldschool
{ # Local type globs.
local *FH;
tie *FH, 'Shout';
print FH "Tie Fighter\n";
close FH;
} # sub

This strategy works well, calling TIEHANDLE, PRINT, CLOSE AND DESTROY as
expected. The output is:

<shout>
TIE FIGHTER
CLOSE called.
</shout>

However, I like this filehandle syntax the least of the bunch.

My second approach goes like this:

sub lexical
{ # Typeglob refs in scalars.
use Symbol 'gensym';
my $fh;
$fh = gensym;
# open my $fh, '>test.dat' or die $!;
tie $fh, 'Shout';
print $fh "X-Wing\n";
} # sub

The only major difference is using gensym to generate a reference to an
anonymous typeglob held in a scalar. The second method dies with the
message:

Can't locate object method "TIESCALAR" via package "Shout"

Whether the file handle is generated with gensym or derived by passing open
an undef scalar appears to make no difference. That is in both cases it
seems tie looks at its args, determines that the first is a scalar and
assumes I'd liek to tie a scalar. Although quite logical, in a way, I would
have expected it to handle filehandles as diversly as print et al do.

The third and final method is the same as the second, except that we use a
scalar holding an IO::File object. Again tie infers that I'd like to tie a
scalar and the problem persists. For completeness, here's the code:

sub oop
{ # The object-oriented interface.
use IO::File;
my $fh = IO::File->new;
tie $fh, 'Shout';
print $fh "Death Star\n";
} # sub

I can, of course, use localized file handles for a solution that works. I
would dearly liek to use some safer variant, however. For simple stuff,
lexically scoped file handles gotten from open are my favorite.

Any help greatly appreciated.

PS: Perl version is 5.8.8 on Win XP Pro SP2.
 
P

Paul Lalli

Veli-Pekka Tätilä said:
I'm playing around with tied filehandles at the moment. Now that I'm finally
beginning to grasp the basics of Perl OOP, tying doesn't seem all that
difficult. The only problem is, I cannot, for the life of me, figure out how
to tie lexically scoped handles or IO::File objects. I'd like to hold my
file handles in lexically scoped scalars be them globrefs or objects.
Excellent!

I've
read perltie and perlref, browsed the Perl FAQ and Googled both the groups
and the Web with little success.

In the interest of simplicity, I won't be showing my real code here, but a
short test script demonstrating the problem.

THANK YOU!!

Here's a very basic tied handle
example slightly adapted from the perltie man-page (I had to add one my in
it):

use strict; use warnings;
package Shout;
sub TIEHANDLE { print "<shout>\n"; my $i; bless \$i, shift }
sub PRINT
{
no warnings 'uninitialized'; # $\ tends to be undef.
my $r = shift; $$r++;
print join($,,map(uc($_),@_)),$\
}
sub CLOSE { print "CLOSE called.\n" }
sub DESTROY { print "</shout>\n" }

And now the test program (actually in the same file):

package main;
# Only the first sub is succesful, the rest attempt calling TIESCALAR and
die.
oldschool(); lexical(); oop();

The first of the Strategies looks like this:

sub oldschool
{ # Local type globs.
local *FH;
tie *FH, 'Shout';
print FH "Tie Fighter\n";
close FH;
} # sub

This strategy works well, calling TIEHANDLE, PRINT, CLOSE AND DESTROY as
expected. The output is:

<shout>
TIE FIGHTER
CLOSE called.
</shout>

However, I like this filehandle syntax the least of the bunch.

My second approach goes like this:

sub lexical
{ # Typeglob refs in scalars.
use Symbol 'gensym';
my $fh;
$fh = gensym;
# open my $fh, '>test.dat' or die $!;
tie $fh, 'Shout';
print $fh "X-Wing\n";
} # sub

The only major difference is using gensym to generate a reference to an
anonymous typeglob held in a scalar.

Right. And references are scalars.
The second method dies with the message:

Can't locate object method "TIESCALAR" via package "Shout"

Whether the file handle is generated with gensym or derived by passing open
an undef scalar appears to make no difference. That is in both cases it
seems tie looks at its args, determines that the first is a scalar and
assumes I'd liek to tie a scalar.

Sounds right to me.
Although quite logical, in a way, I would
have expected it to handle filehandles as diversly as print et al do.

You want to tie the filehandle that $fh *references* to the Shout
class, not $fh itself.

tie *{$fh}, 'Shout';
The third and final method is the same as the second, except that we use a
scalar holding an IO::File object. Again tie infers that I'd like to tie a
scalar and the problem persists. For completeness, here's the code:

sub oop
{ # The object-oriented interface.
use IO::File;
my $fh = IO::File->new;
tie $fh, 'Shout';
print $fh "Death Star\n";
} # sub

I don't know enough abou the internals of IO::File to know *why* this
works, but it does. Same syntax as above. Dereference $fh as a glob,
and everything becomes happy.

Paul Lalli
 
V

Veli-Pekka Tätilä

Paul said:
Veli-Pekka Tätilä wrote:
You want to tie the filehandle that $fh *references* to the Shout
class, not $fh itself.
Ah, a good point, thanks for a quick reply. Often in programming, some
things are blatantly obvious once you do realize them. This time I didn't.
On the other hand, sometimes merely trying to explain a problem in this
group has lead to the solution, so I needn't post at all.
I don't know enough abou the internals of IO::File to know *why* this
works, but it does.
Well, neither do I. Before I saw your reply, I thought of typing an
appologetic addition to the thread about not thinking clearly all the way
through. That is I realized based on the docs, which mention no tying
action, that using a IO::File object as a file handle is probably silently
wrong. Again seems Perl did what I ment so I aint complaining, <grin>.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,969
Messages
2,570,161
Members
46,705
Latest member
Stefkari24

Latest Threads

Top