10

I realize that evaluating an array in Perl in a scalar context is useful: it results in a # of elements.

But what is the practical use of being able to evaluate a hash in a scalar context? e.g.

  • my $scalar_value = %hash;

  • scalar(%hash)

As far as I understand, it produces a string like "3/4" giving some information about the internals of the hash that appears to only be useful for debugging.

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
  • 3
    An array is a variable with a `@` sigil, a list is a series of items in the source code. in this code `@array = (1, 2, 3)`, `(1, 2, 3)` is a list, and `@array` is an array variable. perlfaq4 contains more information: http://perldoc.perl.org/perlfaq4.html#What-is-the-difference-between-a-list-and-an-array? – Eric Strom Feb 21 '12 at 20:39
  • 1
    But can't I write `scalar( 1,2,3,4 )`? if that's the case then "list" was correct based on your statement, no? –  Feb 21 '12 at 20:41
  • 3
    Technically a list can not exist in scalar context, what you have there is the comma operator in scalar context, which first evaluates 1, and throws it away, then 2, then 3, and finally 4 is evaluated and returned. So you are not getting the length of a list, but the last expression evaluated by the comma operator. So in scalar context, `(a, b)` means `evaluate a and throw it away, evaluate b and return it` whereas in list context, it would mean `evaluate a and push it onto the stack, evaluate b and push it onto the stack, return the stack` – Eric Strom Feb 21 '12 at 20:43
  • I see what my mistake was. Thanks for pointing it out! What if I use qw()? In other words `scalar(qw(1 2 3 4))`? That would be a list no? –  Feb 21 '12 at 20:50
  • 1
    `qw` in scalar context behaves the same way as the comma operator, it throws away all but the final value, which is then returned. My first statement might be clearer if edited to read "a list is a series of items in the source code (only when that series is in list context)" – Eric Strom Feb 21 '12 at 20:53

2 Answers2

14

It produces a value that can be used as a TRUE/FALSE flag to know if the hash is empty (no keys).

As an example:

if (%hash) {
    print "Hash has elements\n";
} else {
    print "Hash is empty\n";
}

if forces the expression into a scalar context because of its use as a boolean expression.

It's a very similar concept to using @array in a scalar context to test for emptiness:

if (@array) {
    # NOT empty!
}
DVK
  • 126,886
  • 32
  • 213
  • 327
  • Where "empty" means "has no keys". – tchrist Feb 21 '12 at 21:03
  • @tchrist - added that as clarification, but I'm at a slight loss as to how else "empty hash" may be interpreted? – DVK Feb 21 '12 at 21:05
  • 3
    It’s cause people go all weirdo over whether `%h = (foo=>undef)` means something different as a scalar. Same as they go weirdo over `@a = (undef)`. Each of those has one valid index, albeit no valid value. So it’s its keycount that counts. – tchrist Feb 21 '12 at 21:06
  • 5
    @tchrist - You know you worked with Perl too long when your brain refuses to see `%h = (foo=>undef)` as anywhere close to being a plausible "empty" hash :) – DVK Feb 21 '12 at 21:15
1

The scalar(%hash) lets you check if the hashing algorithm is working correctly. If you have 1,000 keys and you see something like 2/16 that means all the keys are resolving to only 2 of the 16 allotted buckets. This means all your keys are very similar and causing lots of collisions, which results in long sequential searches in the bucket.

Default bucket count is 8

perl -le '$h{a}=1;print scalar %h'
1/8

Prestash the hash with 1000 buckets (to the nearest power of 2)

perl -le 'keys(%h) = 1000;$h{a}=1;print scalar %h'
1/1024

This also helps out when you bless an hash for perl OO. You can speed things up if you know there will be a lot of keys.

Rich
  • 183
  • 5