Hash interpolation failure in string

Ovid on 2006-07-31T12:43:05

So a coworker wanted to know the syntax for getting hash interpolation to work. He had something similar to this:

print "value is $data{'value'}\n";

I assured him that would be fine but he said that he's been bitten by this before, even when using interpolated strings. So just to be sure, I wrote up a simple test. One test line fails. Without running that, can you guess which one and why?

#!/usr/bin/perl

use strict;
use warnings;
use Test::More tests => 6;

my %french_for = (
    one => 'un',
);

my $num = 'one';
is "$french_for{one}",      'un', 'bare literal key';
is "$french_for{'one'}",    'un', 'single quoted literal key';
is qq[$french_for{"one"}],  'un', 'double quoted literal key';
is "$french_for{$num}",     'un', 'bare variable key';
is "$french_for{'$num'}",   'un', 'single quoted variable key';
is qq[$french_for{"$num"}], 'un', 'double quoted variable key';

To be fair, I guess the failure isn't too surprising but in reading through perltrap, it doesn't appear to be documented. Is it documented and I just missed it?


Single quoted variable

Matts on 2006-07-31T12:52:09

Surely:

is "$french_for{'$num'}", 'un', 'single quoted variable key';

Will fail. You've single quoted '$num' hence you're looking for the key "\$num".

Re:Single quoted variable

Ovid on 2006-07-31T13:20:41

Yes, that's the failure, but I don't know why that should be obvious because if you add diag "'$num'" to the end of that script, you get this:

# 'one'

In other words, a variable in single quotes will interpolate if it's embedded in a double quoted string but not used as the key to a hash or an index into an array. That seems a bit odd and it would be nice if it were documented better. I should submit a patch for perltrap if it's not documented.

Re:Single quoted variable

Matts on 2006-07-31T13:39:28

I tend to consider hash interpolation as being outside of the string, even though it's embedded. I consider there to be an invisible ". and ." around it.

Re:Single quoted variable

Smylers on 2006-07-31T14:22:03

a variable in single quotes will interpolate if it's embedded in a double quoted string but not used as the key to a hash or an index into an array. That seems a bit odd

Actually what seemed odd to me was that the first example (with single quotes around the literal) worked OK. But given that, I did expect it to fail round a variable (as in I guessed what the failure would be before even seeing your list of choices).

Yes directly in a double-quoted string literal single quotes don't prevent a variable between them from being interpolated, but then those single quotes do do something: they end up in the output.

You've already established that single quotes inside a hash key inside double quotes are different from single quotes directly inside double quotes because they are not taken literally; the key was one, not 'one'.

So that shows that in that circumstance the quote marks are actually behaving like quote marks rather than merely as literal characters, in which case it seems consistent and predictable that they would act in the way that single quotes do everywhere else and not permit interpretation.

Smylers

Re:Single quoted variable

Ovid on 2006-07-31T14:45:49

Well, basically the stuff after a $ or @ sigil gets treated sort of like it's code to be executed. This leads to the following:

  temp $ touch foo.bar
  temp $ ls
  foo.bar
  temp $ perl -e 'print "$ENV{`rm foo.bar`}"'
  temp $ ls
  temp $

I know you and I have discussed this bit, but others might want to be aware of it.

Hm.

hex on 2006-08-01T11:17:57

I certainly wasn't aware of that behavior. I would have expected the double quotes to cause everything inside to be interpolated, presumably starting with the innermost thing ($num in this case).