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

I made the following mistake:

use strict; use warnings FATAL => qw(all); ... my @remove_env=qw(FOO BAR BAZ); foreach my $var (@remove_env) { $ENV{$var}='something'; } ... delete $ENV{_} foreach (@remove_env); print "$ENV{FOO}\n"; # FOO stil in environment!!!
Of course the error is in the delete line, but I wonder why this mistake was not detected by Perl. In this case, _ would be seen as file handle, but this would mean that using a file handle as a hash key would be a legal usage and not even issue a warning! Any comments?

-- 
Ronald Fischer <ynnor@mm.st>

Replies are listed 'Best First'.
Re: Why did this error slip through?
by Corion (Patriarch) on May 17, 2010 at 09:31 UTC

    Hashes accept barewords in their braces and treat them as the keys. Perl interprets your line

    delete $ENV{_}

    just like it treats the next line:

    print "$ENV{FOO}\n";

    There is little way around that because the second usage is quite common. You could potentially set up some policy for Perl::Critic to prohibit/flag usage of bare hash keys that do not start with [A-Za-z] or something like that. Perl more or less considers everything matching /\s*\w+\s*/ as a valid bareword hash key (he says without checking).

      Hashes accept barewords in their braces and treat them as the keys.
      Of course! How stupid I am that I haven't seen this!! Actually this is a feature I use myself often!!!

      -- 
      Ronald Fischer <ynnor@mm.st>
Re: Why did this error slip through?
by moritz (Cardinal) on May 17, 2010 at 09:31 UTC
    _ is not a file handle in your case, but an unquoted hash key. Which is perfectly legal even with strict enabled.

    Perl 6 solves this problem by having a separte syntax for literal hash keys (%hash<mykey>) and variable acess (%hash{$my_key_in_variable}).

    Perl 6 - links to (nearly) everything that is Perl 6.
Re: Why did this error slip through?
by JavaFan (Canon) on May 17, 2010 at 09:39 UTC
    In your case, delete $ENV{_} is the same as delete $ENV{"_"}. But that doesn't mean file handles are illegal to appear inside hash brackets. Any expression may appear there. Perl will just evaluate that expression (in scalar context (list context when slicing)), and, if necessary, cast the result to a string.

    print "$ENV{FOO}\n"; # FOO stil in environment!!!
    Considering that the bareword FOO can also be a filehandle, you really do not want perl to warn if a (potential) filehandle is used as a hash index. How's perl to know that when you write FOO, you really meant FOO, but when you write _, you might have typoed $_?
Re: Why did this error slip through?
by cdarke (Prior) on May 17, 2010 at 10:54 UTC
    Interestingly the filehandle _ gets stringified but a conventional file handle (stringified as a GLOB) can be used as a hash key:
    open(my $fh, $0) or die $!; $gash{$fh} = 'some value'; stat($0); $gash{*_} = 'some value'; print Dumper(\%gash); $VAR1 = { '*main::_' => 'some value', 'GLOB(0x18ab6ac)' => 'some value' };
    Of course just because it is legal does not mean it is necessarily a good idea.
    use strict; use warnings; can never catch all errors, just that you will catch more with them than without.
Re: Why did this error slip through?
by rowdog (Curate) on May 17, 2010 at 09:42 UTC

    _ gets stringified when you use it as a hash key. In the past, I've used stringified sockets as keys to a hash of clients.

    Edit: deleted useless example.