Ambiguous use of -CONSTANT resolved as -&CONSTANT() - perl

I'm trying to declare magic numbers as constants in my Perl scripts, as described in perlsub. However, I get warnings:
$ cat foo.perl
use warnings ; use strict ;
sub CONSTANT() { 5 }
print 7-CONSTANT,"\n" ;
$ perl foo.perl
Ambiguous use of -CONSTANT resolved as -&CONSTANT() at foo.perl line 3.
2
$
The warning goes away if I insert a space between the minus and the CONSTANT. It makes the expressions more airy than I'd like, but it works.
I'm curious, though: What is the ambiguity it's warning me about? I don't know any other way it could be parsed.
(Perl 5.10.1 from Debian "squeeze").

First, some background. Let's look at the following for a second:
$_ = -foo;
-foo is a string literal[1].
$ perl -Mstrict -wE'say -foo;'
-foo
Except if a sub named foo has been declared.
$ perl -Mstrict -wE'sub foo { 123 } say -foo;'
Ambiguous use of -foo resolved as -&foo() at -e line 1.
-123
Now back to your question. The warning is wrong. A TERM (7) cannot be followed by another TERM, so - can't be the start of a string literal or a unary minus operator. It must be the subtraction operator, so there is no ambiguity.
This warning is still issued in 5.20.0[2]. I have filed a bug report.
Look ma! No quotes!
system(grep => ( -R, $pat, $qfn ));
Well, 5.20.0 isn't out yet, but we're in a code freeze running up to its release. This won't be fixed in 5.20.0.

mpapec's answer helpfully referenced perldiag (which I wasn't aware of) but quoted the wrong diagnostic. The one I'm actually getting is
Ambiguous use of -%s resolved as -&%s()
(S ambiguous) You wrote something like -foo, which might be the string "-foo", or a call to the function foo, negated. If you meant the string, just write "-foo". If you meant the function call, write -foo().
So apparently the point is that -CONSTANT is a valid bareword. I didn't know they could start with dashes.
I still don't really understand why that would give a warning here, given that (a) I'm using strict subs so obviously I'm not going to throw around barewords deliberately, and (b) even if I were, a bareword or string in this position would be a syntax error anyway.
Edit: As pointed out (more or less) by tobyink, it is not actually that -CONSTANT in itself is a bareword, but that strict subs still allows barewords after the unary minus operator. Apparently the lexer isn't context-aware enough to know that parsing -CONSTANT as an unary minus is not allowed in this context.
Still feels strange to me -- one would expect the effect of prototyping a sub with no arguments ought to be that I deliberately forfeit using that name as a bareword, no matter whether it happens to be as the operand to unary minus or in a different context.

Related

What is the "once" warnings in perl?

I have code that has,
no warnings 'once';
Reading man warnings I don't see an occurrence of /once/ what does this do?
So long as you don't have strict on, perl allows you to use a variable without declaring it.
perl -wE'$foo = 4;'
Which outputs,
Name main::foo used only once: possible typo at -e line 1.
Note under strict this wouldn't even be permitted,
Global symbol $foo requires explicit package name (did you forget to declare my $foo?) at -e line 1.
You can disable the warning though, without enabling strict by doing no warnings "once"; Though I would suggest strongly you simply remove the unused code instead of silencing the warning.
perl -wE'no warnings "once"; $foo = 4;'
Which both looks ugly and does nothing.
If you run the following you will trigger the warning, plus a little extra explanation:
perl -Mdiagnostics -Mwarnings -e '$foo=1'
The output will be:
Name "main::foo" used only once: possible typo at -e line 1 (#1)
(W once) Typographical errors often show up as unique variable names.
If you had a good reason for having a unique name, then just mention it
again somehow to suppress the message. The our declaration is
provided for this purpose.
NOTE: This warning detects symbols that have been used only once so $c, #c,
%c, *c, &c, sub c{}, c(), and c (the filehandle or format) are considered
the same; if a program uses $c only once but also uses any of the others it
The warning applies to symbol table entries (not "my" lexical variables). If you add -Mstrict to the above, you'll create a strict violation because your variable violates strict 'vars', which prohibits you using a variable that hasn't been declared, with the exception of package globals referred to by their fully-qualified name. If you were to pre-declare $foo with our, the warning goes away:
perl -Mdiagnostics -Mwarnings -Mstrict=vars -E 'our $foo=1'
This works just fine; it avoids a strict violation, and avoids the "once" warning. So the purpose of the warning is to alert you to the use of identifiers that are not declared, not using a fully-qualified name, and also only used once. The objective is to help prevent typos in symbol names, the assumption being that if you use a symbol name only once and have not declared it, it may be a mistake.
Special (punctuation) variables are exempted from this check. You can, therefore, refer to $_ or $/ only once and not trigger a warning. Also, $a and $b are exempt because they are considered special, for use in sort {$a <=> $b} #list; in such constructs they may appear only a single time yet it wouldn't be useful to raise a warning for what is fairly typical code.
You can find the 'once' warning listed in the Warnings Hierarchy here: perldoc warnings.
A list of all diagnostic blurbs is available in perldoc perldiag.

Make Perl warn me about missing unused functions [duplicate]

This question already has answers here:
How do I get perl -c to throw Undefined or Undeclared function errors?
(4 answers)
Closed 8 years ago.
perl -wle 'if (0) {no_such_func()}'
The above runs without errors, despite the -w, because no_such_func()
is never called.
How do I make Perl check all functions/modules I reference, even ones
I don't use?
In a more realistic case, some functions may only be called in special
cases, but I'd still like to make sure they exist.
EDIT: I installed perlcritic, but I think I'm still doing something wrong. I created this file:
#!/bin/perl -w
use strict;
if (0) {no_such_func();}
and perlcritic said it was fine ("source OK"). Surely static analysis could catch the non-existence of no_such_func()? The program also runs fine (and produces no output).
You can't do it because Perl doesn't see if functions exist until runtime. It can't. Consider a function that only gets evaled into existence:
eval 'sub foo { return $_[0]+1 }';
That line of code will create a subroutine at runtime.
Or consider that Perl can use symbolic references
my $func = 'func';
$func = "no_such_" . $func;
&$func;
In that case, it's calling your no_such_func function, but you can't tell via static analysis.
BTW, if you want to find functions that are never referenced, at least via static analysis, then you can use a tool like Perl::Critic. See http://perlcritic.com/ or install Perl::Critic from CPAN.
Hmm, this is difficult: When Perl parses a function call, it doesn't always know whether that function will exist. This is the case when a function is called before it's declared:
foo();
sub foo { say 42 }
Sometimes, the function may only be made available during runtime:
my $bar = sub { say 42 };
my $baz = sub { say "" };
*foo = rand > 0.5 ? $bar : $baz;
foo();
(I'd like to mention the “Only perl can parse Perl” meme at this point.)
I'm sure you could hack the perl internals to complain when the function can't be resolved before run time, but this is not really useful considering the use cases above.
You can force compile-time checks if you call all subs without parentheses. So the following will fail:
$ perl -e 'use strict; my $condvar; if ($condvar) {no_such_func}'
Bareword "no_such_func" not allowed while "strict subs" in use at -e line 1.
Execution of -e aborted due to compilation errors.
(However, it does not fail if you write if (0), it seems that perl's optimizer is removing the whole block without checking any further)
This has the consequence that you have to define all subroutines before using them. If you work like this, then sometimes "forward" declarations are necessary. But then it's possible that a forward declaration never gets a definition, which is another possible error case.

What is the meaning of the double 'at' (##) in Perl?

I am reviewing a proposed vendor-supplied patch to a Perl tool we use and I'm struggling to identify the reason for a particular type of change - the pre-pending of an '#' to the parameters passed to a subroutine.
For instance, a line that was:
my ($genfd) = #_;
Is now:
my ($genfd) = ##_;
Not being a Perl developer, I'm learning on the go here, but so far I understand that '#_' is the parameters supplied to the enclosing subroutine.
I also understand the assignment above (where the '$genfd' is wrapped in parentheses on the left-hand side) casts '#_' to a list and then assign the 'genfd' scalar variable to the first element of that list. This should result in the first parameter to the subroutine being stored in 'genfd'.
What I am completely stuck on is what difference the second '#' makes. I've found examples of this usage on GitHub but never with an explanation, nor can I find an explanation on any Perl references or SO. Any help would be much appreciated.
Looks like a bad patch.
##_ is a syntax error. At least, when I have the following Perl source file:
#!/usr/bin/perl
use strict;
use warnings;
sub foo {
my ($genfd) = ##_;
}
running perl -cw on it (with Perl 5.14.2) gives:
Bareword found where operator expected at tmp.pl line 7, near "##_"
(Missing operator before _?)
syntax error at tmp.pl line 7, near "##_"
tmp.pl had compilation errors.
I haven't looked at all the examples on GitHub, but many of them are in files with a ,v suffix. That suffix is used by RCS and CVS for their internal version control files. I think the # character has some special meaning, so it's doubled to denote a literal # character. (Yes, it's a bit odd to have RCS or CVS internal files in a Git repository.)
Some kind of RCS or CVS interaction is the most likely explanation for the error, but there could be other causes.
You should ask the person who provided the patch.

Disable Perl warnings for missing qw outer parentheses

Since upgrading Debian recently I've had Perl whining about not having extra parentheses around the qw operator.
As a Systems Administrator this is unacceptable. It is breaking mod_perl applications left, right, and centre.
How can I run Perl with this warning disabled? Is there a flag I can run with the Perl interpreter? Note that editing source is not an option.
This changed in Perl 5.14 - see perldelta.
Use of qw(...) as parentheses
Historically the parser fooled itself into thinking that qw(...)
literals were always enclosed in parentheses, and as a result you
could sometimes omit parentheses around them:
for $x qw(a b c) { ... }
The parser no longer lies to itself in this way. Wrap the list literal
in parentheses like this:
for $x (qw(a b c)) { ... }
This is being deprecated because the parentheses in for $i (1,2,3) {
... } are not part of expression syntax. They are part of the
statement syntax, with the for statement wanting literal parentheses.
The synthetic parentheses that a qw expression acquired were only
intended to be treated as part of expression syntax.
Looks like you can turn the warnings off with no warnings 'qw' but you'd be far better off fixing the code.
As a system administrator I find bad code unacceptable.
The best answer, of course, is to fix the offending perl scripts.
If your business won't let you fix the offending perl scripts, then don't upgrade Debian.
You have risks either way.

Why is parenthesis optional only after sub declaration?

(Assume use strict; use warnings; throughout this question.)
I am exploring the usage of sub.
sub bb { print #_; }
bb 'a';
This works as expected. The parenthesis is optional, like with many other functions, like print, open etc.
However, this causes a compilation error:
bb 'a';
sub bb { print #_; }
String found where operator expected at t13.pl line 4, near "bb 'a'"
(Do you need to predeclare bb?)
syntax error at t13.pl line 4, near "bb 'a'"
Execution of t13.pl aborted due to compilation errors.
But this does not:
bb('a');
sub bb { print #_; }
Similarly, a sub without args, such as:
special_print;
my special_print { print $some_stuff }
Will cause this error:
Bareword "special_print" not allowed while "strict subs" in use at t13.pl line 6.
Execution of t13.pl aborted due to compilation errors.
Ways to alleviate this particular error is:
Put & before the sub name, e.g. &special_print
Put empty parenthesis after sub name, e.g. special_print()
Predeclare special_print with sub special_print at the top of the script.
Call special_print after the sub declaration.
My question is, why this special treatment? If I can use a sub globally within the script, why can't I use it any way I want it? Is there a logic to sub being implemented this way?
ETA: I know how I can fix it. I want to know the logic behind this.
I think what you are missing is that Perl uses a strictly one-pass parser. It does not scan the file for subroutines, and then go back and compile the rest. Knowing this, the following describes how the one pass parse system works:
In Perl, the sub NAME syntax for declaring a subroutine is equivalent to the following:
sub name {...} === BEGIN {*name = sub {...}}
This means that the sub NAME syntax has a compile time effect. When Perl is parsing source code, it is working with a current set of declarations. By default, the set is the builtin functions. Since Perl already knows about these, it lets you omit the parenthesis.
As soon as the compiler hits a BEGIN block, it compiles the inside of the block using the current rule set, and then immediately executes the block. If anything in that block changes the rule set (such as adding a subroutine to the current namespace), those new rules will be in effect for the remainder of the parse.
Without a predeclared rule, an identifier will be interpreted as follows:
bareword === 'bareword' # a string
bareword LIST === syntax error, missing ','
bareword() === &bareword() # runtime execution of &bareword
&bareword === &bareword # same
&bareword() === &bareword() # same
When using strict and warnings as you have stated, barewords will not be converted into strings, so the first example is a syntax error.
When predeclared with any of the following:
sub bareword;
use subs 'bareword';
sub bareword {...}
BEGIN {*bareword = sub {...}}
Then the identifier will be interpreted as follows:
bareword === &bareword() # compile time binding to &bareword
bareword LIST === &bareword(LIST) # same
bareword() === &bareword() # same
&bareword === &bareword # same
&bareword() === &bareword() # same
So in order for the first example to not be a syntax error, one of the preceding subroutine declarations must be seen first.
As to the why behind all of this, Perl has a lot of legacy. One of the goals in developing Perl was complete backwards compatibility. A script that works in Perl 1 still works in Perl 5. Because of this, it is not possible to change the rules surrounding bareword parsing.
That said, you will be hard pressed to find a language that is more flexible in the ways it lets you call subroutines. This allows you to find the method that works best for you. In my own code, if I need to call a subroutine before it has been declared, I usually use name(...), but if that subroutine has a prototype, I will call it as &name(...) (and you will get a warning "subroutine called too early to check prototype" if you don't call it this way).
The best answer I can come up with is that's the way Perl is written. It's not a satisfying answer, but in the end, it's the truth. Perl 6 (if it ever comes out) won't have this limitation.
Perl has a lot of crud and cruft from five different versions of the language. Perl 4 and Perl 5 did some major changes which can cause problems with earlier programs written in a free flowing manner.
Because of the long history, and the various ways Perl has and can work, it can be difficult for Perl to understand what's going on. When you have this:
b $a, $c;
Perl has no way of knowing if b is a string and is simply a bareword (which was allowed in Perl 4) or if b is a function. If b is a function, it should be stored in the symbol table as the rest of the program is parsed. If b isn't a subroutine, you shouldn't put it in the symbol table.
When the Perl compiler sees this:
b($a, $c);
It doesn't know what the function b does, but it at least knows it's a function and can store it in the symbol table waiting for the definition to come later.
When you pre-declare your function, Perl can see this:
sub b; #Or use subs qw(b); will also work.
b $a, $c;
and know that b is a function. It might not know what the function does, but there's now a symbol table entry for b as a function.
One of the reasons for Perl 6 is to remove much of the baggage left from the older versions of Perl and to remove strange things like this.
By the way, never ever use Perl Prototypes to get around this limitation. Use use subs or predeclare a blank subroutine. Don't use prototypes.
Parentheses are optional only if the subroutine has been predeclared. This is documented in perlsub.
Perl needs to know at compile time whether the bareword is a subroutine name or a string literal. If you use parentheses, Perl will guess that it's a subroutine name. Otherwise you need to provide this information beforehand (e.g. using subs).
The reason is that Larry Wall is a linguist, not a computer scientist.
Computer scientist: The grammar of the language should be as simple & clear as possible.
Avoids complexity in the compiler
Eliminates sources of ambiguity
Larry Wall: People work differently from compilers. The language should serve the programmer, not the compiler. See also Larry Wall's outline of the three virtues of a programmer.