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)

On optional arguments Jens Axel Søgaard 21 Jul 2005 16: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