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)

Monday October 06, 2008
02:13 AM

New Method::Signatures: better attributes, traits, aliases

[ #37606 ]

New release of Method::Signatures is on its way to CPAN. I'm in a sprint to get all the sizzle implemented before PPW.

This release features improved parsing of method attributes, thanks to stealing code from Florian Ragwitz's MooseX::Method::Signatures.

Some parameter traits have been implemented. "is alias" lets you work with the parameter as an alias, altering it in the caller's namespace. Previously this was only possible by manipulating @_ directly.

These two are equivalent.

sub strip_ws {
    my $self = shift;
    $_[0] =~ s/^\s+//;
    $_[0] =~ s/\s+$//;
    return;
}
 
method strip_ws($str is alias) {
    $str =~ s/^\s+//;
    $str =~ s/\s+$//;
    return;
}
 
my $str = "  support the right to arm bears ";
Class->strip_ws($str);  # works in place on $str

During the initial arguments about how signatures should work on p5p one of the longest and loudest arguments was whether or not they should copy or alias by default. Perl 6 aliases, but Perl 6 is an "everything is an object" language which passes by reference all over the place. Perl 5 is not. Like it or not, Perl 5 copies. So copying is the default. But every once in a while you want aliasing, so here it is.

"is ro" makes a parameter read only (using the Readonly module). Now you can apply some strictness to your subroutines.

method echo($msg is ro) {
    return $msg;
}

If echo() tried to alter $msg it would throw an error.

Required and optional parameters are finally implemented. All positional parameters are required by default. Parameters with defaults are optional.

# $x and $y are required.  $z is optional and defaults to 0
method print_position($x, $y, $z=0) {
    print "$x, $y, $z";
}
 
# $url is required.  $user and $pass are optional.
method get($url, $user?, $pass?) {
    ...
}

The code generated for the required argument check is redundant (use B::Deparse to see it) and could be tightened up to improve performance. If someone wants to try out some relatively low hanging fruit, that's it. It's on Github so feel free to make a fork and work on it.

Next version will implement named parameters. After talking it over with Florian I think I'm going to go with his semantics from MooseX::Method::Signatures. Named parameters are declared with :$foo as in Perl 6. They are optional by default. Positional parameters can only be called positionally. Named parameters can only be called named. Disallowing mixing resolves ambiguities that Perl 6 needs a heap of special syntax to resolve.

# year is required.  The rest are optional and have defaults.
# They are all readonly.
method date2epoch(:$year! is ro,  :$month = 1 is ro, :$day = 1 is ro,
                  :$hour = 0 is ro, :$min = 0 is ro, :$sec = 0 is ro) {
    ...
}
 
# Jan 1st, 2008 00:00:00
my $epoch = Date->date2epoch( year => 2008 );
 
# One minute after midnight
my $epoch = Date->date2epoch( year => 2008, min => 1 );
 
# $text is positional, the rest are named and optional
method format($text, :$justify = "left", :$quality) {
    ...
}
 
# left justified
Class->format("mu");
 
# right justified, Livejournal quality poetry.
Class->format(<<'POETRY', justify => "right", quality => "LJ");
...
POETRY

Just how much code does this save? Here's date2epoch() written out long-hand.

sub date2epoch {
    my $self = shift;
    my %args = @_;
 
    croak "date2epoch() missing required argument \$year"
       unless exists $args{year};
 
    Readonly my $year  = $args{year};
    Readonly my $month = $args{month} || 1;
    Readonly my $day   = $args{day}   || 1;
    Readonly my $hour  = $args{hour}  || 0;
    Readonly my $min   = $args{min}   || 0;
    Readonly my $sec   = $args{sec}   || 0;
 
    ...
}

Wow, even I'm surprised! Do you really need all that? No, you could do without Readony and you could leave everything in %args. But with Method::Signatures you no longer need to compromise with verbosity. You can have all the features and compact code.

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.