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

In a package with use strict this is not an error:
sub on { my $file = shift; open F, $file or die "couldnt open $file: $!"; }
even though I have not done
our *F
or something along those lines... why is that?

Replies are listed 'Best First'.
(Ovid) Re: I just realized that FILEHANDLES violate use strict
by Ovid (Cardinal) on Mar 27, 2002 at 16:48 UTC

    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.

      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.

      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
        

Re: I just realized that FILEHANDLES violate use strict
by jmcnamara (Monsignor) on Mar 27, 2002 at 17:01 UTC

    Barewords are also allowed under strict in other places where a filehandle might occur, as shown by the following examples:
    $ perl -Mstrict -le 'print F . 1' F1 $ perl -Mstrict -le 'print 1 . F' Bareword "F" not allowed while "strict subs" in use at -e line 1. Execution of -e aborted due to compilation errors.

    --
    John.

      eww! that's ugly! strict should not allow that kind of parsing. fodder for obfu, maybe?

      ~Particle ;Þ

Re: I just realized that FILEHANDLES violate use strict
by broquaint (Abbot) on Mar 27, 2002 at 16:43 UTC
    I believe this is because strict doesn't deal with filehandles. This is why not declaring a filehandle will never raise a warning/error (but if you're using a non-existant filehandle you'll *probably* get an warning/error of some kind), and why they don't violate strict.
    But if you're worried about keeping track of your filehandles and have a recent (see. 5.6.0+) version of perl just use scalars like so.
    open(my $fh, "somefile.txt") or die("Ack - $!"); filemunger($fh); # and so on and so forth

    HTH

    broquaint

Re: I just realized that FILEHANDLES violate use strict
by particle (Vicar) on Mar 27, 2002 at 16:53 UTC
    you can use FileHandle;, if you want to use scalars. then you'll have to follow the rules:
    my $file = shift; my $F = FileHandle->new; if( defined $F ) { $F->open($file) or die "can't open file $file: $!" } # it also lets you do things like $F->autoflush; # instead of that whole select() business

    ~Particle ;Þ

Re: I just realized that FILEHANDLES violate use strict
by trs80 (Priest) on Mar 28, 2002 at 05:26 UTC