views:

284

answers:

10

I'm just starting out with Perl (literally today) and I'm reading the free online version of Beginning Perl. Early on, the book mentioned that double quoted strings will be interpolated. However, in every example using the print function (so far... I'm around page 66), the author is passing scalar variables as a list parameter. Maybe I'm jumping the gun and this will be explained later, but is there any reason to choose method A over method B?

Method A:

$myVar = "value";
print "Current value is ", $myVar, "\n";

Method B:

$myVar = "value";
print "Current value is $myVar\n";

In my opinion, method B is more convenient. Is there a preferred way in the community? Or maybe some hidden gotchas that make one method safer to use over the other etc.?

TIA

+1  A: 

(This should probably be community wiki.)

The only obvious issue that comes to my mind is the interpolation of arrays. Compare

print @arr, "\n";

with

print "@arr\n";

Also, sometimes complicated dereferencing don't work well with interpolation, but those are kind of rare.

Leonardo Herrera
I'll mark it as a wiki.
Jason Down
+3  A: 

If you're reaching for Perl, then you're looking for the quickest way to get things done. You are, furthermore, encouraged to do it in the way that is most like your way of thinking (hence the Perl motto: TMTOWTDI, There's More Than One Way To Do It). Therefore: whichever way is easier for you to write, whichever way you're most likely to understand when you come back to the code later, is the way you should do it (all other things, such as giving the intended result, being equal).

If you're concerned about "safety", as you suggest, then learn about tainting, which helps protect you from potentially mischievous data from the outside world.

Jonathan Feinberg
+10  A: 

In a simple example such as this, no.. but consider if $myVar was actually something more complicated, such as a deep dereferencing of a hash reference, or a method call. Some things interpolate inside strings (most object references do), but method calls don't. Also arrays do different things when printed out directly vs. interpolated into a string.

PS. Welcome to Perl; please enjoy the journey! :)

Ether
Thanks. It's been on my to-learn list for quite a while... finally getting around to it.
Jason Down
+4  A: 

Method A should be:

$myVar = "value";
print 'Current value is ', $myVar, "\n";

When you single-quote a string, Perl doesn't bother reading the whole thing looking for things to interpolate, so if you have a long string that doesn't need interpolation, it may be faster to use single quotes and append the dynamic parts, like above.

However, this is a micro-optimization that doesn't really make a huge difference.

Another case for using Method A is if the string contains escape characters that you don't want to bother escaping:

$myVar = 12000;
print 'Conversion from $US to $CND: ', $myVar,\n";

In this case, you don't want Perl to look for the $US and $CND variables, you just want the string to have the dollar sign in it.

In the end, it's mostly a matter of style. I usually try to avoid double-quoted strings unless I need them.

Ben S
print "x", $y, "z" is actually different from print "x" . $y . "z" which is the same as print "x${y}z" after the compiler had a go. The first variant is passing three arguments to print. The two others pass just one. But you're right: Effectively, it doesn't make a difference in just about any situation.
tsee
Almost...if $, is set, then it might not be the same. But most people don't mess with $, anyway. :)
Robert P
+1  A: 

As a Perl outsider who is not familiar with any perl-specific editors and their highlighting powers, I vote for using single quotes whenever possible. This makes it clearer to the reader, that this string contains nothing that will be interpolated in any way.

mxp
Many cross-language IDE and editors will highlight Perl. For ex., any Scintilla-based.
Alexandr Ciornii
I use syntax highlighting in vim and I still use single quotes almost everywhere. It's a good way of indicating to the reader "I don't intend there to be any interpolation here", and fewer characters need to be escaped (generally just \ and ').
Ether
+9  A: 

There definitely are hidden gotchas -- perl will deal with simple variable names, and expressions like

"$array[$subscript]"

and

"$hashref->{key}"

without any problems. As your expressions get more and more complicated, though, eventually perl will not be able to tell where your expression stops and the remainder of your string starts.

There are lots of gory details in this paper Variable Interpolation in Double-Quoted Strings

Ian Clelland
Thanks for the link...
Jason Down
+10  A: 

There's the ' gotcha:

$owner = "John";
$item = "motorcycle".
print "This is $owner's $item.\n";  # Oops, parsed as $owner::s

but the above can be safely written as

print "This is ${owner}'s $item.\n";
mobrule
... or `print "This is ", $owner, "'s $item.\n";
Brad Gilbert
+2  A: 

since we are talking about interpolation gotchas, its worth mentioning that if you are using single quoted strings to avoid interpolation, you still will need to escape a trailing slash:

'c:\files\'  #parse error
'c:\files\\' #correct

this is because the final character of the first string looks like an escaped single quote, rather than the string terminator. also an escaped slash will be converted to a single slash in single quoted strings

Eric Strom
IF you have that data in a variable, you don't need the extra slashes to get it to interpolate correctly. This isn't really an interpolation problem though, since even as your examples show it happens with single-quoted (non-interpolated) strings too.
brian d foy
+9  A: 

There are several things to watch out for with interpolation, although once you know about them, you hardly ever do them by mistake.

Putting a variable name next to valid identifier text. Perl finds the longest valid variable name and doesn't care if it is previously defined. You can set off the variable name portion with braces to be explicit:

  my $p = 'p';
  print "Mind your $ps and qs\n";  # $ps, not $p

  print "Mind your ${p}s and qs";  # now its $p

Now, in that example, I forgot the apostrophe. If I add it, I have another problem since the apostrophe used to be the package separator from the old days and it still works. The braces work there too:

  my $p = 'p';
  print "Mind your $p's and q's\n";  # $p::s, not $p

  print "Mind your ${p}'s and q's";  # now its $p

Perl can also interpolate single element accesses to hashes and arrays, so putting indexing characters next to a variable name might do something you don't want:

 print "The values are $string[$foo]\n";  That's the element at index $foo
 print "The values are $string{$foo}\n";  That's the value for the key $foo

When you want an email address in a string, you might forget Perl interpolates arrays. Perl used to make that a fatal error unless you escaped the @:

 print "Send me mail at [email protected]\n";  # interpolates @example

 print "Send me mail at joe\@example.com\n";

Since Perl uses the backslash to escape some characters, you need to double up those when you want a literal one:

 print "C:\real\tools\for\new\work";      # not what you might expect

 print "C:\\real\\tools\\for\\new\\work"; # kinda ugly, but that's life
 print "C:/real/tools/for/new/work";      # Windows still understands this

Despite these minor gotchas, I really miss the ease with which I can construct strings in Perl if I have to use another language.

brian d foy
The gotchas with interpolation are one more good reason for using `strict` and `warnings`. If you make an error like `my $p = 'p'; print "$ps and qs";` `strict` will pitch a compile time fit. If you make the `'` error, `warnings` will tell you that you are using an undefined value.
daotoad
There's also a specific warning "Possible unintended interpolation of @example" if you accidentally write `print "[email protected]"` with warnings on. Unless you were unlucky enough to have an array `@example` in scope, anyway.
hobbs
A: 

Interpolation is a great simplifier and time saver. But it is possible to go too far.

You can do some bizarre stuff with interpolation if you want to.

@foo = 0..10;
print "$foo[2*3]"; # prints 6

And for exciting arbitrary interpolation you can use this abomination:

print "@{[ some_function_call('in list context') ]}";

If you really, really want to make interpolated function calls work, there is a module for that. Check out Interpolation. It lets you do stuff like this:

use Interpolation;
print "I like $eval{ what_I_like() };

sub what_like_like {
    return 'pie';
}

And much, much more.

For background on this module, see Identity.pm: A Very Funny Module and Interpolation.

daotoad