Why Perl ignores spaces between a sigil and variable name? - perl

The question Is space supposed to be ignored between a sigil and its variable name? was answered positively.
What is the reason Perl interprets $ foo as $foo?
perl -w -E 'my $ foo = $$; say "Perl $]\n\$ foo = ", $foo'
Perl 5.028001
$ foo = 3492
Isn't it against The Syntax of Variable Names documentation?

That documentation only discusses the name, not the sigil. The sigil can always be separated from the name by space characters. It is definitely underdocumented and I would not suggest ever making use of it, but it is used.

Perl does not have sigils, it has "dereference" operators:
$test[1] means 'give me the scalar at the index 1 of the array called "test" from this scope'. That is why you can put spaces after the "sigil".
I don't understand why everybody keeps calling them sigils, it makes things very confusing. BASIC had sigils, PHP has sigils, but Perl 5 does not even if it looks like it has. I wish I had realized the "sigils" are in fact operators when I was learning Perl, understanding and parsing references and derefferencing would have been a lot easier, not to mention grokking symbol tree manipulation.
The "sigils" are not documented as "operators" in perldoc, but it is much easier to parse Perl code if you think of them as being operators.
Later, after discussion in the comments: here is how Perl 5 uses "sigils": https://www.oreilly.com/library/view/advanced-perl-programming/0596004567/ch01.html

Related

Why use &getcwd() and not getcwd() in Perl?

I am new to Perl language, and in the code I am using there is this line :
$BASEDIR = &getcwd();
I am wondering why there is a & in front of the call to getcwd, and I could not find any reference about that. Could someone help me with this ?
Thanks a lot !
It causes the subroutine's prototype to be ignored.
$ perl -e'
sub f($#) { print("#_\n"); }
my #a = (4,5,6);
f(4,5,6);
f(#a);
&f(#a);
'
4 5 6
3
4 5 6
But that's probably not the reason it's used here. After all, Cwd::getcwd doesn't have a prototype. & can't be used on named operators (i.e. the functions of perlfunc, e.g. print), so some beginners use it on subroutines to distinguish them from operators. I believe this is a practice recommended by a popular Perl book.
Short answer is that it is optional unless you are running a really old version of perl.
For more detail see the perlsub man page (run perldoc perlsub or man perlsub depending on your environment)
A subroutine may be called using an explicit "&" prefix. The "&" is optional in modern Perl, as are parentheses if the subroutine has been predeclared. The "&" is not optional when just naming the subroutine, such as when it's used as an argument to defined() or undef(). Nor is it optional when you want to do an indirect subroutine call with a subroutine name or reference using the "&$subref()" or "&{$subref}()" constructs, although the "$subref->()" notation solves that problem. See perlref for more about all that.

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

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.

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.

How can I use the value of a variable as a variable name in Perl?

If I have a variable, $bar, which is equal to string "foo" and $foo is equal to 0xdead, how can I get $foo's value while I only have the the string for the variable name?
Essentially, I want to do a kind of pointer indirection on the global namespace or a hash lookup on the global namespace.
The following didn't work:
perl -e 'my $foo=0xdead; my $bar ="foo"; print ${$bar}."\n";'
It only prints the newline.
This trick works only with global variables (symbolic references seek the symbol table of the current package), i. e.
perl -e '$foo=0xdead; my $bar ="foo"; print ${$bar}."\n";'
If you want to catch lexicals, you'll have to use eval ""
perl -e 'my $foo=0xdead; my $bar ="foo"; print eval("\$$bar"),"\n";'
But using eval "" without purpose is considered bad style in Perl, as well as using global variables. Consider using real references (if you can).
There are very very very preciously few instances in Perl where you must use symbolic references. Avoiding symbolic references in all other instances is not about style. It is about being a smart programmer. As mjd explains in Why it's stupid to "use a variable as a variable name":
The real root of the problem code is: It's fragile. You're mingling unlike things when you do this. And if two of those unlike things happen to have the same name, they'll collide and you'll get the wrong answer. So you end up having a whole long list of names which you have to be careful not to reuse, and if you screw up, you get a very bizarre error. This is precisely the problem that namespaces were invented to solve, and that's just what a hash is: A portable namespace.
See also Part 2 and Part 3.
Without my and with $$bar works for me:
$ perl -e '$foo=0xdead;$bar ="foo"; print $$bar."\n";'
57005
You can find out more about using a variable as a variable name in the Perl FAQ List.

Are #{$list_ref} and #$list_ref equivalent in Perl?

I am new to Perl and am curious whether #{$list_ref} and #$list_ref are perfectly equivalent.
They seem to be interchangeable, but I am nervous that there is something subtle going on that I may be missing.
Yes, they're equivalent. You need braces when the expression is more than a simple scalar variable, e.g.,
push #{ $foo{$bar} } => "baz";
For more detail, see the Using References section of the documentation on references. The standard Perl documentation also includes several tutorials on using references:
Understand References Today (mentioned by hobbs in the question's comments)
Manipulating Arrays of Arrays in Perl
Perl Data Structures Cookbook
I've always found it helpful to remember that the outer braces are not syntactical magic, they're just a block that returns a reference. The expression inside the block can be anything that returns a reference:
$ perl -le 'sub foo {[qw/ apple orange banana /]} print ${print "Do something here."; foo()} [1]'
Do something here.
orange