Beefy Boxes and Bandwidth Generously Provided by pair Networks
go ahead... be a heretic
 
PerlMonks  

unexpected close() success on (non-) filehandle

by mkmcconn (Chaplain)
on Nov 21, 2001 at 17:59 UTC ( [id://126764]=perlquestion: print w/replies, xml ) Need Help??

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

Brethren,
In a learning experiment using multiple filehandles in a hash, I stumbled on something that I don't understand.

#/usr/bin/perl -w use strict; local (*E,*F,*G); my $string = <<JUNK; I will print unless I perish JUNK my %rh = (E=> *E, F=> *F, G=> *G); open $rh{$_}, ">test_$_.txt" or die $! for keys %rh; print { $rh{$_}} $_.$string for keys %rh;
# the following (incorrect) line closes the filehandles
close $_ or die $!                        for keys %rh; # so that this (correct) line dies
close $rh{$_} or die $! for keys %rh; #error: # Bad file descriptor at C:\Perl\scripts\test5.pl line 20.

Note that strict is being used.
Why is $_, above, allowed to be used as a Filehandle? In the other contexts, open() or print (), the script would have failed with appropriate messages that 'String ('F') can't be used ..' etc.

So, close() doesn't expect the same strictness that open() does. Is that as it ought to be?
(ActiveState perl 5.6.1)
mkmcconn

Replies are listed 'Best First'.
Re: unexpected close() success on (non-) filehandle
by tachyon (Chancellor) on Nov 21, 2001 at 18:33 UTC

    No this is not incorrect at all, it is exactly what you expect. The glob *X consists of the following elements $X @X %X &X and X (the filehandle). When you write open *X, $foo Perl opens $foo onto the filehandle X from the *X glob. Thus when you say close X you close the filehandle X - this is what your close $_ example does. When you say close *X Perl also does a close X as X is the filehandle in the *X glob - this is what your close $rh{$_} example does.

    Update (changed code to better example)

    #/usr/bin/perl -w use strict; my %rh = (E=> *E, F=> *F, G=> *G); { no strict 'refs'; print "\n\n\$_ has a value, used as a hard reference\n"; for (values %rh) { open $_, ">test.txt" or die $!; print $_ "$_ This works\n"; close $_ or die $!; open $_, "<test.txt" or die $!; print <$_>; close $_ or die $!; unlink "test.txt" or die $!; } print "\n\n\$_ has a value, used as a symbolic reference\n"; for (keys %rh) { open $_, ">test.txt" or die $!; print $_ "$_ This works\n"; close $_ or die $!; open $_, "<test.txt" or die $!; print <$_>; close $_ or die $!; unlink "test.txt" or die $!; } } # and under strict.... print "\n\n\$_ has a value, used as a hard reference\n"; for (values %rh) { open $_, ">test.txt" or die $!; print $_ "$_ This works\n"; close $_ or die $!; open $_, "<test.txt" or die $!; print <$_>; close $_ or die $!; unlink "test.txt" or die $!; } print "\n\n\$_ has a value, used as a symbolic reference\n"; for (keys %rh) { open $_, ">test.txt" or die $!; print $_ "$_ This works\n"; close $_ or die $!; open $_, "<test.txt" or die $!; print <$_>; close $_ or die $!; unlink "test.txt" or die $!; }

    Part of the problem you are having is not distinguishing a hard reference (OK under strict) an a symbolic reference (not OK under strict)

    cheers

    tachyon

    s&&rsenoyhcatreve&&&s&n.+t&"$'$`$\"$\&"&ee&&y&srve&&d&&print

(tye)Re: unexpected close() success on (non-) filehandle
by tye (Sage) on Nov 21, 2001 at 22:24 UTC

    Did you know that open "E", ... works just fine? That seems like it should be a symbolic reference, doesn't it? In other words, yes, stringy file handles suck and use strict doesn't always protect you from them. And that protection is even inconsistant, as you noted.

    I'd say you've found a bug. It isn't one I care much about, though. (:

    The real solution to your problem is to not simply use things like *E as file handles.

    What you want is a reference to a glob (not just a glob) because it is easy to distinguish a reference to a glob from a string while distinguishing a glob from a string is a bit of a trick (I'm not even sure it is always possible). Globs are what Perl4 used in place of references and are really only in Perl5 for backward compatability.

    And you want that glob to not currently be in the current symbol table. You can use Symbol's gensym() to get a reference to a glob in that module's symbol table. I tend to prefer:     my $fh= do { local(*FILE); \*FILE }; (which gives you a reference to a glob that was only briefly in the current symbol table) or to use IO::Handle.

    Any of these three approaches will prevent the casual string from being successfully used as a file handle. Note that there are lots of other problems with having globs in your current symbol table that are open file handles. For example, open(CGI,... seriously breaks things...

            - tye (but my friends call me "Tye")
      yes, stringy file handles suck and use strict doesn't always protect you from them. And that protection is even inconsistant, as you noted... tye

      That's what I wanted to know tye, thanks. That is, I recognized that the behavior I illustrated was caused by the way that the hash was constructed and used, which magnified the ambiguity of globs and strings (which I did to try to clarify my question). My focus was on why the 'protection' of the strict pragma "didn't work" sometimes. I assumed that use strict;, turning on perl's ability to decide the difference between 'F' and *main::F, would always work. When it didn't work with complete consistency, I wanted to understand why.

      So, I guess what I've learned from the discussion here is that there are some limits to perl's amazing context sensing abilities, but there is no need to approach that horizon, even when those limits are restrained by strict. Saying more explicitly what I mean can be an important help in assuring that the code will do exactly what I mean

      Thanks to all for all of your patience and helpful comments
      mkmcconn

Re: unexpected close() success on (non-) filehandle
by demerphq (Chancellor) on Nov 21, 2001 at 19:39 UTC
    Well, not answering your question but the entire framework here seems off kilter. If you want to populate a hash with a bunch of filehandles what about
    my @files; #the files my %handles; foreach my $name (@files) { open $handles{$name},$name or die "$name:$!"; } foreach my $fh (values %handles) { print $fh scalar(localtime),"\n"; } foreach my $fh (values %handles) { close $fh; }
    Anyway, a quick $.02 while excel loads another 20mb "database" (NOT!) across the network.

    Oooh! For the record tilly has pointed out that autovivification is a 5.6 feature and wont work in those prehistoric version that some systems have installed ;-) :-)

    Yves / DeMerphq
    --
    Have you registered your Name Space?

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://126764]
Approved by root
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others examining the Monastery: (6)
As of 2024-03-29 09:57 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found