Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

Context aware functions - best practices?

by Aristotle (Chancellor)
on Jan 14, 2003 at 18:22 UTC ( [id://226916]=perlquestion: print w/replies, xml ) Need Help??

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

One thing that has bugged me in a while is the fact that context propagates in Perl in ways that can sometimes lead to surprising results if you haven't realised what's going on. I haven't actually tripped over this particular problem as I was aware of it to begin with, but I'm not sure what the best way to solve it would be:

I'm building a list to return in a function, and naturally I'm storing it in an array. This function is meant to be called with any number of parameters, map each of them to a result, and return the pile. In this particular case, I'm passing CGI parameter names and an untaint spec for each. Obviously I'm often assigning the results to a fresh batch of lexical variables and of course sometimes I want to call it with just a single parameter. There's the quandary:

sub foo { my $num = shift; my @arr = (42)x$num; return @arr; } my $x = foo(1); print $x;
The result is 1 of course because that's the number of elements in @arr - the value an array evaluates to in scalar context, which I established by omitting the parens on the my. The only clean and robust solution I can think of is somewhat awkward: return wantarray ? @arr : $arr[0]; Am I missing any simpler idiom?

Makeshifts last the longest.

Replies are listed 'Best First'.
Re: Context aware functions - best practices?
by Zaxo (Archbishop) on Jan 14, 2003 at 18:48 UTC

    I think the wantarray solution is fine, and not all that awkward. That's what wantarray is for.

    I think I can make a case for scalar foo LIST to return the last element of the result return wantarray ? @arr : $arr[-1]; instead of the first. A comma sequence behaves that way in scalar context, so that is the ordinary precedent competing with array count for behavior in scalar context.

    A third possibility is to return a reference to the generated array. Some modules do that, but it is clearly not desired here.

    No, I don't think you missed anything.

    After Compline,
    Zaxo

      Thanks for the well thought out response. I hadn't even though about -1, but I accept the argument. "Awkward" was probably the wrong term - really I should have written "verbose" instead. I was just wondering if the same behaviour is possible to achieve in a more concise way.

      Makeshifts last the longest.

Re: Context aware functions - best practices?
by scholar (Acolyte) on Jan 14, 2003 at 18:35 UTC
    If I understand the question correctly you're wanting the sub to be aware of the context within which it is called which is precisely the purpose of the wantarray function. And it's perfectly clear to boot. I have to say I've always thought of it as rather elegant myself.
Re: Context aware functions - best practices?
by runrig (Abbot) on Jan 14, 2003 at 18:33 UTC
    I think I would just put parens around the $x. I'd only use wantarray if I wanted to return something besides the first element of the array that would otherwise be returned, like an array reference or whatever.

    Update: /me changes his mind. I'll agree, typing a bit more in the function does save you from remembering to type all those parens in the usage of the function, so go ahead and use wantarray just like you have.

Re: Context aware functions - best practices?
by LAI (Hermit) on Jan 14, 2003 at 18:46 UTC

    Hm. My first reaction is to consider the possibility of:

    my $x = foo(1,2,3,5);

    This should of course be a scalar result, and not equal to scalar (@x = foo(1,2,3,5)). I'd feel uncomfortable omitting the results from the 2,3 and 5, so I'd probably do one of the following:

    return wantarray ? @arr : "@arr"; return wantarray ? @arr : \@arr;

    depending on use, 'yadda'x3. Perhaps, if it really suits the particular sub, you might want to return a join, but I'd personally be leery of that.


    LAI
    :eof
      You are aware that scalar (@x = foo(1,2,3,5)); will evaluate to the number of elements returned by foo rather than return the last one of them, right? :) And no, I even considered returning an array ref. (But not a concatenation, yuck - if the caller wants unstructured data he can flatten the array himself, but he can't well unflatten a string.) I'm not going to ask this particular function for two return values when I'm only interested in one of them though. I just don't want to have to remember and to type the parens in every instance I only ask for one return value, because that will be pretty a common case. CGI::param works the same way with good reason, f.ex.

      Makeshifts last the longest.

        You are aware that
        scalar (@x = foo(1,2,3,5));
        will evaluate to the number of elements returned by foo rather than return the last one of them, right? :)

        Yes, of course. I wrote that in reference to my $x = foo(1); setting $x to 1 :oP

        I agree that it would be a rare case when the flattened array would be an acceptable return value, but I still don't like the idea of throwing away data. Oh, well. The only alternative I can think of is the hideous

        return wantarray ? @arr : $#arr ? \@arr : $arr[0];

        which borders on the obfuscated. I wouldn't use something like that if I were you. Of course I'm me, and love using lines like that, but I digress...

        Zaxo's suggestion of using $arr[-1] makes sense too, especially if the sub is doing something cumulative with its args. Imagine a sum() function that keeps track of all the intermediate sums, or whatever.


        LAI
        :eof
Re: Context aware functions - best practices?
by Hofmator (Curate) on Jan 14, 2003 at 21:01 UTC
    If I understand you correctly, you only want to return a scalar from this function if it is called with only one argument. What I'm thinking of is a function that, when called with one argument returns a scalar and when called with multiple arguments returns an array. Then you could just have sth like this:
    sub foo { my @args = @_; # do your calculation if (@args != 1) { return @results; } else { return $results[0]; # or return $result; # depending on your calculation } }
    It depends on what your function is doing. The problem with the wantarray solution is that you are calculating an array of results but not giving everything back to the user - whether you return the first or the last element, it's lying, because you actually had more results calculated in the sub.

    What I'm trying to say: the user is normally expecting an array returned from that sub. So he might on purpose write sth like my $length = foo(1,2,3); to get the amount of results. This user might then be surprised if he gets the first (or last) element of the array instead. If you return the whole array then he could still choose the get only the first (or last value) or any value in between like so:my $value = ( foo(1,2,3) )[$i];

    Just a few thoughts ...

    -- Hofmator

      I'm not calculating all that much. As I've said repeatedly, what I want is merely a convenience feature to have the same convenience as CGI offers with my $foo = $cgi->param(''); vs my ($foo) = $cgi->param(''); which both do the same.

      Data getting thrown away is not really a problem here, just like when doing my $foo = (bar(), baz(), qux()); the user knows he asked for more than he provided the space to save it in.

      Makeshifts last the longest.

Re: Context aware functions - best practices?
by shotgunefx (Parson) on Jan 15, 2003 at 01:50 UTC
    I see nothing wrong with this idiom. It's how I would do it, but if you were worried about generating the extra data (Which in this case your not) I would recommend looking at Want. "wantarray on steriods". In this example you could use the howmany() sub to determine how many items the caller wants.

    But for most cases I would stick to plain ol' wantarray()

    -Lee

    "To be civilized is to deny one's nature."
Re: Context aware functions - best practices?
by sauoq (Abbot) on Jan 15, 2003 at 06:20 UTC

    Your case may be exceptional but, most often, the right thing to do is just return the array. That allows the user to get behavior he is already familiar with from dealing with plain old arrays.

    sub foo { my @r = (42) x $_[0]; return @r; } my @a = foo(3); my $s = foo(3); my ($sl)= foo(3); print "\@a: @a\n"; print "\$s: $s\n"; print "\$sl: $sl\n"; my @t = (42,42,42); @a = @t; $s = @t; ($sl) = @t; print '-'x40,"\n"; print "\@a: @a\n"; print "\$s: $s\n"; print "\$sl: $sl\n"; __END__ @a: 42 42 42 $s: 3 $sl: 42 ---------------------------------------- @a: 42 42 42 $s: 3 $sl: 42

    Consequently, in most cases, I think that if a user wants to call a function that is documented to return a list and assign it directly to a scalar, it is fair to ask him to remember what he is doing. By the way, I don't think the right way to do that is

    my ($x) = foo(1);
    but rather
    my $x = (foo(1))[0];
    The results may be the same but, though the latter is more verbose, it makes the desired result obvious. It doesn't look like it might have been a mistake.

    All of that said, I think using wantarray is probably the right way to do it in your case. It seems unlikely that someone would want to evaluate the returned list in scalar context to get the number of elements, so you are using the facilities Perl provides to get more useful behavior out of your function.

    -sauoq
    "My two cents aren't worth a dime.";
    

      Regarding the choice to use wantarray to grant context to the return value of a subroutine, you say:

      Consequently, in most cases, I think that if a user wants to call a function that is documented to return a list and assign it directly to a scalar, it is fair to ask him to remember what he is doing.

      An argument against this is that the user expects a list to be returned, not an array. Normally when a list is used on the right side of the expression, a scalar on the left side of the expression will be given the last value in the list, not the number of items in the list. This argument at least indicates that wantarray is desirable, and that the other suggestion in this thread (returning the last item in the list) is preferable to returning the array itself.

      Further on, you suggest that:

      my $x = (foo(l))[0];

      Is preferable to:

      my ($x) = foo(1);

      In Perl, there is a clear precidence for context to be significant. Consequently, Perl programmers expect functions to return the most sensible results in either context. It is a question of programming efficiency, more than programming purity. Calling a function in scalar context is like using a contraction in the English language. "I want the simpler form."

      Often, the value in scalar context is _very_ different than than the value in list context. For example, the builtin getpwnam() functions returns the username in scalar context, while getpwuid() returns the uid. Both return the same sort of list in list context.

      In terms of intuition, most people intuitively expect the following two expressions to be equivalent:

      my($x) = foo(...);

      And:

      my $x = foo(...);

      Sometimes the above is not the case, however, the times that this is not the case are usually the exception to the rule, and not the rule itself.

      I, personally, often use "wantarray ? @array : $array[0]" as a return value, not only because I believe that this is the most intuitive behaviour, but also because in most cases, I consider this the most useful behaviour. Useful often directly equates to efficient from a programming perspective.

        An argument against this is that the user expects a list to be returned, not an array. Normally when a list is used on the right side of the expression, a scalar on the left side of the expression will be given the last value in the list, not the number of items in the list.

        That's true when dealing with literal lists because that's how the comma operator works. Few builtin functions work this way. As far as the builtins go, there really is no standard way of relating both contexts. The perlfunc manpage says it nicely, "In general, they do what you want, unless you want consistency."

        This argument at least indicates that wantarray is desirable, and that the other suggestion in this thread (returning the last item in the list) is preferable to returning the array itself.

        There are many cases where wantarray is desirable. I even pointed out that Aristotle's case was probably one of them. I stand by my assertion, however, that most of the time returning the array makes more sense than using wantarray. For the record, I think that Zaxo's suggestion that the last element be returned is not very well thought out. For the general case, at least, it's a horrid idea. It's not exactly intuitive that a function would behave like a list literal and it wouldn't be very useful in most cases either. Besides, if you really want your function to act like a list literal, you could do it with a slice instead of wantarray; something like sub listify { @_[0..$#1] } for instance.

        In terms of intuition, most people intuitively expect the following two expressions to be equivalent:
        my($x) = foo(...);
        And:
        my $x = foo(...);
        Sometimes the above is not the case, however, the times that this is not the case are usually the exception to the rule, and not the rule itself.

        I disagree. The cases where those aren't the same are the rule. Consider

        my ($x) = split//,"foo"; # $x eq 'f' my $x = split//,"foo"; # $x == 3 my ($x) = map $_, qw(foo bar); # $x eq 'bar' my $x = map $_, qw(foo bar); # $x == 2 my ($x) = localtime; # seconds my $x = localtime; # String like ctime(3)
        The list could go on and on. So, though it's true people that are relatively new to perl might find the behavior you describe intuitive, it's also true that people with a modicum of perl experience learn not to expect it.

        I, personally, often use "wantarray ? @array : $array[0]" as a return value, not only because I believe that this is the most intuitive behaviour, but also because in most cases, I consider this the most useful behaviour. Useful often directly equates to efficient from a programming perspective.

        Again, I think this may be intuitive for someone that doesn't know perl but rather than that being the most useful behavior, I think it is simply hobbled. Here's an illustration:

        sub foo { my @a = qw(foo bar); @a } sub bar { my @a = qw(foo bar); wantarray ? @a : $a[0] } my($p) = foo; # $p eq 'foo' my $q = foo; # $q == 2 (different information) my($r) = bar; # $r eq 'foo' my $s = bar; # $s eq 'foo' (same information)
        Doing it your way, both calls result in the same information. If one wants the number of items returned, one must call it in list context first and then retrieve the count in a separate operation. Where's the efficiency in that? Allowing the call in scalar context to provide that information in exactly the way we are used to getting it from actual array variables is the most useful behavior most of the time. It makes a good default. For those times when it makes more sense to provide other information in scalar context, wantarray is available.

        -sauoq
        "My two cents aren't worth a dime.";
        
        An argument against this is that the user expects a list to be returned, not an array.

        While I understand your argument I believe that it is the user that errors. The error lies in his expectation. If a subroutine is documented to return a list it's also implicitly documented only for list context. When calling such a subroutine in scalar context you can't expect anything to happen--even less something sane to happen; there are no lists in scalar context. Take sort() for instance. That's obviously a list-context function, and you don't expect it to do anything useful at all in scalar context. Aristotle's problem is not as clear, but my point is still that if a subroutine is documented to return a list it's only documented for list context. Every other behaviour is undefined.

        But you also hit the nail when saying that we should code so that our routines get intuitive. So yes, I do partly agree with your argument.

        In terms of intuition, most people intuitively expect the following two expressions to be equivalent:
        my($x) = foo(...);
        And:
        my $x = foo(...);


        Yes, but this intuition is quickly counter-prooved by the numerous bugs that will come to any programmer expecting this. This is probably the first context bug that Perl programmers will meet. And usually, when past the newbie state, they don't get that wrong anymore. I too want to write easy-to-use code, but I expect a certain level of Perl understanding of my users, and list vs. scalar assignment is a basic thing in Perl.

        I'm undecided...

        ihb
Re: Context aware functions - best practices?
by ihb (Deacon) on Jan 15, 2003 at 22:40 UTC
    Before I start arguing for my case I'd like to point out that instead of writing   return wantarray ? @arr : $arr[-1]; to return the last argument in scalar context you can do   return @arr[0..$#arr]; Perhaps it's neither efficient nor clear, but I thought it could be worth mentioning.

    Besides that, I don't have much against   my ($x) = foo(...); Though, consider a method like this:
    sub get_headers { my $self = shift; my @headers = @_; my @values = @{$self->{headers}}{@headers}; return @values; }
    I hope it's clear what it does. It could be called like   my ($recipient, $sender) = $obj->get_headers('to', 'from'); But this is a typical subroutine that you often call with one element,   my ($recipient) = $obj->get_headers('to'); thus benefit from making that last return statement honour wantarray:   return wantarray ? @values : $values[0]; and now you can do   my $recipient = $obj->get_headers('to'); and I find this quite DWIMy.

    But, how much sense does   my $recipient = $obj->get_headers('to', 'from'); make? Not much, if you're asking me. For that reason, I think that it would be suitable to issue a warning if the function was called in scalar context with more than one argument.

    Even if that behaviour is documented to either return the last or first element it can be confusing when maintaining code. Since the construction doesn't make much sense you have to look in the documentation again, because you've probably forgotten if it'll return the first or last element. For that reason, I don't call subroutines with arguments it doesn't make use of. I haven't yet some across a case where I've felt a special desire to pass more arguments to the function than the function will use.

    It would also feel unsafe. The argument for this is pretty weak, but here it comes anyway. The author perhaps didn't think it through so well, and the current behaviour was just a consequence of the algorithm and he thought "why not, I might as well add this feature [prematurely]" (that happens a lot--that people add things prematurely, that is). And then he realizes that in scalar context the subroutine can be extra spiffy if it gets an extra argument or two. And that he can add, since it doesn't make sense to give more than one argument in scalar context anyway, right? Note that I'm not hoping that this would ever happen, but I think it can, and I'm a paranoid programmer. I'm especially paranoid against other programmers, and it does happen that module authors don't think through their API thoroughly.

    The &foo routine's return behaviour Aristotle presents isn't fully comparable to my &get_headers method though. In &foo the result depends on the value rather than number of parameters. If it can't be decided by looking directly at scalar @_ then you really ought to warn if the result gets longer than one element. It quite probably wasn't intended. If not, what's the harm in forcing the programmer to in this particular case disambiguate by putting a pair of parentheses? We use disambiguation tricks all the time, like +{} in maps and such.

    To sum it up as a general rule of thumb: If a subroutine has the character of returning a list, but sometimes returns just one element, then it can be made so that in scalar context it returns that very element. But if it's called in scalar context and it in list context would have returned more than one element then it should warn.

    Code-wise this means
    return @results if wantarray; carp("More than one value in result in scalar context") if @results > 1; return $results[0];
    Just my thoughts,
    ihb
      I haven't yet some across a case where I've felt a special desire to pass more arguments to the function than the function will use.

      Funny. There a number of situations where ive taken advantage of this very feature. And frankly would have been annoyed if the code warned when I did so. An example might be a situation where we extract the contents of a line via a regex, and then process that line via a dispatch function:

      my ($meth,@parts)=/.../; exists($dispatch{$meth}) and $disptach{$meth}->(@parts);
      or something like it. Another example would be overriding a method in a class that takes a certain number of parameters with one that takes a few more. When calling the overriden sub its fairly natural say something like
      sub blah { $foo->SUPER::blah(@_); ... }
      So IMO warning when someone passes too many parameters seems a little extreme. If you do that then I at least hope that you
      use warnings::register;
      so that I can turn off the annoying messages instead of having to write tortured code just so your sub gets the correct number of parameters. I have come across a similar annoyance when people use prototypes (usually for the wrong reasons, such as argument count checking).

      I'm especially paranoid against other programmers,

      Im sympathetic to this postion, but I think its a fine line between being paranoid, and being unduely restrictive. If the end user wants to give you more arguments then you need, then theres a decent chance that decision was a sound one. At a certain point you have to let the end user take responsibility for their own code, and thus their own (mis)use of your code. I certainly disagree with code that makes it impossible to do something just because the author couldnt see any reason why anyone would want to do it. (A position that you arent necessarily advocating I realize, but you can see the relevance I hope.) A good example is code like this:

      sub foo { my $array_ref=shift; ref($array_ref) ne "ARRAY" and die "Can't use anything but an array"; ... }
      Cheers,

      --- demerphq
      my friends call me, usually because I'm late....

        First of all I want to point out that my reply to which demerphq replied should be read in its right context: as a reply to a question about wantarray and proper usage.

        Funny. There a number of situations where ive taken advantage of this very feature [passing extra arguments].

        There's a big difference between seeing where you can take advantage and have a desire to take that advantage. I can see when you might want to do it, but I've never felt I actually want to do it. When you do it it's quite likely that you've written your dispatch routines yourself. And if that's the case then I see no problem with it. You've hopefully documented that extra arguments will be ignored and that it's safe to do that.

        However, when I use such techniques myself I've found that I do it mainly when the routines takes the same arguments. Sometimes the routines are generalized to ignore some arguments though, just to fit into the template. But they're almost always related. But even if they're not, I'm not all convinced it in the general case it A-OK to pass extra arguments. I'm not into too much stricture, so I wouldn't disallow it. But I hope that the programmer doing it is aware of that it can lead to bugs in the future, like when a module is updated. Module authors expect their users to follow the manual. I wouldn't hesitate a second to add an extra argument to a subroutine if I had documented the subroutine to take a specific number of arguments. But whilst I'm against excessive stricture I still want to help the programmer discover his error. If I see a great potential for a user to error I consider putting in a warning. In my argumentation to which you replied, that is the case. There is a great chance that if the warning is issued something unforeseen or unintended happened in the user's code.

        When calling the overriden sub its fairly natural say something like sub blah { $foo->SUPER::blah(@_); ... }

        This does not relate much to my post, as far as I can see. But this is not an obvious issue, as I understand it, and could be the topic of another discussion.

        So IMO warning when someone passes too many parameters seems a little extreme.

        I can't see where I've advocated this. I've recommended programmers to use the same philosophy as Perl itself does when it comes to warnings. For instance, @foo = $bar, $baz gives a warning in void context, because most likely the programmer didn't intend it to be (@foo = $baz), $baz. I'm saying the same here: Warn if it looks like the programmer did something he didn't want to, but also give a way to disambiguate and get rid of the warning. In my case above, that simply means you make a list assignment instead of a scalar assignment.

        # Consider a subroutine with a 1-to-1 # argument to return length mapping. my ($a) = foo($bar); # OK my $a = foo($bar); # OK my ($a) = foo($bar, $baz); # OK my $a = foo($bar, $baz); # Warns. # Why did the programmer pass two arguments # if he just wanted one return value?

        In real life it could look like this:

          my $a = foo(burk());

        and &burk is believed to return just one element. Perhaps the user was wrong in that, and &burk returned more than one element. Or perhaps &burk needed to be called in scalar context to give the expected return behaviour of one element, like localtime(). If I'm reading you right, you would be annoyed by that it warns?

        I also would like to extra clearly point out that I wasn't talking about arguments length checks per se. I was talking about return list length. Checking against @_ is just a way to in a simple way often be able to check the return length. Again, my statements in my reply must be read in its proper context. I was talking about my &get_headers method, that uses one-to-one argument to return length mapping. If you read my rule of thumb (which is just that; a rule of thumb and thus has exceptions) again you'll see that it's generalized to be about the output rather than the input. That ought to be clear in the code illustration.

        If you do that then I at least hope that you use warnings::register;

        Or I use a global like $Pkg::WARN so pre-perl5.6 programmers can control the warnings. Or a combination of the two. The functionality warnings::register gives you (described in perllexwarn for those that are unfamiliar with it), is unfortunately not so well known, nor used. I think it should be given more attention.

        ... so that I can turn off the annoying messages instead of having to write tortured code just so your sub gets the correct number of parameters.

        Or you could just disambiguate... don't torture yourself when you don't have to.

        Me: I'm especially paranoid against other programmers
        You: Im sympathetic to this postion, but I think its a fine line between being paranoid, and being unduely restrictive.

        I'm not saying that I'm paranoid against my users. I'm not afraid of their abuse of my code. I'm paranoid when I am the user. I choose to write my code to be restricted by the documentation of the module I'm using. If the documentation says the subroutine wants three arguments, then it gets three arguments. If I break this deal between me and the module author I have no one to blame but myself. So I do as the documentation tells me.

        If the end user wants to give you more arguments then you need, then theres a decent chance that decision was a sound one.

        Not in this case! It's most probably a slip-up, and I want to be fair and warn the user. See the example above.

        I certainly disagree with code that makes it impossible to do something just because the author couldnt see any reason why anyone would want to do it. (A position that you arent necessarily advocating I realize, but you can see the relevance I hope.)

        I sure don't advocate that. I don't see the relevance, but I trust you that there is. But while on the topic I can just as well elaborate a bit. Why I definately not am advocating this is because I believe some of my users to be smart--often a lot smarter than I. So they might come up with cool tricks that follow by the unrestrictive interface. And I want to let people be creative. Sometimes though, restriction can be accepted. One of those cases are when you see potential future constructions that might necessarily restrain certain things. It's better to start restrictive in such cases, and easy up the rules later on. If users are significantly disturbed by my restrictions they'll hopefully let me know. If they come with good arguments, I'll sure consider it. But I don't want to paint myself in a corner due to premature design. (CPAN has examples of this.) Some modules need a couple of releases to grow, and initially you want to keep your doors open. I much prefer this over having the whole module marked as experimental, since that probably leads to that the people who actually want/need to use it in real-life situations won't, and I won't get the feedback I need on it.

        ihb

        I'll bite:) What should I do if I write a sub that is expecting an array ref and I get passed something other than an array ref?


        Examine what is said, not who speaks.

        The 7th Rule of perl club is -- pearl clubs are easily damaged. Use a diamond club instead.

      foo() was just an example thrown together to demonstrate the propagation of context to return :) - in my actual function, the number of returned elements does indeed depend on the number of passed parameters. Thanks for the suggestion, I like it.

      Makeshifts last the longest.

Re: Context aware functions - best practices?
by jmuhlich (Acolyte) on Jan 15, 2003 at 21:27 UTC
    The CGI.pm-style shortcut that some have mentioned is nice, and if you find it appropriate for your code that's fine. But do be aware of the consequences. Without realizing what $cgi->param() was really doing, I once wrote something like this:
    %hash = ( foo => $cgi->param('foo'), bar => $cgi->param('bar'), ... );
    Now, what happens when the 'foo' CGI param isn't passed? The above param() calls are in list context, so the param('foo') call returns an empty list, not an undef scalar value. Therefore $hash{foo} is set to 'bar', and any key/value pairs after that are shifted as well. wantarray is a neat tool, but you must keep your wits about you when it's afoot. :)

      Very good point. I hadn't considered the lack of values case - what struck me immediately (the first time I was about to write such code, even) about at that snippet was the opposite case: if foo has several values you get extraneous key/value pairs - oops. So I have to agree that it's easy to create confusing semantics with wantarray.

      At this point I am confident about my choice for this particular case, and reassured about the fact I hadn't overlooked any caveats myself. Thanks and ++ to everyone for their arguments and for pointing out some implications that escaped me.

      Makeshifts last the longest.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://226916]
Approved by Mr. Muskrat
Front-paged by diotalevi
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others browsing the Monastery: (3)
As of 2024-03-19 05:17 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found