http://qs321.pair.com?node_id=893123

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

I have the following code, where "length keys" is returning one when I expect it to return three. Any ideas about what's going on? BTW, this is Strawberry Perl 5, version 12, subversion 1 (v5.12.1) built for MSWin32-x86-multi-thread.
print length keys %$hashref; print join ',', keys %$hashref; print Dumper $hashref;
produces the following (note that keys have been changed to protect privacy, they are actually 60-80 characters in length)
1 x,y,z $VAR1 = { 'x' => 0, 'y' => 0, 'z' => 0 };

Replies are listed 'Best First'.
Re: Wrong result for "length keys %$hashref"?
by toolic (Bishop) on Mar 14, 2011 at 19:47 UTC
    I think you want scalar instead of length. This prints 3:
    use warnings; use strict; my $hashref = { 'x' => 0, 'y' => 0, 'zzz' => 0 }; print scalar keys %$hashref;
Re: Wrong result for "length keys %$hashref"?
by philipbailey (Curate) on Mar 14, 2011 at 19:48 UTC

    The documentation of length answers your question:

    'length Returns the length in characters of the value of EXPR. If EXPR is omitted, returns length of $_. Note that this cannot be used on an entire array or hash to find out how many elements these have. For that, use "scalar @array" and "scalar keys %hash" respectively.'

Re: Wrong result for "length keys %$hashref"?
by cdarke (Prior) on Mar 14, 2011 at 23:30 UTC
    Among the excellent replies above I don't think anyone explained explicitly why you are getting the answer 1 from length, although maybe it is implied.

    length takes a scalar, so it uses keys %$hashref in scalar context. That gives 3, but length converts that to text '3', which is 1 character.

    For example:
    use warnings; use strict; my $hashref = {1..20}; print scalar(keys %$hashref)."\n"; print length keys %$hashref;
    Gives:
    10 2
    because there are 2 characters in "10".
Re: Wrong result for "length keys %$hashref"?
by ikegami (Patriarch) on Mar 14, 2011 at 19:54 UTC

    I prefer 0+ over scalar. It's a little more self-documenting.

    my %h = (a=>1, b=>2); print 0+keys(%h), "\n"; my @a = qw( a b c ); print 0+@a, "\n";
      That's only more self-documenting if you already understand list vs. scalar context. If a junior programmer saw that they would say WTF and have no idea where to look next. If you used scalar, they might not know exactly what it did but they'd have a direct pointer to documentation that would explain exactly what the intent of the code was.
        If you used scalar, they might not know exactly what it did...

        A Perl programmer who doesn't understand scalar context has no business programming alone.

        With that said, this is one of the few places where using the explicit scalar operator makes sense.

        You're assuming code exists in isolation. I can't think of any code that needs the number of elements in a hash that would be unclear no matter how you spelled

        0+keys(%h)

        But that doesn't mean they're all equal.

        • The 0+ points out that something special is happening, whereas scalar() just looks like a function call. A function call that doesn't exist. There's not even an op for it.

        • The 0+ points out that a number is going to be returned, confirming what one might think keys is doing.

        If you used scalar, they might not know exactly what it did but they'd have a direct pointer to documentation that would explain exactly what the intent of the code was.

        I think they'd be better off reading the docs for keys, not scalar. The former lists the two possible return values for keys. The understanding of context will follow.