http://qs321.pair.com?node_id=127281

tame1 has asked for the wisdom of the Perl Monks concerning the following question:

Just wanted to get some opinions on this particular method of calling subroutines with arguments

my ($ret, $msg) = mysub( 'cat' => $val1, 'dog' => $val2 ); sub mysub { my $args = { 'cat' => undef, 'dog' => undef, @_ }; my $cat = $args->{'cat'}; my $dog = $args->{'dog'}; # do something with them if ($ok) { return($answer, undef); } else { return(undef, $error_msg); } }
Sort of like a poor man's prototyping?
At least I think it's better than "shift"ing to get arguments, etc. Everyone tell me if I am wrong, please!


What does this little button do . .<Click>; "USER HAS SIGNED OFF FOR THE DAY"

Replies are listed 'Best First'.
Re: Poor Man's Prototyping?
by VSarkiss (Monsignor) on Nov 24, 2001 at 22:27 UTC
Re: Poor Man's Prototyping?
by data64 (Chaplain) on Nov 24, 2001 at 22:14 UTC
Re: Poor Man's Prototyping?
by jlongino (Parson) on Nov 24, 2001 at 22:25 UTC
    I don't suppose there is any reason why you can't do it that way. My only question is why? It seems like it adds unnecessary code bloat, makes things more difficult to read and is less idiomatic than @_ and shift. But that is just my opinion and I'm sure there are others who will disagree (and they're entitled).

    Update: I can see where it is useful in the cases that chromatic describes. But for casual substitution of @_ and shift I'd still have to say that it is unattractive and overkill.

    --Jim

      It's a good technique when you have optional arguments to pass to a sub, or you have more than three or four. Look at the constructor for any of the IO:: modules, for example, or (as has been stated) just about anything in CGI.pm.

      Don't overlook the ability to provide default arguments as well. This isn't always appropriate, but there are times when it handily beats @_ and shift.

      I'd even nuke the shift. I replace:

      sub dosomething{ my $foo = shift; my $bar = shift;

      with

      sub dosomething{ my ($foo, $bar) = @_;

      That gets all the args and their order right up on the first line of the sub, where it's easier to see. I tend to agree with the Linux kernel CodingStyle document when it says that if you have more than 2-3 args there's probably some re-factoring in order. Cutting and pasting your function calls just seems... icky.

        This is something I would call a matter of personal taste. I talked about it at Silly code reviews and shift, and as I said there, it certainly is common to find shift used in argument processing in core modules, CPAN, etc. I have personally tried it both ways.

        My current opinion is that whether or not using shift for processing or assigning in one line is better is dependent on the rest of your coding style. As my style has changed it has gone from being definitely better to shift to (currently) being essentially indifferent.

        Furthermore on named arguments, I agree that long argument lists maintained by argument order are a bad idea. But I do not agree that the Linux kernel CodingStyle applies directly to Perl. In particular in Perl it is often very good style to develop list-based functions which may easily have 10 or 1000 arguments. And often you want to provide various kinds of optional default behaviour. In which case, as suggested in the root node, I find it best to provide a named parameter style with reasonable defaults where appropriate. Typically the calls will either wind up (at least in my code) being a pass-through hash, or else I will just use a few of the possible options in any particular code.

        Try it. It may take some time to be able to take good advantage of the flexibility offered. But I think that knowing how and when to do that is a good tool to put in your toolbox for languages that give you a way to do it.

Re: Poor Man's Prototyping in CGI.pm
by petdance (Parson) on Nov 24, 2001 at 23:39 UTC
    Whenever I wanna do stuff like that, I look at other people's code and see how they do it, and steal liberally.

    For me, I love the way Lincoln's done it in CGI. That's the model I try to use.

    xoxo,
    Andy
    --
    <megaphone> Throw down the gun and tiara and come out of the float! </megaphone>

Re: Poor Man's Prototyping?
by jarich (Curate) on Nov 25, 2001 at 07:20 UTC
    This is a really common way to do things in Perl OO, but need not be limited to that. It gives you the opportunity to allow defaults etc.

    Something I do a lot (in OO) is this:

    my %defaults = ( cat => 1, dog => 2 ); my @allowed = keys(%defaults); # you might allow others in here too. sub new { my $class = shift; my %args = (%defaults, @_); my @hash{@allowed} = @args{@allowed}; # ignore arguments # that we're not expecting. # do any specific checking here. my $self = \%hash; return bless ($self, $class); }
    The key point here is that this makes it easy for the user to pass the same set of arguments to a subroutine/constructor and for the class to only use the ones it wants. What is more, this method of passing arguments means that the user doesn't have to remember what order things go in.

    That's probably the biggest advantage of this method passing, not for prototyping purposes but that it saves the user having to remember argument order, especially if you have "optional" arguments.

    Defaults can be done when you use shift too.

    sub mysub { my $cat = shift || 1; # etc }

    By the way, putting the defaults hash outside of your subroutine means that you need build it only once (and you can modify it during the program if needed, but this can be a bad thing too).

      While this is a very good thing to do, as it protects you quite well, it can cause further problems when it comes to user expectations. You have to make sure that the contract between this object and the rest of the world is well-documented. Otherwise, a user will pass in 'bird' and not know why 'bird' isn't there.

      ------
      We are the carpenters and bricklayers of the Information Age.

      Don't go borrowing trouble. For programmers, this means Worry only about what you need to implement.

        I agree. Documentation is essential. But so it is for all interfaces. If I'm calling by position, the user still has to understand what order the items are required in. At least with named parameter passing the user can afford to forget the exact ordering sometimes. :)

        (Good point though. ++)