Reputation:
I've stumbled upon something odd with Perl string parsing. Here's an example:
$word = "hello";
$test1 = "colon:values::$word:test";
$test2 = "colon:values::$word::test";
// test1 prints: "colon:values::hello:test"
// test2 prints: "colon:values::"
So if Perl sees a double colon after a variable in a string, it will (I assume) think you're trying to use a package name. I guess it's trying to load "Hello::test" and not finding anything - hence the early termination of the string.
Is this normal? I find it pretty counter-intuitive. I was able to work around it by escaping the first colon like so:
$works = "colon:values::$word\::test";
Is this a bug or am I completely missing something obvious?
Upvotes: 4
Views: 1134
Reputation: 6642
While that works, a more widespread way to handle the case is to disambiguate the name of your variable with braces:
perl -E "my $word = 'red'; say qq|colon::values::${word}::test|"
colon::values::red::test
This is documented in perldata:
As in some shells, you can enclose the variable name in braces to disambiguate it from following alphanumerics (and underscores). You must also do this when interpolating a variable into a string to separate the variable name from a following double-colon or an apostrophe, since these would be otherwise treated as a package separator:
$who = "Larry"; print PASSWD "${who}::0:0:Superuser:/:/bin/perl\n"; print "We use ${who}speak when ${who}'s here.\n";
Without the braces, Perl would have looked for a
$whospeak
, a$who::0
, and a$who's
variable. The last two would be the$0
and the$s
variables in the (presumably) non-existent packagewho
.
Upvotes: 9
Reputation: 107080
Perl uses namespaces for variable names, and Perl when Perl sees ::
or a '
, it assumes what's before is a package (i.e. namespace) name. It is similar to this error:
use strict;
use warnings; # You're using these? Aren't you?
my $foo = "bar"
print "The magic word is $foo_for_you\n";
Since the underscore is a valid character for variable names, Perl assumes that you want the variable $foo_for_you
and not $foo
with _for_you
appended to the value. So, would you consider this a bug or a feature? Is it any difference from this:
print "The magic word is $foobar\n"; # Whoops! my variable is $foo.
The way to get around this is to make it absolutely clear that $foo
is your variable:
print "The magic word is " . $foo . "_for_you\n";
printf "The magic word is %s_for_you\n", $foo;
print "The magic word is ${foo}_for_you\n";
The same issue if you had $foo::for::you
(or $foo'for'you
) In this case, Perl is looking for a variable called $you
in the namespace foo::for
. As you can imagine, you can use similar solutions:
print "The magic word is " . $foo . "::for::you\n";
printf "The magic word is %d::for::you\n", $foo;
print "The magic word is ${foo}::for::you\n";
Namespaces are used to help keep variables in Perl modules from modifying variables in your program. Imagine calling a function in a Perl package, and suddenly discovering that a variable you were using in your program was changed.
Take a look at File::Find and you can see variables with the package namespace attached to them ($File::Find::name
and $File::Find::dir
are two examples).
Upvotes: 1
Reputation: 9969
The reason this is happening is because it's trying to look up $word::test
as a variable name. As you've correctly deduced, the package separator ::
is part of the name, but it's not going to follow the value of $word
because it's not being used as a symbolic reference here (that requires more syntax).
Oesor's solution will solve your problem - the general way to fix this kind of issue is to use ${identifier}
syntax. Basically use it any time you're interpolating a variable into a string and you need to follow it with something that's a valid identifier character or related symbol (i.e. ::
).
Upvotes: 3