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

A variable I'm passing into a subroutine may be a string, or it may be a hash reference. I need to take one action or the other as a result of a test for this. Is there a better way to perform that test than I've constructed in this code?

My Perl version is 5.8.5, running under Redhat.
#!/usr/bin/perl -w use strict; use Carp; my %h = ( 'one' => 'uno', 'two' => 'dos', 'three' => 'tres', ); my $s = 'foo bar'; sub xyz() { my $arg; my $argNum=0; my $stringOrRef; while(defined($arg = shift)) { if($argNum == 0) { $stringOrRef = $arg; } else { carp "one arg only please"; } $argNum++; } # here is where I test the argument ###################################### if($stringOrRef =~ /^HASH\(/) { print "it's a hash:\n"; foreach my $k (keys %{ $stringOrRef }) { print " $k : $$stringOrRef{$k}\n"; } } else { print "it's a string:\n"; print " $stringOrRef\n"; } } &xyz($s); &xyz(\%h);

Replies are listed 'Best First'.
Re: How to tell if I have a string, or a ref to a hash
by moritz (Cardinal) on Oct 19, 2010 at 16:40 UTC
    It's safer to use Scalar::Util::reftype -- if you just use the string representation, you'll have trouble if the string happens to look like HASH(0x88bd48).
    Perl 6 - links to (nearly) everything that is Perl 6.
Re: How to tell if I have a string, or a ref to a hash
by Corion (Patriarch) on Oct 19, 2010 at 16:38 UTC
Re: How to tell if I have a string, or a ref to a hash
by ikegami (Patriarch) on Oct 19, 2010 at 17:36 UTC

    The tools have been provided already, but I wanted to add a comment: You can't do it perfectly unless you disallow certain special cases related to overloading. Perl is designed around of the concept of implicit coercion, so trying to use type-based polymorphism in Perl is inherently flawed.


    By the way, your use of a prototype is not only unnecessary, it's wrong. You tell Perl that the sub takes no arguments ("sub xyz()"), but the sub clearly does take arguments ("while(defined($arg = shift))") and you have to tell Perl to ignore the fact that you told it the sub takes no arguments ("&xyz"). You should have

    sub xyz { ... } xyz($s); xyz(\%h);
      Thanks very much, all. It's interesting that not only had I never heard of 'ref', but that my searches through the index of the Camel Book didn't turn it up. I've decided to use Scalar::Util::reftype.

      Thanks also for the note on prototypes.
        The ref function is in the index of the camel book in both the 2nd and 3rd editions. The original pink one is in a box in my garage, so I don't know about that one.
Re: How to tell if I have a string, or a ref to a hash
by chromatic (Archbishop) on Oct 19, 2010 at 18:42 UTC
    sub xyz_from_string { my $arg_string = shift; ... } sub xyz_from_hashref { my $arg_href = shift; ... }
Re: How to tell if I have a string, or a ref to a hash
by locked_user sundialsvc4 (Abbot) on Oct 19, 2010 at 18:17 UTC

    perldoc -f ref

    Returns a non-empty string if EXPR is a reference, the empty string otherwise.   If EXPR is not specified, $_ will be used.   The value returned depends on the type of thing the reference is a reference to.   Builtin types include:

    • SCALAR
    • ARRAY
    • HASH
    • CODE
    • REF
    • GLOB
    • LVALUE
    • FORMAT
    • IO
    • VSTRING
    • Regexp
    If the referenced object has been blessed into a package, then that package name is returned instead.   You can think of “ref” as a “typeof” operator.