Beefy Boxes and Bandwidth Generously Provided by pair Networks
Syntactic Confectionery Delight
 
PerlMonks  

Re: Benifits of using hash rather than number of variables?

by DrHyde (Prior)
on Jul 20, 2011 at 10:11 UTC ( #915625=note: print w/ replies, xml ) Need Help??


in reply to Benifits of using hash rather than number of variables?

The three big advantages of passing hashes / hashrefs to your subroutines are:

  1. you have named parameters inside the subroutine, and you don't have to remember the order of arguments outside the subroutine;
  2. much easier to handle optional arguments, and to calculate which arguments to pass at runtime;
  3. easy to build up that hash a little bit at a time;

The big disadvantage of using hashes is that you lose some strictness checking. use strict will usually tell you if you mis-type a variable name, but it can't tell you if you mis-type a hash key - instead, if you mis-type a key name when reading the hash, it'll just auto-vivify. This sort of bug can be a real pain in the arse to track down.

Thankfully, there's a solution to this problem on the CPAN. Tie::Hash::Vivify is meant to let you provide "a hash where if you read a key that doesn't exist, it will call a code reference to fill that slot with a value", but it can of course be used thus:

use Tie::Hash::Vivify; use Carp qw(confess); use Data::Dumper; ... my $hashref = Tie::Hash::Vivify->new(sub { confess("No auto-vivifying!\n".Dumper(\@_)) });


Comment on Re: Benifits of using hash rather than number of variables?
Select or Download Code
Re^2: Benifits of using hash rather than number of variables?
by duelafn (Priest) on Jul 20, 2011 at 14:45 UTC

    See also Hash::Util which is in perl core since 5.8.0

    use Hash::Util qw( lock_keys ); my %hash = (foo => 42, bar => 23); lock_keys(%hash); say $hash{bae}; # Boom! "Attempt to access disallowed key 'bae' in a + restricted hash..."

    Good Day,
        Dean

      That doesn't really work for named parameters, specially not if some parameters are optional. Unless you're going to do something unwieldy like:
      sub whatever { unless (@_) { my %params = (key1 => undef, key2 => undef, key3 => undef,); lock_keys %params; return \%params; } my %params = %{+shift}; ... sub body using named parameters ... } my $whatever_params = whatever(); $whatever_params->{key1} = $value1; $whatever_params->{key2} = $value2; $whatever_params->{key3} = $value3; whatever $whatever_params;

        It will work fine for sub parameters. You can provide a list of keys as a second parameter to lock_keys:

        sub whatever { my %params = @_; lock_keys %params, qw/ key1 key2 key3 /; say "Got key1" if $params{key1}; # ok say "Got key2" if $params{key2}; # ok say "Got key3" if $params{keye}; # Oops - BOOM! } whatever key2 => $value2; whatever keyq => $value1; # Hash has key 'keyq' which is not in the ne +w key set

        For example, I use the following for parsing command-line options in my scripts:

        use Getopt::Long qw/:config bundling/; use Hash::Util qw/ lock_keys /; our %OPT; my @OPT_SPEC = qw/ help|h version noact|no-act|dry-run DEBUG output|o= +s /; GetOptions \%OPT, @OPT_SPEC or ($OPT{help} = 1); lock_keys(%OPT, map /^(\w+)/, @OPT_SPEC);

        Update 2: A diligent Anonymous monk actually tested this code (actually executing proposed code - what a concept) and pointed out that the initial lock_keys suggestion is sufficient. Updated the comments in the code above to reflect this.

        Update: Add example where lock_keys is not quite sufficient... One could solve this in a couple ways without changing how whatever is called: Anonymous monk make all this unnecessary

        # Option 1: use Params::Validate # Option 2: sub whatever { my @param_keys = qw/ key1 key2 key3 /; my %params = @_; $params{$_} //= undef for @param_keys; die "Invalid usage" if @param_keys != (keys %params); lock_keys %params; # ... } # Option 3: sub whatever { my %expected_params = map +($_,1), qw/ key1 key2 key3 /; my %params = @_; for (keys %params) { die "whatever: Unexpected named parameter $_" unless exists $e +xpected_params{$_}; } lock_keys %params, keys %expected_params; # ... }

        Good Day,
            Dean

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://915625]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others pondering the Monastery: (16)
As of 2015-07-02 13:18 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    The top three priorities of my open tasks are (in descending order of likelihood to be worked on) ...









    Results (38 votes), past polls