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

Apologies if this has already been raised - I did look in SuperSearch. Strange behaviour (bug?) of use strict 'subs' (was: ... strict 'vars') dances around it.

Documentation for strict 'subs' states: ... generating a compile-time error if you try to use a bareword identifier that's not a subroutine, unless it ... appears in curly braces...

This does not appear to be the case for keys in a hash slice. For example:
use warnings; use strict 'subs'; my %hash = qw (k1 v1 k2 v2 k3 v3); $hash{k1} = 42; # is fine @hash{k1,k2,k3} = (1,2,3); # BANG! Bareword "k1" not allowed... @hash{qw(k1 k2 k3)} = (1,2,3); # is fine
(Windows ActiveState 5.10.1)
Why are single keys and multiple keys handled differently?

OK, so a hash slice uses a list instead of a scalar, but why should that make a difference? Is an unquoted list somehow more dangerous than an unquoted scalar value?

Replies are listed 'Best First'.
Re: Unquoted hash slice keys with use strict 'subs'
by JavaFan (Canon) on Oct 14, 2009 at 10:58 UTC
    It has nothing to do with danger. It's a parsing/tokenizer thing. An unquoted string that looks like an identifier is a single token. The next token is the curly brace - so with one lookahead token, perl can determine it's a bareword that needs autoquoting. But if it sees a comma, it doesn't know what's happening - it cannot say "hmmm, I saw an opening curly brace, a bare word, a comma, perhaps it's a list, let's just see if it's a list of bare words all the way until the closing brace, if something else happens, I just backpaddle and try something else".

    If you do want perl to parse $hash{key1,key2,key3}, just turn off use strict 'subs'.

      You might be right - I have no knowledge of the complexities of the parse order - but I would have thought that the comma would not be unexpected because of the @ sigil. Surely, knowing that the clause inside the curley braces is in list context it would be expecting a list, a comma shouldn't come as any surprise.
      The error message reports three bare words, so it knows what the comma is and it recognises them as a list, it seems though it ignores the sigil and the braces.
        It may know what the comma is, it doesn't know what follows the comma.

      I don't think any backpedaling would be necessary if you want

      $hash{foo,bar} => $hash{'foo','bar'} $hash{foo,bar()} => $hash{'foo',bar()}

      Or are you saying you should get something else from the second line?

      By the way, Perl's parser is an LR parser, and they can't backpedal.

Re: Unquoted hash slice keys with use strict 'subs'
by moritz (Cardinal) on Oct 14, 2009 at 10:36 UTC

    IMHO it's not unquoted list are more dangerous than an unquoted scalar value but rather anything more complicated than a single identifier is potentially dangerous.

    Sure you can argue about that, but I somehow like the symmetry between $hash{...} autoquoting one key  ... => $value autoquoting one key.

    Still it's an arbitrary distinction, and in the Perl 6 design that was avoided by adding another quoting construct: %hash{mykey} never autoquotes, but interprets mykey is a function call, whereas %hash<mykey> explicitly quotes, and is extensible to lists: %hash<key1 key2>.

    The same construct can also be used in "normal" (non-postcircumfix) Perl 6 code: my @array = <word1 word2>;

    Perl 6 - links to (nearly) everything that is Perl 6.
Re: Unquoted hash slice keys with use strict 'subs'
by Bloodnok (Vicar) on Oct 14, 2009 at 11:13 UTC
    Unless it's a typo, the quote is clearly specified in the singular context i.e. 'bareword identifier' & 'it' (c/w 'bareword identifiers') - thus the compiler is behaving according to spec. and invalidating what appears to be a bareword list.

    I wonder if it's down to the single quoting, by the compiler, of single barewords within braces i.e. a hash key context consider the following 2 equivalent statements: $hash{key} = 'some val'; & $hash{'key'} = 'some val'; - equivalent since the single quotes around the key, in the former, are inserted (if not already there) by the compiler.

    As we all know, the compiler doesn't do any auto-quoting of list values (if not already quoted) - because it [the compiler] doesn't (and can't??) 2nd guess what the author intended - hence the behaviour is entirely both determinstic & consistent.

    </10 penn'orth>

    A user level that continues to overstate my experience :-))
Re: Unquoted hash slice keys with use strict 'subs'
by ikegami (Patriarch) on Oct 14, 2009 at 14:33 UTC

    Why didn't you complain about the following not working?

    my %hash = (k1, v1, k2, v2, k3, v3);

    The difference between $hash{k1} and @hash{k1,k2,k3} is the difference between the use the comma operator ((k1,k2,k3)) and the use of a hash element lookup ($h{k}), not between one and many keys.

    The comma operator does not autoquote.

    The ability to differentiate between functions calls and string literals is valuable, and what you suggested would remove that ability

    print(k1, k2, k3);

    could mean

    print('k1', k2(), 'k3');

    and there'd be no easy way to find out. You specifically requested to prevent this kind of ambiguity using use strict.

    In some cases, omitting the quotes is deemed unambiguous. That would not be the case for the comma operator's operands.

Re: Unquoted hash slice keys with use strict 'subs'
by ikegami (Patriarch) on Oct 14, 2009 at 17:22 UTC

    Documentation for strict 'subs' states: ... generating a compile-time error if you try to use a bareword identifier that's not a subroutine, unless it ... appears in curly braces...

    Thanks for your reply. I still think it is inconsistent

    It's not. The barewords don't appear in curly braces, they appear in a list.

    $ perl -c -e'use strict; my %h; $h{foo}' -e syntax OK $ perl -c -e'use strict; my %h; $h{map $_, foo}' Bareword "foo" not allowed while "strict subs" in use at -e line 1. -e had compilation errors. $ perl -c -e'use strict; my %h; $h{f(foo)}' Bareword "foo" not allowed while "strict subs" in use at -e line 1. -e had compilation errors. $ perl -c -e'use strict; my %h; $h{foo,bar}' Bareword "foo" not allowed while "strict subs" in use at -e line 1. Bareword "bar" not allowed while "strict subs" in use at -e line 1. -e had compilation errors.