[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
On optional arguments
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
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.
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
Personally, I would find it confusing if the compare procedure
argument is in front for some operations and at the tail for others.
(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.
- 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
Ditch the curry overload; make the comparison an optional last
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
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
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
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
(<? 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
(<? compare <large-expression1> <large-expression2>)
Botner has a similar point in
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
(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