Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Something I just noticed is kind of interesting and was wondering if anyone here could explain why this does what it does.

To print scalars, both of these work

print $scalar; print "$scalar";
To print arrays, both of these work
print @array; print "@array";
But hashes, it doesn't work that way.
print %hash; # works print "%hash"; # prints literally %hash
Can anyone explain why hashes can't be printed in quotes?

Replies are listed 'Best First'.
Re: printing hashes
by Roy Johnson (Monsignor) on May 06, 2005 at 02:06 UTC
    Because hashes don't interpolate into quotes. Which is kind of like saying "Because."

    No sensible, generally useful hash-to-string conversion was proposed. So there isn't one. Without quotes, it gets turned into a list, and each element is printed.


    Caution: Contents may have been coded under pressure.
      Perl 6 will interpolate spacetab-separated pairs, one per line, though the restrictions on interpolating arrays and hashes are tightened a bit to avoid accidental interpolation of email addresses and printf formats. You have to do something like:
      say "Array is @array[]"; say "Array is {@array}"; say "Hash is %hash{}"; say "Hash is {%hash}";
      Only scalars interpolate without some kind of bracketing.

      The space-separated form was chosen to make it easy to split on whitespace, but it's expected that most hash interpolations will in fact specify some more explicit format:

      say "Hash is %hash.as('%s => %s', ', ')";

        Looks like pugs does most of this:

        $ pugs -e'my @array=1..5;say "Array is @array[]";' Array is 1 2 3 4 5 $ pugs -e'my @array=1..5;say "Array is {@array}";' Array is 1 2 3 4 5 $ pugs -e'my %hash;%hash{"a".."c"}=1..3;say "Hash is %hash{}"' Hash is a 1 b 2 c 3 $ pugs -e'my %hash;%hash{"a".."c"}=1..3;say "Hash is {%hash}"' Hash is a 1 b 2 c 3 $ pugs -e'my %hash;%hash{"a".."c"}=1..3;say "Hash is %hash.as(q(%s => +%s), q(, ))";' *** Error: No compatible subroutine found: "&as" at -e line 1, column +35-73 $
        Pugs version is 6.2.2.

        After Compline,
        Zaxo

      I'm surprised you didn't propose this variant of your earlier post today:

      use List::Util 'reduce'; my %hash = ( foo => 1, bar => 2, baz => 3 ); my $count = 0; print +( reduce {$a . (++$count % 2 ? ' => ' : ', ') . $b} %hash ), $/; __END__ bar => 2, baz => 3, foo => 1
      ...or any other of the other join alternation schemes.

      the lowliest monk

        In that case, the question was "How do I get the output format I want?" This is a case of "Why doesn't Perl interpolate hashes in strings?" I only shamelessly plug my previous posts when it's justified.

        Of course, with the right syntax, Perl will interpolate anything in a string.

        my %hash = ( foo => 1, bar => 2, baz => 3 ); print "@{[%hash]}";
        But here's another reducing scheme that doesn't involve strenuous exercise or counting calories:
        print((reduce { $a . ($$...$$ ? ' => ' : ',') . $b } %hash), $/);
        The flip-flop doesn't maintain state between calls because in this case, it's not the same flip-flop on each call! Each entry into a subroutine gets a "different" flip-flop.

        Caution: Contents may have been coded under pressure.
Re: printing hashes
by davidrw (Prior) on May 06, 2005 at 02:10 UTC
    I'm not sure of the techincal/lingual reasons, but I point you at the perlop manpage that states:
    For constructs that do interpolate, variables beginning with ""$"" or ""@"" are interpolated, as are the following escape sequences.

    As for printing, I would recommend something like one of the following (I'm assuming the printing is basically for debugging purposes):
    use Data::Dumper; print Dumper \%hash; print join ":", %hash; print join ":", keys %hash; print join ":", values %hash; while( my ($k, $v) = each %hash ){ printf " %s --> %s\n", %k, $v; }
      My favorite is:
      print join(', ', map { $_ . ' => '. $hash{$_} } keys %hash), "\n";
      -- gam3
      A picture is worth a thousand words, but takes 200K.
        i absolutely agree with you, but propose to sort the hash keys prior to mapping the result:
        print join(', ', map { $_ . _ => ' . $hash{$_} } sort { $a cmp $b } ke +ys(%hash), "\n";


        @ anonymus monk:
        the sort block is what sort() performs automatically, so it's just a placeholder for any other sorting routine.
        perldoc -f sort will give you some examples and advices.

        language is a virus from outer space.
Re: printing hashes
by chas (Priest) on May 06, 2005 at 02:27 UTC
    You could do print "@{[%hash]}"; if you really must interpolate a hash inside double quotes.
    chas
Re: printing hashes
by ikegami (Patriarch) on May 06, 2005 at 02:09 UTC

    "" interpolates only $vars and @arrays. $" can be used to customize how the array is interpolated. Hashes probably can't be interpolated because it would require two variables to properly control the interpolation of %hashes. There are few symbols left (if any), and the benefits would be rather slim.

    IIRC, only $ vars were interpolated historically.