Search code examples
perlsyntaxlanguage-lawyerpunctuationbareword

Why are leading-hyphen options permitted on `use` lines without fat comma and with strict?


Why is the following use line legal Perl syntax? (Adapted from the POD for parent; tested on Perl 5.26.2 x64 on Cygwin.)

package MyHash;
use strict;
use Tie::Hash;
use parent -norequire, "Tie::StdHash";
       #   ^^^^^^^^^^ A bareword with nothing to protect it!

Under -MO=Deparse, the use line becomes

use parent ('-norequire', 'Tie::StdHash');

but I can't tell from the use docs where the quoting on -norequire comes from.

  • If use strict were not in force, I would understand it. The bareword norequire would become the string "norequire", the unary minus would turn that string into "-bareword", and the resulting string would go into the use import list. For example:

    package MyHash;
    use Tie::Hash;
    use parent -norequire, "Tie::StdHash";
    
  • Similarly, if there were a fat comma, I would understand it. -foo => bar becomes "-foo", bar because => turns foo into "foo", and then the unary minus works its magic again. For example:

    package MyHash;
    use strict;
    use Tie::Hash;
    use parent -norequire => "Tie::StdHash";
    

Both of those examples produce the same deparse for the use line. However, both have quoting that the original example does not. What am I missing that makes the original example (with strict, without =>) legal? Thanks!


Solution

  • You already cited perldoc perlop, but it is relevant here.

    Unary - performs arithmetic negation if the operand is numeric, including any string that looks like a number. If the operand is an identifier, a string consisting of a minus sign concatenated with the identifier is returned. ... One effect of these rules is that -bareword is equivalent to the string "-bareword".

    This behavior of the unary minus operator is applied to the bareword before the strict checks are applied. Therefore, unary minus is a kind of quoting operator that also works in strict mode.

    Similarly, barewords as the invocant in method invocation do not need to be quoted as long as they are not a function call:

    Foo->bar;    # 'Foo'->bar(); --- but only if no sub Foo exists
    print->bar;  # print($_)->bar();
    

    However, the unary minus behaviour seems to be due to constant folding, not due to a special case in the parser. For example, this code

    use strict;
    0 ? foo : bar;
    

    will only complain about the bareword "bar" being disallowed, suggesting that the bareword check happens very late during parsing and compilation. In the unary minus case, the bareword will already have been constant-folded into a proper string value at that point, and no bareword remains visible.

    While this is arguably buggy, it is also impossible to change without breaking backwards compatibility – and this behaviour is used by many modules such as use parent to communicate options. Compare also similar idioms on command line interfaces, where options usually begin with a dash.