http://www.perlmonks.org?node_id=915883


in reply to Re^3: Benifits of using hash rather than number of variables?
in thread Benifits of using hash rather than number of variables?

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

Replies are listed 'Best First'.
Re^5: Benifits of using hash rather than number of variables?
by JavaFan (Canon) on Jul 21, 2011 at 14:59 UTC
    As you pointed out, it won't catch typos when calling the subroutine. Which is the important case.

    Since there's no reason to use the hash key more than once inside the subroutine, the protecting inside the subroutine is just overhead, adding absolutely nothing at all of value:

    sub whatever { my %params = @_; my $key1 = $params{key1}; my $key2 = $params{key2}; my $key3 = $params{key3}; ... neither %params, nor the key names are needed anymore ... }
    Alternatively, you can stick the key names in variables.

      Note: Updated my previous reply with various proposed solutions.

      Indeed, the initial implementation (lock_keys %params, qw/ key1 key2 key3 /;) is equivalent to your solution there. Though, my reading of the OP was that they wanted to use hashes rather than set a bunch of variables like that and lock_keys offers no less protection than the originally proposed Tie::Hash::Vivify.

      My personal use of lock_keys is restricted to command line option parsing and some cases where it is "easy" to set up on hashes that may be passed around or used a lot (for example, log file parsing as described in The value of declarations). If I were looking for a complete solution for subroutine arguments I would most likely reach for Params::Validate or similar since once you move beyond lock_keys %params, qw/ key1 key2 key3 /;, the added coding effort for proper validation (vs just verifying key names) isn't much.

      Good Day,
          Dean

Re^5: Benifits of using hash rather than number of variables?
by Anonymous Monk on Jul 21, 2011 at 16:51 UTC
    whatever keyq => $value1; gives: Hash has key 'keyq' which is not in the new key set at ...

    Seems useful enough.