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

Is there a better way than this to deference a hashref arg? I mean, maybe a way in one line? Also, it would be nice if there were some way to die if the arg was not a hashref.
my $arg = shift or die "no arg"; my %arg = %{$arg};

UPDATE: Thanks for pointing out the obvious, LR et al. There's really no reason to do this; I'm rewriting my code with just the ref.

Replies are listed 'Best First'.
Re: Better way to dereference a shifted hashref arg?
by Limbic~Region (Chancellor) on Jun 15, 2005 at 15:38 UTC
    tphyahoo,
    The obvious question is why? Typically when you pass by reference you keep it as a reference and not make a complete copy later on. To answer your question:
    my %arg = %{ shift() or die "Error" };

    Cheers - L~R

    Update: Placed the or die inside hash key.
Re: Better way to dereference a shifted hashref arg?
by Fang (Pilgrim) on Jun 15, 2005 at 15:43 UTC

    You don't have to dereference the hashref if you want to use it. For example, instead of:

    my %arg = %{$arg}; for (keys %arg) { ... }
    you can do:
    for (keys %$arg) { ... }
    That's what references allow in the first place, use it. :)

    As for your other question, perldoc -f ref:

    die "No what I want!" unless (ref($arg) eq "HASH");

Re: Better way to dereference a shifted hashref arg?
by davidrw (Prior) on Jun 15, 2005 at 15:43 UTC
    First question is why you would want to? The point (in most cases) of passing a hashref into the function is so that the data isn't copied (waste of time and memory). But If you really wanted to (maybe this is just a one-liner excercise), this seems to do the trick:
    sub f { my %args = do { ref($_=shift) eq 'HASH' or die "arg is not a hashref +"; %$_ } ; ... }
    Update: my %args = (ref($_=shift) eq 'HASH' or die "blah") && %$_ ;
Re: Better way to dereference a shifted hashref arg?
by Fletch (Bishop) on Jun 15, 2005 at 15:39 UTC
Re: Better way to dereference a shifted hashref arg?
by tlm (Prior) on Jun 15, 2005 at 16:08 UTC

    Update I fixed my original proposal with a comma kluge (so that it wouldn't die when the input was a ref to an empty hash. The resulting line is so long and tortured that it hardly qualifies as a one-liner, and it is not particularly clear coding, so I don't think it is worth the trouble. FWIW, here it is (along with some minimal testing code):

    use strict; use warnings; use Scalar::Util 'reftype'; use Test::More 'no_plan'; sub foo { reftype( $_[ 0 ] ) || '' eq 'HASH' and ( my %h = %{ shift() } ), 1 o +r die; return 1; } ok( eval { foo(+{}) }, 'empty hashref' ); ok( !eval { foo() }, 'no input' ); ok( !eval { foo( 1 ) }, 'bad input: constant' ); ok( !eval { foo( [] ) }, 'bad input: array ref' ); ok( eval { foo( +{ 1 => 1 }) }, 'good input' ); __END__

    Update #2771: Changed the code to use Scalar::Util::reftype instead of UNIVERSAL::isa, in response to chromatic's comment. If the code was tortured before, it is even more so now. The business with || '' is to silence a warning.

    the lowliest monk

      This code is almost always wrong:

      UNIVERSAL::isa( $_[ 0 ], 'HASH' )

      Besides breaking polymorphism, it's unreliable:

      my $x = bless \(my $y), 'HASH';

      Use Scalar::Util's reftype() instead.

        Thanks++ for the pointer. Interestingly, a few months ago I would have used ref $_[ 0 ] eq 'HASH', but I switched to using UNIVERSAL::isa upon reading the advice of some high-ranking monk (can't remember who, though), who deprecated such use of ref because it failed on blessed references.

        My point is that sometimes best practices in Perl seem to be a moving target.

        More than once I have seen convincing arguments for why stuff that appears in the Perl docs is actually bad programming (e.g. using AUTOLOAD for defining accessors; making constructors dual class/object methods; using INIT for initialization code). I realize that this is in part due to the fact that the docs are contributed by users, who may not know any better, and also because Perl is a "work in progress," but I wonder how Perl compares in this regard with other languages, and whether this uncertainty on best practices deters people from choosing Perl as a language for development.

        Maybe TheDamian's upcoming best practices book will put a stop to that, or at least slow down the mutation rate for best practices.

        the lowliest monk

Re: Better way to dereference a shifted hashref arg?
by fireartist (Chaplain) on Jun 15, 2005 at 15:42 UTC
    my $arg = %{+shift} or die "no arg";

    update: bad solution

      Assuming you meant my %arg, your code has two problems: 1) It gives a warning before dying when it's undef, and 2) it also dies when a ref to an empty hash is passed.