in reply to How do I test if a 'thing' is a hash (or array or scalar)?

But ref() won't tell you whether a blessed reference is a reference to a scalar, array, hash, or other. A better approach is:

UNIVERSAL::isa( $ref, "HASH" )
        - tye (but my friends call me "Tye")

Q&A Editor comment: See Library entry: perlman:lib:UNIVERSAL

Replies are listed 'Best First'.
RE: Answer: How do I test if a
by chromatic (Archbishop) on Sep 12, 2000 at 22:44 UTC
    When I find myself in this situation, I usually just do a regex for HASH or CODE or whatever. Seems to be more efficient than making UNIVERSAL check the (potentially tall) inheritance tree.

    References to my objects tend to be of the form  One=SCALAR(0x80f11bc) or Two=CODE(0x80f7d30).

      To be clear, you are suggesting something like:

      $ref =~ /HASH/
      or
      $ref =~ /(^|=)HASH\b/
      which checks the "stringification" of the reference. But this fails for objects that have stringification overloaded. It is better than ref(), but I still don't want to make code that breaks for such cases. I have seen cases of this, but unfortunately I don't remember where. :(

      If UNIVERSAL::isa() is a pig, then an efficient replacement needs to be provided (Hmmm... that would be an easy XS to write...).

      I didn't think that UNIVERSAL::isa() would search the inheritance tree since whether a blessed reference is a hash or not has nothing to do with inheritance. I hadn't looked into how isa() is implemented. You'll have to read universal.c if you are that interested. I started to and realized I don't have that much time right now.

              - tye (but my friends call me "Tye")

        I was curious so I benchmarked the different approaches:

        "HASH" eq ref($_) /HASH/ /(^|=)HASH\b/ UNIVERSAL::isa( $_, "HASH" )

        If you have 20,000 references that you want to validate, then you might be able to notice that one of these methods takes 1/50 of a second to do all 20,000 while another takes 1/10 of a second. The first can be done about 1 million times per second, the middle 2 about 100,000 times per second, and the last about 500,000 times per second. I don't consider this difference something worth worrying about. (:

        So UNIVERSAL::isa() is not a pig (and I didn't have to read the source code, yeah).

        A comment I expected but only got in private is that doing anything other than "HASH" eq ref($r) is "looking inside the object" and should be avoided. I actually agree with the spirit of that criticism. If you are doing this to figure out how an object is internally implemented, then you deserve to have your code break when that object's implementation is updated. But I really don't think that that is the way something like this is likely to be used. In fact, I feel strongly that using "HASH" eq ref($r) is a bad thing because it breaks objects that it shouldn't!

        If I have code that does something interesting with a hash via a reference, then I probably should (and may even need to) check whether I actually was given a reference to a hash. But I shouldn't refuse to work just because the reference to a hash that was given to me happened to be blessed.

        Why should I make it difficult for someone to write:

        use Hash::FindKeys qw( FindHashKeys ); # FindHashKeys finds keys of a hash where the key and # corresponding value meet certain criteria. Note that # ref($_[0]) must be "HASH" or it dies! [...] sub someMethod { my( $self )= shift @_; my @opts= FindHashKeys( $self, sub { /^-/ }, sub { $_ ne "" } ); # Oops, that dies! }
        I shouldn't. And there are several other cases that come to mind like this, but I've rambled on long enough.

                - tye (but my friends call me "Tye")