Beefy Boxes and Bandwidth Generously Provided by pair Networks
good chemistry is complicated,
and a little bit messy -LW
 
PerlMonks  

Subroutines: Returning a hash vs. hash reference

by mt2k (Hermit)
on Nov 28, 2002 at 04:02 UTC ( [id://216232]=perlquestion: print w/replies, xml ) Need Help??

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

I am continually working on a set of modules for a system I am planning to use in the (hopefully) near future. I have come across something new that I have never given much thought to. This is not a problem I have come across, but more of a question of style and perhaps preference. In these modules, I have several subroutines that give a hash as a return value. My question to you wise and wonderful monks is whether I should return a hash or a hash reference.

To explain perfectly well, this is an example of one of my subroutines:

package Module::Name; # require CGI, strict, constructor, all other code... # A sub to return a [hash|hash reference] of CGI params. sub get_params { my $self = shift; my %input; $input{$_} = $self->{$cgi_handle}->param($_) foreach $self->{$cgi_handle}->param()); # The two possible ways of returning the hash. # Is there a preference (style or personal) # as to which one I should use? return %input; # return hash # OR return \%input; # return hash reference }

The first method of returning the hash (return %input;), would be handled as such:

my $CGI = new Module::Name; my %INPUT = $CGI->get_params(); print $INPUT{'node'};

The second method of returning the has (return \%input;), would be handled as such:

my $CGI = new Module::Name; my $INPUT = $CGI->get_params(); print $INPUT->{'node'};
My guess is that this is probably a completely personal preference rather than style, but I might be wrong. If it is personal preference, I'd like to know which method other perl users prefer and perhaps any reason(s) as to why. :)

Replies are listed 'Best First'.
Re: Subroutines: Returning a hash vs. hash reference
by pg (Canon) on Nov 28, 2002 at 04:40 UTC
    Performance is different, and return hash ref has a much better performance. Try the following test: (I tried 1000 by 200, return hash cost 20 secs, when return ref only cost 13 secs. Well... you can see how slow my PC is.)

    use strict; sub return_hash { my %hash; for (0..shift) { $hash{$_} = $_; } return %hash; } sub return_hash_ref { my %hash; for (0..shift) { $hash{$_} = $_; } return \%hash; } my $ti = time(); for (0..$ARGV[1]) { my %hash = return_hash($ARGV[0]); } print "return hash takes: ", time() - $ti, " secs\n"; $ti = time(); for (0..$ARGV[1]) { my $hash = return_hash_ref($ARGV[0]); } print "return hash REF takes: ", time() - $ti, " secs\n";
      /me mutters something along the lines of "Why didn't I think of that?" :)

      Anyhow, I went as far as 2000x2000 and got the following results:

      return hash takes: 32 secs return hash REF takes: 11 secs
      This demonstrates that hash REFs do indeed run much faster. I suppose that returning a regular hash requires that the interpreter copy the data structure... likely doubling the memory required to keep the data structure memorized.

      Thanks a lot, I do believe I have got an answer to my "problem".

        It's actually worse than just copying the data structure...it first flattens the structure to a list of (key0, value0, key1, value1,...) then has to re-construct the hash by re-hashing all the keys. Its the latter part that takes most of the time.


        Okay you lot, get your wings on the left, halos on the right. It's one size fits all, and "No!", you can't have a different color.
        Pick up your cloud down the end and "Yes" if you get allocated a grey one they are a bit damp under foot, but someone has to get them.
        Get used to the wings fast cos its an 8 hour day...unless the Govenor calls for a cyclone or hurricane, in which case 16 hour shifts are mandatory.
        Just be grateful that you arrived just as the tornado season finished. Them buggers are real work.

Re: Subroutines: Returning a hash vs. hash reference
by BrowserUk (Patriarch) on Nov 28, 2002 at 04:29 UTC

    Personally, the decision as to whether to return a hash or a hash reference would be made on the basis of the size of the hash, and the frequency with which the subroutine is called. If the hash is small and the subroutine is only called a few times, I might return the whole thing simply because it makes the notation for using the hash much simpler in the calling code.

    Of course, that can be overcome by passing a reference to a hash declared in the calling code to the sub and having it populate it. The return then becomes (almost)irrelevant, serving only as a marker that the hash may have been modified. Though you might opt to return undef if the sub was unable to complete its task, and the passed hashref if successful.

    It's worth pointing out that your example sub could be replaced by my %INPUT = $CGI->Vars; or $INPUT = $CGI-Vars;.

    See section "FETCHING THE PARAMETER LIST AS A HASH:" in the CGI.pm pod for more info.


    Okay you lot, get your wings on the left, halos on the right. It's one size fits all, and "No!", you can't have a different color.
    Pick up your cloud down the end and "Yes" if you get allocated a grey one they are a bit damp under foot, but someone has to get them.
    Get used to the wings fast cos its an 8 hour day...unless the Govenor calls for a cyclone or hurricane, in which case 16 hour shifts are mandatory.
    Just be grateful that you arrived just as the tornado season finished. Them buggers are real work.

      It's worth pointing out that your example sub could be replaced by my %INPUT = $CGI->Vars; or $INPUT = $CGI->Vars;
      Okay, time to bring something up here... I was earlier (a year ago or so here at perlmonks) in a discussion over using a for() loop vs. using CGI::Vars. IIRC, the general decision was to stick with a loop to copy the values into a hash, because of some compatability issues with the fact that CGI::Vars looks back on the old cgi-lib.pl library. Perhaps CGI.pm has been updated since then? Anyone have any input on this (again, after such a long time?)
Re: Subroutines: Returning a hash vs. hash reference
by demerphq (Chancellor) on Nov 28, 2002 at 09:39 UTC
    My question to you wise and wonderful monks is whether I should return a hash or a hash reference.

    Why lock your users into only one option? Thats not the perl way to do things.

    If their code makes more sense with a ref then give them one, if it makes more sense to get a list of key=>value pairs then give it to them.

    I avoid the term "to get a hash" as there is no way to return a hash from a subroutine. Instead the hash must be listified into key=>value pairs and then returned that way. Its up to the user to shove that list into an actual hash (or not).

    And since this approach involves returning a list then good old perlfunc:wantarray comes to the rescue:

    sub get_params { my $self = shift; my %input; $input{$_} = $self->{$cgi_handle}->param($_) foreach $self->{$cgi_handle}->param()); # we return a hashref if the user calls us in scalar context # or a list of key=>values pairs if they call us in list context. return wantarray ? %input : \%input; }
    Incidentally this is a standard idiom that can come in very useful. Consider the behaviour of localtime(). You could even insert the following before the return statement
    die "get_params in void context:".Dumper(\%input) unless defined wan +tarray;
    to provide a debugging behaviour for when the sub is called in void context.

    HTH

    --- demerphq
    my friends call me, usually because I'm late....

Re: Subroutines: Returning a hash vs. hash reference
by EvdB (Deacon) on Nov 28, 2002 at 11:21 UTC
    If you are creating CGI scripts (which I think you are) and are using Template to create the HTML then hash refs are a better idea. For example if you have a function such as $hash_ref = get_user_details($user_id) you can do this:

    # %output is the hash that will be passed to Template. $output{user_details} = get_user_details( $user_id );

    This allows you to send data straight through to Template without having it hang around in your script. You could certainly do the same with a function that returns a normal hash with a step in between, but it is easier to standardise on hash refs and then to know that you can always do the above.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://216232]
Approved by rob_au
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others chilling in the Monastery: (7)
As of 2024-03-28 22:20 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found