http://www.perlmonks.org?node_id=228455


in reply to Re: Re: Re: Context aware functions - best practices?
in thread Context aware functions - best practices?

Good reply. ++. Like your previous node theres a considerable room for digression onto other topics. Something that I certainly did in my reply to you.

:-)

Hmm. I have to admit that my reply didnt take full account of the context that you were discussing. Let me put it this way, I probably wouldn't write

sub my_lc_warn { not defined wantarray and warnings::warnif("void", "my_lc used in vo +id context"); unless (wantarray) { @_>1 and warnings::warnif("my_lc called in scalar context with ex +tra arguments (".join(",",@_).")"); return lc shift; } else { return map lc $_,@_; } }
preferring
sub my_lc { not defined wantarray and warnings::warnif("void", "my_lc used in vo +id context"); return wantarray ? map lc $_,@_ : lc shift; }
but I can see your point that
my $lc=lc("A","B");
would most likely be an error, and thus the warning could be useful.

I admit that my comments more directly dealt with the general case that I know realize you weren't making. Although I still think that to a certain degree you were arguing the more general case than narrowly confining yourself to the specific one.

A few comments to some particular things you mentioned, that may or may not be a digression. :-)

You've hopefully documented that extra arguments will be ignored and that it's safe to do that.

On the contrary. Perl idiom is relatively clear about what happens to supefluous arguments. They get ignored. So if a routine that does anything other than quietly ignore arguments should document it as so, not the other way around.

can lead to bugs in the future, like when a module is updated.

Well, I agree that when a module is updated and new arguments are added to old subroutines there is a possibility of problems. But this is an API change and as such means that careful checking will have to be done when upgrading to ensure that no problems arise anyway, so I'm not sure how good an argument this is.

There is a great chance that if the warning is issued something unforeseen or unintended happened in the user's code.

Yes. I agree with this point in this context.

This does not relate much to my post, as far as I can see.

But it does. Ive seen enough code where overriden methods get new arguments appended in child classes to see this as relevent. (Again i'm refering to the more general case.)

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.

Well on this one im not so convinced. Does the documentation say Takes three arguments... or does it say takes three and only three arguments...?. Unless the documentation is extremely specific the general conventions of the language need to be taken into account. One of them is extreme flexibility in handling arguments, with a bias towards tolerance. This is one reason why prototypes and related argument checking can be quite annoying. You expect that in the absence of a statment to the contrary that you can pass arguments as flattened lists (an argument against $$$ type prototypes), and that only the arguments relevent get used (an argument against caring about extra parameters). So for instance if a subroutine is documented that it takes a reference to a hash that contains the keys 'foo', 'bar', 'baz', 'bob' that it wont do anything horrible to or about the keys 'fred' and 'wilma'. And for me one expectation is that a subroutine won't use or complain about extra arguments that aren't needed or used. (Again this is more general observation, you've convinced me about the specific case.) I actually am saying this from a position of experience. THe POSIX::strftime() function and friends demands that you give them only the correct arguments. On a number of occasions I have had objects that comprised of an array(ref) made up of a format string and a localtime() output, with a number of other arguments following them in the array. I personally would have preferred (and attempted) to write

my $timestr=strftime(@$self);
and was annoyed at having to write
my $timestr=POSIX::strftime(@{$self}[0..9]);
It just seemed like an unnecessary step, particularly as the operation is just a cosmetic improvement over
my @strftime=@{$self}[0..9]; my $timestr=POSIX::strftime(@strftime);

I don't see the relevance, but I trust you that there is.

Ok, well for me this comes under the subject of "interface usage restrcitions". I think that as a general rule an interface should be as flexible and forgiving as possible. And to me a warning is only slightly less annoying than a die(). Which is where I see the connection. Tenuous perhaps, but I did sort of miss your point. :-)

Sometimes though, restriction can be accepted. One of those cases are when you see potential future constructions that might necessarily restrain certain things

Hearty agreement for this paragraph. Although as a thought for another time I think that careful use of perls flexibility in argument handling at the initial interface design level can really cut down the number of changes to the literal interface. By this I mean something like using a hashref for options or even the use of key=>value pairs (named arguments) in parameter passing. Doing this means you usually can add attributes without fear of breaking peoples code. Incidentally if you delve through the older nodes here there are a number of discussions of argument handling tactics.

Anyways, thanks for the reply. The next time I write something like my_lc() I just might stick a warning in there as you suggest.

:-)

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