Re: Default subroutine parameters
by perlplexer (Hermit) on Apr 22, 2002 at 16:41 UTC
|
Perhaps this may be of some use
sub foo{
my $bar = defined $_[0] ? $_[0] : 'default';
# ...
}
--perlplexer | [reply] [d/l] |
|
Or, keeping in the spirit of this lightweight approach, i.e. not bringing a hash to bear on the problem, if you want to munch @_ with shift you will have to do something like:
#! /usr/bin/perl -w
use strict;
sub x {
# my $one = do { @_ ? shift : 'default' };
# my $two = do { @_ ? shift : 43 };
my $one = do { my $arg = shift; defined($arg) ? $arg : 'default' }
+;
my $two = do { my $arg = shift; defined($arg) ? $arg : 43 };
print "x($one, $two)\n";
}
x();
x( 'this' );
x( 1, 2 );
update: sheesh, misread a requirements document and get downvoted into oblivion. I corrected the code; you can stop now. The principal idea I wanted to show was that a do block is a pretty nice way of doing this, because the default value appears at the end of the code, making it easy to spot, thus letting you gloss over the mechanics.
print@_{sort keys %_},$/if%_=split//,'= & *a?b:e\f/h^h!j+n,o@o;r$s-t%t#u' | [reply] [d/l] |
|
Your method doesn't take into account the fact that @_ may contain
one or more undef elements.
| [reply] |
|
sub foo
{
my ($bar)=@_; $bar ||= 'default';
}
| [reply] |
Re: Default subroutine parameters (boo)
by boo_radley (Parson) on Apr 22, 2002 at 16:56 UTC
|
&foo (bar=>"1");
sub foo {
%args=@_;
%defaults=(foo=>9, bar=>8, baz=>7);
foreach ("foo", "bar", "baz") {
defined ($args{$_}) || {$args{$_}= $defaults{$_}} ;
print $args {$_}
}
}
update : or better yet, with the keys that you expect the sub to know :
&foo (bar=>"1");
sub foo {
%args=@_;
%defaults=(foo=>9, bar=>8, baz=>7);
foreach (keys %defaults) {
defined ($args{$_}) || {$args{$_}= $defaults{$_}} ;
print $_ ," - ",$args {$_},"\n";
}
}
update : or better yet, just like Fletch sez. Nice stuff. | [reply] [d/l] [select] |
|
sub foo {
my %defaults = ( qw( foo 9 bar 8 baz 7 ) );
my %args = ( %defaults, @_ );
...
}
| [reply] [d/l] |
|
I really like this solution because it's syntactically simple.
It works when an argument is omitted entirely, but unfortunately it doesn't supply the default value when the value 'undef' is passed as an argument, like this:
mysub(foo => 0, bar => 1, baz => undef);
sub mysub {
my %defaults = qw(foo 9 bar 8 baz 7);
my %args = (%defaults, @_);
print "Foo: $args{foo}, Bar: $args{bar}, Baz: $args{baz}\n";
}
But it's inspired me to see if I can modify it to suit my needs. Thank you! | [reply] [d/l] |
|
|
Re: Default subroutine parameters
by particle (Vicar) on Apr 22, 2002 at 17:08 UTC
|
my preferred method is my $foo = shift // 'default';
alas, this method won't be available until perl 6 :(
see Exegesis 3 for more details (there's a summary on page 7.)
~Particle ;Þ
| [reply] [d/l] |
|
I submitted a patch last night to p5p that implements //, but it's too late to make it into 5.8. However, everyone thinks it's really cool, so there's a very good chance it'll be in 5.10. (One person suggested that we fork off 5.9 right now so the patch would apply, but everyone else (including me) thinks that it'd be more trouble than it's worth to keep it in sync with the 5.8 release candidates, which should start coming out Real Soon Now.)
Needless to say, I'm happy--it's the first time I've ever patched the core and they're already excited. :^) I thought I'd get a few "oh, that's cool"s, some style critiques, and enough experience to confidently patch the core--not the first feature for the next version of the language.
=cut
--Brent Dax
There is no sig.
| [reply] [d/l] |
|
congrats, BrentDax. that is *very* cool.
~Particle ;Þ
| [reply] |
Explicitly check for argument presence...
by RMGir (Prior) on Apr 22, 2002 at 16:55 UTC
|
sub mysub {
my $foo='default';
$foo = shift if @_;
}
--
Mike
Delayed post: I keep hitting Newest Nodes from the preview page, then wondering why my post doesn't show up. D'oh! :) | [reply] [d/l] |
|
That's a clever way of doing it. Of course its only
useful if the subroutine you are writing is expecting
exactly 0 or 1 argument.
If the subroutine allows multiple arguments with only
some being optional, the above approach will not work.
| [reply] |
|
Well, it works if the optional arguments are all trailing.
sub lotsaArgs {
my $arg1 = 'default';
$arg1 = shift if @_;
my $arg2 = 'default';
$arg2 = shift if @_;
my $arg3 = 'default';
$arg3 = shift if @_;
my $arg4 = 'default';
$arg4 = shift if @_;
...
}
This would be analogous to default arguments in C++, for instance.
If you want to have named arguments, and only pass some of them, then the hash of default values and
my %args=(%defaults,@_);
as suggested below is obviously better.
But as asked, he seemed to have only one arg to default.
--
Mike | [reply] [d/l] [select] |
|
Re: Default subroutine parameters
by Super Monkey (Beadle) on Apr 22, 2002 at 16:53 UTC
|
| [reply] |
Re: Default subroutine parameters
by stephen (Priest) on Apr 22, 2002 at 18:52 UTC
|
The "defined" method is the best way, but there's a way to have your cake and eat it too, for a price... just define a sub that processes your arguments, filling in as necessary. Like so:
##
## _fd()
##
## Arguments:
## ARGUMENTS: arrayref -- The arguments to a subroutine
## DEFAULTS: arrayref -- The defaults for those arguments
##
## Returns:
## list -- The elements of ARGUMENTS. Any elements in ARGUMENTS ar
+e replaced
## by the corresponding element in DEFAULTS.
##
sub _fd {
my ($args, $defaults) = @_;
my @filled = ();
foreach (0 .. max($#$args, $#$defaults)) {
push @filled, ( defined( $args->[$_] ) ? $args->[$_] : $defaults->
+[$_] );
}
return @filled;
}
sub max {
($_[0] > $_[1]) ? $_[0] : $_[1];
}
Then, in the rest of your code, you can just run your subroutines through _fd(), like so:
##
## test_default()
##
## Arguments:
## $name: string -- Somebody's name. (Optional)
##
## Prints "Hello my name is $name". Name defaults to "ben".
##
sub test_default {
my ($name) = _fd(\@_, ["ben"]);
print "Hello my name is $name\n";
}
Then, test_default('luke') prints "Hello my name is luke", while test_default() prints "Hello my name is ben". There's some overhead to calling subroutines and doing list processing all the time, but you can use it most of the time.
Update: After thinking about this for a while, I figured out a way to use theDamian's Attribute::Handlers and a small amount of symbol-table work to give Perl a default attribute: Attribute::Default.
use base 'Attribute::Default';
sub test_default : default('ben') {
my ($name) = @_;
print "Hello my name is $name\n";
}
stephen
| [reply] [d/l] [select] |
Re: Default subroutine parameters
by trs80 (Priest) on Apr 22, 2002 at 22:47 UTC
|
Here is the manner in which I would approach this based on the (what appears to be) non OO Perl you posted. The assignment of the values could be shorten based on some of the other posts. In reviewing the other posts it dawned on me that adding anonymous hash refs might make this more confusing so apology in advance if it does.
use Data::Dumper;
use strict;
# here is our default values for various
# parameters. We set this up so we have
# a central spot to set defaults, or
# you could say a poor mans conf routine.
our $defaults = {
call_it => {
incoming => 'text',
argument => 'value',
parameter => 'hello'
},
call_this => {
incoming => 'text',
argument => 'value',
parameter => 'hello'
},
};
# call our sub passing an anonymous hashref
call_it( { incoming => 'html' } );
sub call_it {
# pull off our first value which is our hashref
my $args = shift;
# loop through what should be our defaults
# based on our defaults hashref above
foreach (keys %{$defaults->{call_it}}) {
$args->{$_} ||=
$defaults->{call_it}{$_}
}
# print out our new args
# complete with our defaults and our
# passed parameter preserved.
print Dumper($args);
}
# below we move the assignment into another sub
# this helps if we are going to be doing this often
# another reason to do this is so that if you
# make changes to how you merge the parameters
# with the defaults you only have to edit this
# one sub vs. replacing every copy and paste
# of it.
# here is our assignment function
sub assign_defaults {
my ($hashref,$sub) = @_;
foreach (keys %{$defaults->{$sub}}) {
$hashref->{$_} ||=
$defaults->{$sub}{$_}
}
return $hashref;
}
# call our sub
call_this( { parameter => 'good bye' } );
# this sub uses the new assign_defaults
# as would any other sub that needs it
sub call_this {
my $args = shift;
$args = assign_defaults($args,'call_this');
print Dumper($args);
}
| [reply] [d/l] |
Re: Default subroutine parameters
by jeffenstein (Friar) on Apr 23, 2002 at 09:55 UTC
|
sub mysub {
return unless( (@_ % 2) == 0);
my %args = (
host => 'localhost',
port => 25,
@_);
#
print "Args: host = $args{'host'}, port = $args{'port'}\n";
1;
}
mysub( host => 'gatekeeper.dec.com', port => 80)
or die "Mysub failed";
| [reply] [d/l] |
Re: Default subroutine parameters
by samgold (Scribe) on Apr 23, 2002 at 03:47 UTC
|
Could you check the number of arguments using $#argv and use an if statement to define it or not.
if ($#argv == 0){
$foo = 'default';
}else {
$foo = shift;
}
or something like that. I hope that helps.
Sam
| [reply] [d/l] |
Re: Default subroutine parameters
by thelenm (Vicar) on Apr 23, 2002 at 16:15 UTC
|
Thank you for all the great replies! I was hoping that maybe there was a nice syntactic shortcut I hadn't thought of, something like // in Perl6, which Particle pointed out. I also did have in mind passing multiple parameters, although my post didn't reflect that. I really appreciate everyone taking the time to post helpful answers! Thanks! | [reply] |
Re: Default subroutine parameters
by Popcorn Dave (Abbot) on Apr 23, 2002 at 17:29 UTC
|
Wouldn't it be a better idea to set all your default parametersin your subroutine and let the values be overwritten by the information you pass in? That way you always have your defaults.
| [reply] |