Item 58: Use or a tied hash to evaluate expressions inside strings.


Item 58: Use @{[ ]} or a tied hash to evaluate expressions inside strings.

Double-quote interpolation works just fine for variables , slices, and the like:

 $name = "Bingo";  print "$name was his name-o\n"; 

Prints:

Bingo was his name-o

 @n = 0..10;  print "Fahrenheit @n[5, 6, 2]\n"; 

Prints:

Fahrenheit 4 5 1

It even works for reference syntax and objects:

 $who->{f} = 'Tiger';  $who->{l} = 'Woods';  print "I'm $who->{f} $who->{l}\n"; 

Prints:

I'm Tiger Woods

However, double-quote interpolation does not work for subroutine calls and other types of expressions. For example, after seeing the above work, you might try:

 package golf;  sub new { bless {} };  sub name { 'Tiger Woods' }; 
 
 package main;  $golfer = new golf;  $name = $golfer->name;  print "I'm $name\n";  print "I'm $golfer->name\n"; 

Prints:

I'm Tiger Woods

I'm golf=HASH(0xabc50)->name

Here, only the scalar variable part, $golfer , of $golfer->name is interpolated into the double-quoted string, and the result is probably not what was desired. You can work around this with a strange bit of Perl syntax. Just combine the anonymous array constructor [ ] with the dereferencing syntax for arrays:

Continued from above:

 print "I'm @{[$golfer->name]}\n"; 

I'm Tiger Woods

It's U.B.E.: Ugly But Effective.

Even if the syntax is ugly, this construct can be very helpful when you are trying to put together a long here doc string, but discover that you need to interpolate some sort of expression in the middle of it:

 $a = 2; $b = 3;  print <<EOT;  Here are the answers:  $a + $b is @{[$a + $b]}  $a * $b is @{[$a * $b]}  EOT 

This isn't a particularly inspired example, but if you've ever used a here doc string to generate HTML in CGI script, you've probably come across a more compelling situation.

There is another alternative, which may or may not seem simpler to you. It does, however, eliminate some more punctuation. You can use a tied hash (see Item 52):

 sub Print::TIEHASH    { bless \ my $thingy, shift() }  sub Print::FETCH    { $_[1] }  tie %print, Print;  $a = 2; $b = 3;  print <<EOT;  Here are the answers:  $a + $b is $print{$a + $b}  $a * $b is $print{$a * $b}  EOT 

Note that in this case the inside of $print{} is a scalar context. You also can use a list inside @print{} , in which case the output will be separated by spaces, as usual. So what happens if you have a list to print, but you don't want spaces between the items? One possibility is changing the value of the $" special variable. I don't recommend this, but if you decide to go this route anyway, be sure to localize the damage, er, change:

 @digits = (1, 2, 3);  {    local $" = "";    print "Testing @digits\n";  } 

Output separator is "" now.

testing 123 no spaces.

If you don't mind a more complicated syntax, you can return to the tied variable. Let's modify the example so that we can specify a "glue" string. We have to use a reference to an array as a subscript to make this work, so we're back to the anonymous array constructor again:

 sub SepPrint::TIEHASH {    my $class = shift;    bless {sep => shift}, $class  }  sub SepPrint::FETCH {    my $self = shift;    join $self->{sep}, @{shift()}  } 
 
 tie %comma, SepPrint, ", ";  tie %colon, SepPrint, ":"; 
 
 print <<EOT;  Here are the answers:  Testing $comma{[1, 2, 3]}  Testing $colon{[1, 2, 3]}  EOT 

Testing 1, 2, 3

Testing 1:2:3



Effective Perl Programming. Writing Better Programs with Perl
Effective Perl Programming: Writing Better Programs with Perl
ISBN: 0201419750
EAN: 2147483647
Year: 1996
Pages: 116

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net