3

Given code like this, I get no warning whatsoever.

use strict;
use warnings;
open STDERR, '>&', STDOUT;

Given this code, I get a fatal error.

use strict;
use warnings;
use autodie;
open STDERR, '>&', STDOUT;

Bareword "STDOUT" not allowed while "strict subs" in use at ./test.pl line 6. Execution of ./test.pl aborted due to compilation errors.

Why is autodie pointing at strict subs as being the source of this error -- when clearly strict was on in the first example and I had no error.

With diagnostics the error is explained like this..

Bareword "STDOUT" not allowed while "strict subs" in use at ./test.pl line 7. Execution of ./test.pl aborted due to compilation errors (#1) (F) With "strict subs" in use, a bareword is only allowed as a subroutine identifier, in curly brackets or to the left of the "=>" symbol. Perhaps you need to predeclare a subroutine?

This can all be resolved by doing

open STDERR, '>&', *STDOUT;

Then it's not a bareword, but why is the bareword special cased for open without autodie, and not with autodie? Is something else happening here?

Evan Carroll
  • 78,363
  • 46
  • 261
  • 468
  • 3
    Because autodie replaces the built in with a regular Perl function that does not have the same *parser* special cases. – Grinnz Jan 22 '20 at 22:31
  • 5
    This is one of the arguments against using `autodie`. It has edge cases that people don't expect. In many cases, I don't think the tradeoff is worth it, especially when I want to provide a useful error message to a user instead a technical detail message to a programmer. – brian d foy Jan 22 '20 at 23:22

1 Answers1

8

autodie achieves its task by exporting a sub named open that Perl uses in favour of the open operator.

$ perl -MO=Concise,-exec -e'             open(my $fh, "<", "foo")'
...
8  <@> open[t3] vK/3
...

$ perl -MO=Concise,-exec -e'use autodie; open(my $fh, "<", "foo")'
...
7  <#> gv[*open] s
8  <1> entersub vKS
...

The open operator has special parsing rules that can't be replicated by a prototype[1], so the open operator can't be accurately replicated by a sub. This accounts for the observed difference.


  1. Normally, prototype("CORE::opname") returns undefined for such operators, but prototype("CORE::open") inaccurately reports that open's parsing rules are equivalent to the *;$@ prototype.
ikegami
  • 367,544
  • 15
  • 269
  • 518
  • Is this because regular functions can not accept barewords? But they can accept typeglobs? If so, if you want to add that to your first sentence I'll mark it accepted. Otherwise I'm not sure I'm following and would like to know why `open` is special (or if it's that `STDOUT` is special. Is `STDOUT` always more properly `*STDOUT` are they different? – Evan Carroll Feb 14 '21 at 05:26
  • In the usage in question, `open` accepts a bareword because the previous argument is `>&`. Were the second argument `>`, a bareword wouldn't be accepted (under `use strict`). This conditional behaviour can't be replicated by a prototype. – ikegami Feb 14 '21 at 10:15