Efficient compilation of functions with keyword arguments Lassi Kortela (22 Jul 2019 15:08 UTC)

Efficient compilation of functions with keyword arguments Lassi Kortela 22 Jul 2019 15:08 UTC

Robert Strandh, author of the Common Lisp implementation SICL,
graciously replied to my inquiry and took the time to explain keyword
arguments to us in detail.

- Option 1 is self-evaluating keyword objects that Common Lisp uses.
- Option 2 is Racket/Kawa style keywords-as-argument-list-markers.

-------- Forwarded Message --------
Subject: Re: Efficient compilation of functions with keyword arguments
Date: Mon, 22 Jul 2019
From: Robert Strandh
To: Lassi Kortela

Hello,

Option 1 is indeed very simple.  There is no special ways to call a
function.  In fact, Common Lisp does not require &KEY parameters to be
symbols in the KEYWORD package.  Any symbol will do.  You just have to
use the syntax ((symbol variable) [init-form [supplied-p-parameter]])
for it, rather than (variable [init-form [supplied-p-parameter]]).

Option 1 is quite costly for the callee.  Common Lisp also allows the
same keyword to occur multiple times in the argument list, in which
case the first one is the one that counts.  In addition, it is always
possible to supply :ALLOW-OTHER-KEYS <true> to suppress the validity
check for keyword arguments.  This freedom implies that, for each
keyword parameter, the callee needs to search the the argument list
(after required and optional arguments have been removed) from the
start to determine whether a value for the parameter was given.

However, option 1 also gives a lot of flexibility.  A common idiom is
to have an intermediate function modify the argument list only
slightly, perhaps prefixing a keyword/value pair, and then call a
second function.  That way, the intermediate function is ignorant of
what keyword arguments the ultimate callee can handle, which improves
modularity.  Here is an example:

(defun foo (arg &rest more-args &key &allow-other-keys)
   (apply #'bar arg :new-key val more-args))

I don't see how you can get this flexibility with option 2.

The most common way of dealing with the performance problem of keyword
arguments is to define a compiler macro that recognizes a direct call
of the function (as opposed to through APPLY).  It can then parse the
argument list at compile time and turn the entire call into one that
calls a special version of the callee, with only required arguments.
It is not trivial, given the requirement that Common Lisp evaluate the
arguments from left to right, but it can be done.

I can't say much of the performance implications of option 2 since I
am unfamiliar with the way it is typically implemented.

Hope this helps.

Regards,

--
Robert Strandh