Following the How to make an object method read named parameters? discussion on how to read named parameter hashes, I've been thinking about the rather non-intuitive nature of the various parameter processing techniques.

In essence, all of them are more-or-less workarounds for a lack of syntactic support in Perl itself for named parameter hashes.

Worse - they are all (with the exception of raw my %args = @_) very slow.

So, for consideration, here is a proposal for a module that uses source filters to add syntactic support for hash parameters (the code for this has been written and has tested to work all the way back to Perl 5.005_04):

use Sub::Parms; # Case insensitive function parms sub my_function { FunctionParms : %args; my ($a_name, $another_name) = @args{'a_name', 'another_name'}; # ... } # Case sensitive function parms sub my_other_function { CSFunctionParms : %args; my ($a_name, $another_name) = @args{'a_name', 'another_name'}; # ... } # Case insensitive method parms sub my_method { MethodParms : $self, %args; my ($a_name, $another_name) = @args{'a_name', 'another_name'}; # ... } # Case sensitive parms sub my_other_method { CSMethodParms : $self, %args; my ($a_name, $another_name) = @args{'a_name', 'another_name'}; # ... }

The difference the 'CSxxxx' versions handle is that the default mode is case insensitive processing of parameter names (they are all folded to lowercase), but the 'CSxxxx' versions are not folded to lowercase (and hence are Case-Sensitive).

The method declarations also handle the declaration of the class invokation parameter for the OO inclined

The thought is that the declarations could be extended in the future with more parameters to handle validation, defaults and variable binding options.

Replies are listed 'Best First'.
Re: RFC named parameter syntactic sugar
by BUU (Prior) on Oct 15, 2005 at 19:50 UTC

      Backward compatibility to 5.005.

      Also, I couldn't figure out how to get Sub::Signature to handle a simple open ended named parameter hash like

      function_name( aname => 'value', anothername => 'value' );

      Honestly, given the docs, I'm not sure it can.

      And Sub::Signatures shows a disconcerting tendency to break even simple code.

      #!/usr/local/bin/perl use strict; use Sub::Signatures; my $example = { 'null_sub' => sub { null_sub( handle => 'Test', 'thing' => 'someth +ing')}, }; sub null_sub { }

      The above runs fine only if you comment out the 'use Sub::Signatures;'.

      Wierdly, changing the everywhere that says 'null' to 'method' works fine:

      #!/usr/local/bin/perl use strict; use Sub::Signatures; my $example = { 'null_method' => sub { null_method( handle => 'Test', 'thing' => ' +something')}, }; exit; sub null_method { }

      I think Sub::Signatures is trying to address a different problem. I think he is trying to add 'multi-dispatch' by method signature rather than simplify parameter parsing. I also think it is very fragile.

Re: RFC named parameter syntactic sugar
by diotalevi (Canon) on Oct 17, 2005 at 15:45 UTC

    I'd prefer more people used the plain my %p = @_ because then its just a step to the left, you can say use Params::Validate; ... my %p = validate( @_, ... ). It makes adding proper argument handling code /so/ easy.

      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.

        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 } ); ... }
        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?