On optional arguments Jens Axel Søgaard (21 Jul 2005 16:33 UTC)
|
Re: On optional arguments
David Van Horn
(21 Jul 2005 17:44 UTC)
|
Re: On optional arguments
Jens Axel Søgaard
(01 Aug 2005 21:10 UTC)
|
Re: On optional arguments
bear
(22 Jul 2005 15:33 UTC)
|
Re: On optional arguments
Per Bothner
(25 Jul 2005 17:32 UTC)
|
The discussion on optional arguments at the beginning stopped before a consensus was reached. Since the last letter in the thread was posted a while ago, I have made an attempt to recap the discussion. The discussion started in <http://srfi.schemers.org/srfi-67/mail-archive/msg00036.html> in which Mike Sperber writes: procedure: (=? [ compare ] [ x y ]) procedure: (<? [ compare ] [ x y ]) procedure: (>? [ compare ] [ x y ]) procedure: (<=? [ compare ] [ x y ]) procedure: (>=? [ compare ] [ x y ]) procedure: (not=? [ compare ] [ x y ]) I dislike having the compare optional argument at the beginning: There seems to be almost no precedent for it in Scheme libraries, and it means that the parameter positions change their meaning depending on the total number of arguments, which I find confusing. In <http://srfi.schemers.org/srfi-67/mail-archive/msg00039.html> Sebastian Egner writes: b) If there is an optional compare proc. why is it in front? So that (foo compare x y) is always understood as (foo (compare x y)). This is consistent throughout the SRFI with all operations accepting a compare procedure as parameter---no matter the arity. Personally, I would find it confusing if the compare procedure argument is in front for some operations and at the tail for others. Consider: (if<? (compare x y) A B) (if (<? compare x y) A B) (if ((<? compare) x y) A B) The confusion of compare changing places might be more than the confusion of having an optional leading argument. In <http://srfi.schemers.org/srfi-67/mail-archive/msg00046.html> Mike writes - You use overloading to implement the curried version. I think that's a bad idea, partly for the reason described above, and partly for the existence of SRFI 26, which makes it clear that there's currying going on with little notational overhead. (But who am I talking to? :-) ) - You ditch the overloading, your rationale goes out the door. and elsewhere suggests Solution #1: Ditch the curry overload; make the comparison an optional last argument. Solution #2: Make the comparison a mandatory first argument. I'll for a moment assume that we ditch the curry overload and let the compare argument be the first of any optional arguments. Do we then get consistency? Well, almost, but there is still an (unrepairable) conflict with these functions (chain=? compare x1 ...) (chain<? compare x1 ...) (chain>? compare x1 ...) (chain<=? compare x1 ...) (chain>=? compare x1 ...) (pairwise-not=? compare x1 ...) (min-compare compare x1 x2 ...) (max-compare compare x1 x2 ...) (kth-largest compare k x0 x1 ...). [the conflict being (=? x y compare) versus (chain=? compare x y) ]. [Note: The if-family of macros also take compare as first parameter] The main objection against solution #1 is thus that it will become harder to remember where the compare functions are to be placed. But why did Mike objecti to putting the optional argument in front? On the technical side in <http://srfi.schemers.org/srfi-67/mail-archive/msg00045.html> he writes: The problems come later, when you pass these things around as higher-order procedures, and it's not immediately apparent that the procedure you've been passed uses an unorthodox argument processing convention. (This is generally a case against overloading in higher-order languages, I think---it doesn't scale well.) This is why you haven't encountered the problem yet, but may in the future. I am not sure I understand what he is getting at. If an unknown function is passed, then you obviously don't know how to call it correctly - and if you do know it, then you are aware of the functions calling conventions. On the cognitive front in <http://srfi.schemers.org/srfi-67/mail-archive/msg00049.html> he argues (prompted by the curry overloading I think) that having different names for different operations is preferrable (I tend to agree with that). Also on the cognitive front it should be mentioned that the traditional way of passing optional arguments is to use the variable number of arguments-mechanism. One might even say that our problem is that Scheme doesn't have a way to specify optional arguments. If it were possible to specify optional arguments with keywords this whole thread wouldn't exists. I.e. both (<? :compare default x y) and (<? x y :compare default) would work. The argument for the compare argument in front is also cognitive. The most important one is consistency as mentioned previously. Another parameter to consider is code readability. In some situations it is important to have read a certain argument before reading the others. Erm - more concretely consider (<? compare x y). Here <? signals we need to compare something. compare describes how the things are compared, and x and y is what to compare. In (<? <large-expression1> <large-expression2> compare) one reads what is to be compared before one finds out how they are to be compared. In that situation I prefer (<? compare <large-expression1> <large-expression2>) Botner has a similar point in <http://srfi.schemers.org/srfi-67/mail-archive/msg00050.html> SRFI 64 also has non-final optional arguments. E,g.: (test-eqv [test-name] expected test-expr) I think this is preferable to having two functions, and in this case having the test-name first is desirable for documentation reasons: (test-eqv "test-string-apppend-1" (....) (....)) To sum up - I think the choice is between tradition and consistency. In the end it is a matter of taste, which is why it is hard to choose. My personal preference is to keep the optional compare argument in front. Having it appear first in some functions (chain=?, ...) and last in others will confuse me. -- Jens Axel Søgaard