Hash::Util's lock_keys

Smylers Smylers at stripey.com
Wed Feb 19 13:26:33 GMT 2014


Robert Rothenberg writes:

> At $work, we're having a debate about using restricted hashes
> 
>   https://metacpan.org/pod/Hash::Util#Restricted-hashes

Given that we use strict to prevent typos in variable names, this seems
like the equivalent technique for when a bunch of variables are grouped
together in a hash, so I'm surprised that it isn't used widely.

(Note, I put myself among the category of people that I'm surprised
don't use it.)

However:

> Basically, we have code of the form
> 
>   $obj->some_method( \%args );
> 
> The method can use restricted hashes to catch typos in argument keys, e.g.
> 
>   sub some_method {
>     my ($self, $args) = @_;
> 
>     lock_keys( %{$args}, qw/ type foo bar /);
> 
>     ...
>   }
> 
> so when somebody calls
> 
>   $obj->some_method( { typo => '...' } );

I've found using hash-refs for named arguments to be more error-prone
than a list (copied into a hash), as well as requiring more punctuation
to use. I know that some (Damian's ‘Perl Best Practices’, I think)
recommend hash-refs for the potential ‘odd number of elements’ warning,
but I've encountered bugs that turned out to be along the lines of
some_method above doing:

  $args->{colour} //= 'purple';
  $args->{count} //= 1;
  $self->_some_helper_method($args);

The problem was that if it's invoked with:

  $obj->some_method(\%opt);

then setting defaults inside the method actually changes the caller's
%opt.

Yes, obviously this can be avoided by some_method taking a deep copy of
%$args, but that doesn't mean that all developers always remember to do
that (particularly if initially the method didn't require a deep copy,
the defaults being added later), nor that it's easy to track down the
source of such a bug afterwards (the %opt hash contains plausibly valid
data).

Whereas with:

  sub some_method {
    my ($self, %args) = @_;

    $args{colour} //= 'purple';
    $args{count} //= 1;
    $self->_some_helper_method(%args);

  }

  $obj->some_method(%opt);

that possibility doesn't occur. And having fewer %$-s and {...}-s from
de- and re-referencing makes the code a little less distracting as your
mind tracks what's going on.

Obviously neither way is wrong, but this way has been less painful for
me. ‘Odd number of elements’ bugs tend to be relatively easy to spot (the hash
contains nonsense), and locking the keys in %args would catch them
anyway.

> So, what are your opinions about this?

Please give it a go, let us know how it goes, and if it's successful
start evangelizing it to the wider Perl community.

Good luck!

Smylers
-- 
http://twitter.com/Smylers2



More information about the london.pm mailing list