[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

A Hole in Common Lisp

Of course, it's too late for Common Lisp -- this would be a VERY
incompatible change for no very good reason.  And, of course, you can
get the effect of a required keyword argument by signalling an error in
the init form.  We could provide some conventional function for
signalling this error and CLOS could recognize this and treat that arg
as required.

Even if I were designing a new Lisp from scratch, I'm not sure that I
would want to fill in the fourth box in your matrix.  By-name arguments
are for functions that have so many arguments that you can't remember
the order, or so many that it is convenient just to type in the two or
three you need and not the twenty you don't need.  But if the by-name
arguments are required, you have to type them all.  Furthermore, you
must remember them all (or look them up to make sure you haven't
forgotten one), and in that case you may as well enter them in the
canonical order.

Even if I wanted to mix positional and named args in a single function,
I don't like your way of doing it -- it seems treacherous to me.  If the
value of certain arguments to a function happen to match the named
arguments, things get interpreted in an unintended and very mysterious
way.  This would only be a good scheme if there were absolute separation
between the space of legal arguments and the space of arg names.  We
would have to go back to saying that all keywords must be keywords, and
we would also have to eliminate the practice of using keywords for other
things.  Or else we would have to create a new kind of object that is
reserved for use in arg names.

I have sometimes thought that if I were designing a lisp-like language
 from scratch, I would leave the question of by-postion or by-name
arguments to the caller of a function.  He's the one who can decide
whether he wants to remember the order of arguments or to do some extra
typing.  A lambda would have the following simple form (setting aside
&rest and &more arguments for now, and flushing &aux, which was a
mistake from the start):

(lambda ({var | (var intiform) | (var initform svar) }* )
   declarations, docs, body, etc. )

Variables with no initform are required.  They need not be at the head
of the list.

There are two forms of function calling, postional and by-arg-name
either of which can be used on any function.  They need to be
syntactically distinguished somehow.  I'll use square brackets to group
the name/argument pairs in the latter -- this might be a read macro that
turns into some three-element list with a reserved token in the car.

(function-name pos-arg-1 pos-arg-2 pos-arg-3 ...)

(function-name [nameX argX] [nameY argY] ...)

The latter form says to look up the argument names at the time of the
call and rearrange the call into the order the function is expecting;
cacheing of this step is encouraged.  The order of evaluation of a
function's args would be explicitly unpredictable in this language, so
the rearrangement is legal and not difficult.

Then the function gets called, unsupplied args get their initforms
evaluated, and if any of the required args does not have a value
assigned, an error is signaled.  If the lambda list has any optional
args before a required arg, the only way NOT to supply a value for the
optional args is to use the by-name form of call.

One can imagine versions of this in which the caller can mix positional
and named args -- some arguments and then some bracketed pairs -- but if
this is allowed, one would have to worry about what happens if the same
variable gets a positional value and a by-name value.  Signal an error,
I guess, or say that the result is indeterminate.

-- Scott