in reply to I just realized that FILEHANDLES violate use strict

Prior to Perl 5.6 (I think that's the version), a filehandle was merely another slot in a typeglob. Typeglobs only exist in symbol tables, so any filehandle was automatically a package variable and the only way to pass them around was to pass typeglobs around. Since, at the time, pretty much the only way to create a filehandle was with the open statement, I can only assume that Larry thought there was no need to have a separate declaration for the filehandle and thus allowed it to run under strict.

However, if you needed to pass around typeglobs, it was cumbersome and error prone, so newer versions of Perl allow lexically scoped filehandles:

open my $fh, $somefile or die $!;

Incidentally, as a matter of good style, it's usually safer to localize the filehandle within a sub to ensure that you don't trample on a similarly named filehandle in the same package:

sub on { my $file = shift; local \*F; open F, $file or die "Couldn't open $file: $!"; }

Cheers,
Ovid

Update: Okay, now I'm a bit confused. I was curious about the behavior of a lexically scoped filehandle and was wondering what Perl thinks it is:

C:\>perl -e "open my $fh, q|< test.txt| or die $!;print ref $fh" GLOB

GLOB? I don't get it. perlguts says that a scalar can return this value for a filehandle, but if it's lexically scoped, is this really a typeglob? Are there other, unused slots here, or is this just a poor choice of name? (Or is Ovid off in never-never land again?)

Join the Perlmonks Setiathome Group or just click on the the link and check out our stats.

Replies are listed 'Best First'.
(bbfu) (IO::Handle and Symbol) Re: (Ovid) Re: I just realized that FILEHANDLES violate use strict
by bbfu (Curate) on Mar 27, 2002 at 17:51 UTC

    When using a scalar variable, open (invisibly) returns an IO::Handle object. IO::Handle, as it happens, generates an "anonymous" typeglob using the Symbol module.

    Perl doesn't actually have true anonymous typeglobs (as they must be (er.. make that) start as (see Update2 below) part of a symbol table), so what the Symbol module does to create pseudo-anonymous typeglobs is create a unique, unused-by-anything-else entry in the symbol table for the Symbol:: package. It then returns a (typeglob) reference to that symbol table entry.

    So, uh, I guess the answer is: yes, it is really a typeglob, but no, it's not really lexically scoped (well, the ref is, but not the actual typeglob that it points to).

    Update: Well, ok. There's some internal magic that mucks about with the name of the typeglob entry (as evidenced by Juerd's post), but the principle is the same.

    Update2: Well, as tye points out, the internal magic of open uses the magic of local to break the glob away from its symbol table of origin (which also, incidentally, happens to be the same package the open statement is in, instead of a seperate package like Symbol) and make it truly lexical.

    This has the added benefit that the name of the symbol used is irrelevent, so open uses the name of the original variable (which, of course, Symbol wouldn't have access to anyway). This allows warnings and errors to report the name of the opened filehandle as the name of the variable used to read from the file (and be right... most of the time).

    bbfu
    Seasons don't fear The Reaper.
    Nor do the wind, the sun, and the rain.
    We can be like they are.

Re: (Ovid) Re: I just realized that FILEHANDLES violate use strict
by demerphq (Chancellor) on Mar 27, 2002 at 17:12 UTC
    Afaik it really is a glob. Just one that doesn't live in the package namespace (and thus it has no name) but an anonymous one just like the rest of the lexically scoped vars.

    The annoying thing is that I remember reading a much better explaination of this but I cant remember where... Perl5Porters maybe.

    Yves / DeMerphq
    ---
    Writing a good benchmark isnt as easy as it might look.

      Afaik it really is a glob. Just one that doesn't live in the package namespace (and thus it has no name) but an anonymous one just like the rest of the lexically scoped vars.

      Partly true. With open my $foo, $file, $foo is a reference to a glob, and the glob is not anonymous, because globs can only be in a package. The glob reference $foo can be dereferenced in a normal fashion: *$foo. With *$foo, you'll have a normal glob, like all others. Globs have a string representation that happens to be an asterisk, followed by namespace :: name.

      Consider:

      #!/usr/bin/perl -l { open my $foo, '>', $$ or die $!; print $foo; # GLOB(0x...) print ref $foo; # GLOB print *$foo; # *main::$foo print $foo "Test"; # Test > $$ } # The scope has ended. Because the lexical dies, the file is closed. # The (normally unreachable because of its invalid name) glob # *main::$foo still exists, because globals just don't die. # And they lived happily ev^U


      Writing this, I thought of what would happen if I created a new lexical scope in the already existing bare block. Would the glob clash? I tried:
      { open my $foo, '>', $$ or die $!; print $foo; # GLOB(0x...) print ref $foo; # GLOB print *$foo; # *main::$foo print $foo "Test"; # Test > $$ { open my $foo, '>',"$$.z" or die $!; print $foo; # GLOB(0x...) print ref $foo; # GLOB print *$foo; # *main::$foo <-- !!!!! print $foo "Test"; # Test > $$ } }
      I cannot explain this. The glob has the same stringification, but actually is another glob? Is it local()ized internally?

      U28geW91IGNhbiBhbGwgcm90MTMgY
      W5kIHBhY2soKS4gQnV0IGRvIHlvdS
      ByZWNvZ25pc2UgQmFzZTY0IHdoZW4
      geW91IHNlZSBpdD8gIC0tIEp1ZXJk
      

        the glob is not anonymous, because globs can only be in a package

        Actually, as you hint at later, local makes this so that it isn't strictly true. You have to create a glob in a package namespace (at least when writing Perl, probably not so when writing C imbedded in perl), which also gives it a name, but it doesn't have to stay there. I don't know if open also temporarilly creates *{'$foo'} and then moves it out of the symbol table, but the end result is similar to that of:   my $foo= do { local *{'$foo'}; \*{'$foo'}; }; so that none of your *$foos are in any symbol table, and so none of them are the same as *{'$foo'}.

                - tye (but my friends call me "Tye")