Re: Correct idiom for default parameters
by MidLifeXis (Monsignor) on Apr 28, 2010 at 17:43 UTC
|
If you only have one layer of parameters (an HoV?), you could do this....
sub foo {
my %defaults = (
a => 1,
b => 2,
c => 3,
);
# other forms left as exercise...
my %params = (%defaults, @_);
# ...
}
| [reply] [d/l] |
|
| [reply] |
|
It also makes the calling code self-documenting. This is a large win for anyone dealing with the code including you when you come back to it a couple months later and can't remember which of the 6 args goes in the middle or what happens if you leave arg 2 out, etc, etc.
| [reply] |
|
|
Re: Correct idiom for default parameters
by Your Mother (Archbishop) on Apr 28, 2010 at 18:11 UTC
|
Test::new() is pretty un-Perl/OO way to get an object made. Object constructors are generally called as class or objects methods: Test->new([args]). Then you'd have an _init methods to process the args to new or later in other calls where they are allowed. I hope you are not really using the name "Test" for your package. :)
I find >2 arguments to be the tipping point for making named arguments much preferable to positional. What MidLifeXis showed is a good way to go about that.
| [reply] [d/l] [select] |
|
Good points. Understand though, that this bears almost no resemblance to my "real" code. I was attempting to put together the absolute minimum necessary to demonstrate the question and my intentions. And no, my real package isn't called "Test" :)
For the most part, the sub routines in question take one parameter and it's optional. I think there's one (maybe two) subroutines that take two where the first is mandatory, and the second is optional. I'd have to look again, as I forget off the top of my head. I do appreciate the input though.
| [reply] |
|
Object constructors are generally called as class or objects methods Test->new([args])
There's only one object constructor in Perl, and it's called bless. Test->new is nothing more than a class method, that just happens to return an object, often of the same class. More often than not, programmers decide said new() creates a brand-spanking new object, which gets initialized as well. These programmers make it hard to do MI.
| [reply] [d/l] [select] |
|
| [reply] |
|
| [reply] |
|
|
|
Re: Correct idiom for default parameters
by AR (Friar) on Apr 28, 2010 at 17:37 UTC
|
sub defaults {
my $self = shift;
my $default1 = shift // 1;
my $default2 = shift // 2;
my $default3 = shift // 3;
print("$default1 $default2 $default3\n");
}
Though I would never claim this is the "correct" idiom. Celebrate TIMTOWTDI! | [reply] [d/l] |
|
| [reply] |
|
sub test{
my( $p1, $p2, $p3) = map{ scalar @_ ? shift : $_ }( 1, 2, 3 );
print "p1:$p1; p2:$p2; p3:$p3";
};;
test();;
p1:1; p2:2; p3:3
test( 'a' );;
p1:a; p2:2; p3:3
test( 'a', 'b', 'c' );;
p1:a; p2:b; p3:c
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
| [reply] [d/l] |
|
|
|
Re: Correct idiom for default parameters
by BrowserUk (Patriarch) on Apr 28, 2010 at 17:44 UTC
|
sub test{
my $p1 = shift // 1;
my $p2 = shift // 2;
my $p3 = shift // 3;
print "p1:$p1; p2:$p2; p3:$p3";
};;
test();;
p1:1; p2:2; p3:3
test( 'a' );;
p1:a; p2:2; p3:3
test( 'a', 'b' );;
p1:a; p2:b; p3:3
test( 'a', 'b', 'c' );;
p1:a; p2:b; p3:c
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
| [reply] [d/l] |
|
sub test{
my $p1 = shift || 1;
[...]
| [reply] [d/l] |
|
| [reply] |
Re: Correct idiom for default parameters
by LanX (Saint) on Apr 28, 2010 at 20:22 UTC
|
if you are restricted to positional parameters, what about this ...
sub defaults {
my $d1= ( @_ ? shift : 1 );
my $d2= ( @_ ? shift : 2 );
my $d3= ( @_ ? shift : 3 );
print("$d1 $d2 $d3\n");
}
defaults();
defaults(0);
defaults(0, 0);
defaults(0, 0, 0);
__DATA__
1 2 3
0 2 3
0 0 3
0 0 0
UPDATE: precedence rules allow to omit the parens.
UPDATE from the example you gave I assumed that you don't plan to pass undef in the middle of parameters and expect this to be checked... otherwise all these solutions are too simplified and you have to check explicitly with defined. But in this case I really recommend using named parameters! | [reply] [d/l] [select] |
|
sub defaults {
my ($d1,$d2,$d3) = map { @_ ? shift : $_ } (1,2,3);
print("$d1 $d2 $d3\n");
}
defaults();
defaults(0);
defaults(0, 0);
defaults(0, 0, 0);
plz note: this solution depends on the number of defaulted parameters...
| [reply] [d/l] |
|
That looks pretty good!
And to answer your question in the post previous to this one, no I don't expect there to be an "undef" in the middle. The overwhelming majority of the cases there is one parameter that is optional. Which means that the predominant use will look like this:
sub defaults {
my ($self, $param) = map { @_ ? shift : $_ } (1);
print($param);
}
I found one place where it would be nice to have two optional parameters, but I'm debating refactoring that sub routine. | [reply] [d/l] |
|
|
sub defaults {
my ($d1,$d2,$d3) = ( @_ , (1,2,3)[@_ .. 2] );
print("$d1 $d2 $d3\n");
}
defaults();
defaults(0);
defaults(0, 0);
defaults(0, 0, 0);
but I don't like that the maximum index has to be hard coded.
at least this solution doesn't destroy @_ ...
| [reply] [d/l] |
DWIM code would use Params::Validate
by metaperl (Curate) on Apr 29, 2010 at 17:08 UTC
|
It has been said before that this code is "too simple" for CPAN, but I must disagree. I have seen people write this kind of code over and over again and they always get it wrong. Perhaps now they will spend more time getting the rest of their code right...
-- Leon Brocard in the notes of Data::Page
All the errors, mistakes, and cryptic golfing in this thread, along with the fact that you will need to do this more than once imply you need a modular, re-usable solution.
The software engineering approach is to use Params::Validate or a newer related module.
| [reply] |
|
You seem to be a big fan of software (over)engineering. As I've only seen overengineered solutions, maybe you can show an example where the code using Params::Validate is shorter and/or more concise or even more readable than the solutions already presented. The synopsis of Params::Validate only shows verbose "solutions" spanning at least five or six lines.
| [reply] |
|
| [reply] |
|
|
Here's one reason not to use Params::Validate.
The code (minus the inline stuff), in Re: Inline Subs Revisited takes just over 4 1/2 minutes to run.
Modify those subs to validate their parameters using P:V like so:
sub max {
validate_pos( @_, { TYPE => ARRAYREF } );
my ($list) = @_;
my $max;
for (@$list) {
$max = $_ if ! defined $max || $_ > $max;
}
return $max;
}
And it takes almost 22 minutes.
And achieves nothing that couldn't be done with die unless ref( $list ) eq 'ARRAY';. (That costs nothing measurable.)
Its like trying get better fuel economy by adding a large, copper-wound electric motor and 50Kg of batteries to your car.
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
| [reply] [d/l] [select] |
|
You can disable validation for production to avoid the hit, set VALIDATION to something true
| [reply] |
|
A reply falls below the community's threshold of quality. You may see it by logging in.
|