[Top][All Lists]

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

Re: [External] : Re: Shrinking the C core

From: Tomas Hlavaty
Subject: Re: [External] : Re: Shrinking the C core
Date: Tue, 12 Sep 2023 21:52:32 +0200

On Mon 11 Sep 2023 at 22:10, João Távora <joaotavora@gmail.com> wrote:
> On Mon, Sep 11, 2023 at 9:37 PM Tomas Hlavaty <tom@logand.com> wrote:
>> not really, it seems that CL:SORT is a bad example
> The example was for comparing to Emacs's lisp 'sort', where
> IMO it's much easier to do
>   (cl-sort things-having-foo #'< :key #'foo)
> than
>   (sort things-having-foo (lambda (a b) (< (foo a) (foo b))))

That has nothing to do with &key.
It has everything to do with the lack of the KEY argument
and the KEY argument could as well be &optional instead of &key.

If you find lack of the key argument "much not easier", you can define
your own sort, something like:

   (defun sort3 (seq pred key)
     (sort seq (lambda (a b)
                 (funcall pred
                   (funcall key a)
                   (funcall key b)))))

   (sort3 things-having-foo #'< #'foo)

is "much easier to do" than

   (cl-sort things-having-foo #'< :key #'foo)


   (sort things-having-foo (lambda (a b) (< (foo a) (foo b))))

Additionally, you'll get much nicer tool support automatically,
e.g. autodoc tells me:

   sort3: (SEQ PRED KEY)

One can see that autodoc for cl-sort is severely crippled.

> As to the advantage of @key key vs &optional key it is -- in my
> eyes,  at least -- that you already know its meaning from many other
> functions.

The point Richard raised was that your "many other functions" with &key
are bad way of doing it.

Simply naming the argument KEY would achieve the same goal of already
knowing its meaning from many other functions.  Making it &key does not
change that.

>> (btw why two functions and not extra stablep keyword argument?)
> Why not? Maybe that makes passing sort and stable-sort to higher
> order functions more practical?

That speculation does not sound plausible.

By that logic, CL would probably define 4 functions:

   sort sequence predicate => sorted-sequence
   sort3 sequence predicate key => sorted-sequence
   stable-sort sequence predicate => sorted-sequence
   stable-sort3 sequence predicate key => sorted-sequence

>> > Let's look at a traditional Elisp macro define-minor-mode.
>> the usual CL argument list does not seem to be able to express arguments
>> of such shape
>> it looks like whoever extended the original argument list did it
>> "weirdly" using custom ad-hoc single-use argument list parser.
> Quite likely the cl machinery wasn't available at the time...  But yes,
> Greenspun's 10th.
>> > are maintenance hazards, the macro now accepts keyword arguments
>> in CL, the arguments would normally be in a list before body, something
>> like
>>    (define-minor-mode MODE ([KEYWORD VAL ... ]) [DOC] &rest BODY)
> OK, but this is irrelevant.  This is a macro, not a function.
> For all practical purposes it was extended with keyword arguments.
> In fact you could have used cl-lib's cl-destructuring-bind.

No, that's missing the point.  CL itself is not able to express the
argument list structure in the shape it is implemented in
define-minor-mode.  You need custom argument parser anyway.

autodoc for define-minor-mode is also useless:

   define-minor-mode: (MODE DOC [KEYWORD VAL ... &rest BODY])

The way define-minor-mode sneaks in keyword arguments is pretty bad.  It
implements custom argument list parser and makes tools that understand
and work with argument lists useless, which causes extra manual work in
other areas.  If there was a unified argument list parser implemented in
one place and used consistently, it would avoid lots of manual work.

Back to the [KEYWORD VAL ... ] example, putting the argument list of the
macro into an extra list would allow one to use unified argument list
parser, but the way define-minor-mode arguments are specified at the
moment, CL:DESTRUCTURING-BIND cannot destructure such structure (&key
before &rest/&body is malformed).

Another example, take &body as opposed to &rest.  It automatically
declares the intent and how the indentation is meant to be computed.
With &rest indentation needs to be specified individually and manually
per case.  Lack of &body in elisp is annoying inconvenience.  Example:
(with-help-window BUFFER-OR-NAME &rest BODY) has (declare (indent 1))
which would not be needed if it was (with-help-window BUFFER-OR-NAME
&body BODY).

I think that rather than arguing about keyword arguments only, it would
be better to push for a unified argument list format which would be
followed, understood and supported by relevant tools.  So far, argument
list structure in elisp grew into ad-hoc mess which one needs to decode
manually from docstring on case by case basis; and no amount of CL would

reply via email to

[Prev in Thread] Current Thread [Next in Thread]