in reply to Re: RFC named parameter syntactic sugar
in thread RFC named parameter syntactic sugar

Params::Validate has too many features, (I know that sounds odd, but read on). It is also slow.

Too Many Features?

Yah. In trying to solve the generalized problem of parameter validation (which makes it darn useful - but only in specialized situations), it makes the simple cases complex. This is precisely the problem that my idea of adding some syntactic sugar proposes to address.

use Params::Validate qw (validate_with); sub example_method { my $self = shift; my %args = validate_with ( params => \@_, spec => { thing => 1, handle => 1 }, normalize_keys => sub { return lc($_[0]); }, ); my ($handle, $thing) = @args{'handle','thing'}; #... }

Uh huh. How long did it take you to figure out exactly what it was doing? That does the same thing as:

use Class::ParmList qw (simple_parms); sub example_method { my $self = shift; my ($handle, $thing) = simple_parms(['handle','thing'],@_); #... }

Except Params::Validate does it half as fast and considerably less clearly.

Ideally, I want Sub::Parms to do be able to do something like this:

use Sub::Parms; sub example_method { Invokation : $self; NamedParam : $handle (+handle); NamedParam : $thing (+thing); #... }

and have it run at the same speed as this (which is about 3x faster than Params::Validate and almost 2x faster than Class::ParmList is while doing exactly the same thing):

sub example_method { my $self = shift; my %args; { my %raw_args = @_; %args = map {lc($_) => $raw_args{$_}} keys %raw_args; } unless ($args{'handle'}) { croak("Missing 'handle' argument"); } unless ($args{'thing'}) { croak("Missing 'thing' argument"); } unless (4 == @_) { croak("Unexpected extra parameters"); } my ($handle,$thing) = @args{'handle','thing'}; #... }

The idea is that the simple cases should be simple and clear.

Replies are listed 'Best First'.
Re^3: RFC named parameter syntactic sugar
by diotalevi (Canon) on Oct 19, 2005 at 15:32 UTC

    I wasn't aware til you posted that there was a validate_with() function. Usually, Params::Validate is as concise as you said you desired. I've also never desired to have case-insensitive named parameters. I suppose that might be desireable. It looks like you'd want to have used the Params::Validate::validate_options() function to set that sort of policy for your package if that that's really common. Then it looks like you can go back to the normal, concise calling form.

    So... my experience is that if you want simple cases, that's simple to use. I've wanted slightly more complex things like named validation for my parameters - then I've just made named constants for those.

    # Restrict row ids to potential or all valid IDs # -1 1..inf use constant ROW_ID => { regex => qr/^$RE{num}{int}$/, callbacks => { valid => sub { local $_ = shif +t; $_ == -1 or $_ >= 1 +} } }; # Restrict row ids to things that are actually valid. # 1 .. inf use constant VALID_ROW_ID => { regex => qr/^$RE{num}{int}$/, callbacks => { valid => sub { local $_ += shift; defined() + && $_ >= 1 } } }; sub example_method { my $self = shift; my %p = validate_pos( @_, { handle => 1, thing => 1, something_else => VALID_ROW_ID } ); ... }
Re^3: RFC named parameter syntactic sugar
by dragonchild (Archbishop) on Oct 19, 2005 at 14:51 UTC
    The mistake Params::Validate makes is that it doesn't allow you to create what your simple case is. There should be a set of import parameters that specify exactly what the default handling for validate() should be, thus allowing you to customize it on a per-file basis. Or, allow the spec to be read from a datastore (such as a config file or files), allowing it to be global for a project. Oh, and that customization has to allow me to set callbacks when and where I need them, for custom validation and error-handling. And I have to be able to override the config file(s) in the use line.

    THAT would be the featureset that would get me to use it. Otherwise, it's just too much trouble for very little gain.


    My criteria for good software:
    1. Does it work?
    2. Can someone else come in, make a change, and be reasonably certain no bugs were introduced?

      What, this doesn't cover it?

      use Params::Validate; Params::Validate::validate_options( normalize_keys => sub { map { local $_ = uc; s/^-//; $_ } @_ } );
      The mistake Params::Validate makes is that it doesn't allow you to create what your simple case is.

      That's not quite true. There is the validation_options function, which sets per-package defaults.

      Params::Validate::validation_options( normalize_keys => sub { $_[0] =~ s/^-//; lc $_[0] } );

      You can also define parameter specs up front and re-use them. (Or put them in a config file/module for reuse across an app.)

      my %specs_for = ( foo => # specify a type { type => ARRAYREF }, bar => # specify an interface { can => [ 'print', 'flush', 'frobnicate' ] }, baz => { type => SCALAR, # a scalar ... # ... that is a plain integer ... regex => qr/^\d+$/, callbacks => { # ... and smaller than 90 'less than 90' => sub { shift() < 90 }, }, ); sub wibble { my %args = validate( @_, { foo => $specs_for{foo}, bar => $specs_for{baz}, }); # ... }

      So with very little up-front work, you can create re-usable parameter validation specs with a preset default case.

      -xdg

      Code written by xdg and posted on PerlMonks is public domain. It is provided as is with no warranties, express or implied, of any kind. Posted code may not have been tested. Use of posted code is at your own risk.