Stories
Slash Boxes
Comments
NOTE: use Perl; is on undef hiatus. You can read content, but you can't post it. More info will be forthcoming forthcomingly.

All the Perl that's Practical to Extract and Report

use Perl Log In

Log In

[ Create a new account ]

schwern (1528)

schwern
  (email not shown publicly)
http://schwern.net/
AOL IM: MichaelSchwern (Add Buddy, Send Message)
Jabber: schwern@gmail.com

Schwern can destroy CPAN at his whim.

Journal of schwern (1528)

Wednesday October 08, 2008
09:28 AM

New Method::Signatures: named parameters!

[ #37623 ]

The next version of Method::Signatures on its way to CPAN now has named parameters.

method display( $text is ro, :$justify = 'left', :$enchef = 0 ) {
    ...
}
 
# $text = "some stuff", $justify = 'left', $enchef = 0
$obj->display( "some stuff" );
 
# $text = "Things and stuff\n", $justify = 'left', enchef = 1
$obj->display( <<'TEXT', enchef => 1 );
Things and stuff
TEXT

Because Perl 5 lacks the extra syntax that Perl 6 has to disambiguate named from
positional arguments, and frankly I don't think it's worth it, there's some restrictions on their use to avoid ambiguous situations. They always have to come at the end of the signature.

method foo( :$this, :$that, $foo?, $bar? )     # illegal
 
# $foo = "this", $bar = 42 or $this = 42 ?
$obj->foo( this => 42 );

Technically, one could allow *required* named params to
come first. I could also probably get away with allowing optional named params coming before required positionals by defining a precedence... but it rapidly gets shaky and I'd rather not open up that complexity unless there's
some great need.

You can't mix optional positional params with named params.

method bar( $a, $b?, :$c )  # illegal, ambiguous
 
# $a = 'c', $b = 42 or is it $c = 42?
$obj->bar( c => 42 );

Again, I could resolve this ambiguity by saying that positional
parameters take precedence over named params. Then the above becomes
$a = 'c' and $b = 42, but again I don't feel a pressing need to open
up that bit of complexity.

Anyhow, I'm pooped. That's the last of the major features for this
sprint before presenting at PPW and I think it's pretty darn useful.

Next is a lot of refactoring work. The signature parser has gotten
messy, named parameters in particular proved more complicated than
they should be. There's almost no error checking and I found when I
tried to add some that I don't have enough information to report on
compile time errors. There's no way for a user to introspect the
signature, though there is an internal signature structure which will
be pretty easy to adapt to the task. All the sugar syntax has to be
turned into equivalent traits (ie. '?$foo' and '$foo is optional' are
equivalent) to make introspection easier. And errors should be thrown
as proper error objects instead of just strings.

And Florian and I have to consolidate the guts of our modules into a
more generic "add block syntax to Perl" module.

The Fine Print: The following comments are owned by whoever posted them. We are not responsible for them in any way.
 Full
 Abbreviated
 Hidden
More | Login | Reply
Loading... please wait.
  • It's be keen to see two more things supported.

    First, it'd be nice to say, "Yes, I just want named arguments, but they're all in $_[1] as a hashref. The rest is empty."

      $obj->method({ named => 'arguments' });

    Secondly, "Yeah, I have positional and named arguments, with all the named arguments in a hashref at the end."

      $obj->method($arg1, $arg2, { named => 'args' });

    This would cover nearly all my code's methods.

    (Maybe I should STFU and WSFC.)

    --
    rjbs
    • To the hash ref, I don't deny it's common, but I ask why do we do that? One reason is to try and save a copy, if the hash happens to be huge. But they aren't, and if they are do you really want to enumerate all the names? And anyway, breaking the hash ref down into a bunch of scalars wastes all that memory savings anyway.

      Another reason is to leave open the possibility of passing in more arguments.

      $obj->method({ this => 'that' }, 42);

      in which case you're not really passing in named arguments else

      • Apart from anything else, the biggest argument is:

        If I don't have to change the calling semantics, I can actually use this in old code. If I have to update every caller to pass a list rather than a hashref, I am not going to do it. If I can't update my old codebase to use this, I am not likely to start using it for new code, either.

        --
        rjbs
      • One reason is to try and save a copy

        The only good reason is that it forces an “Odd number of elements” warning to be emitted from the calling site without having to add any code to the callee. Obviously this does not apply in your module’s case.