Subject: bug#78719: 30.1; [PATCH] Add functions `string-common-prefix' and `string-try-completion'

From: Daniel Mendler <[email-masked]>
Date: Sat, 05 Jul 2025 16:38:58 +0200

Phil Sainty <[email-masked]> writes:

> On 2025-07-06 01:15, Daniel Mendler wrote:
>> Phil Sainty <[email-masked]> writes:
>>> On 2025-07-06 00:35, Daniel Mendler wrote:
>>>> Only changing the return type to string is not worth the addition
>>>> of a new function.
>>> I can only disagree.  Wrapper functions which *eliminate all of the
>>> awkwardness* from an API are completely worthwhile.  They make the
>>> code using them easier to write and read and understand.
>> I agree that a wrapper has an advantage *if it eliminates all of the
>> awkwardness* from the API. Your proposed function fails at doing that
>> since it also provides all the unnecessary awkward arguments from the
>> underlying implementation.
>
> I'm not talking about the complexity of the functionality, but rather
> the complexity of *using* the function.

Yes, but one should not forget that in order to use the function I have
to understand it and read its documentation. Therefore a simpler can be
a better starting point than a more complex function with multiple
optional arguments. Of course this only holds as long as the basic
function covers my use case. I will discover the function likely based
on its name `string-common-prefix' if I am looking prefix computation,
so there is a good chance that it will cover my use case. For more
complicated scenarios, the docstring should point to `try-completion'.

> I'm arguing that if you're not trying to write completion code, it's
> horrible to have to write (and read) this:
>
>   (let* ((completion-ignore-case nil)
>          (completion-regexp-list regexp-list)
>          (prefix (try-completion "" collection)))
>     (if (stringp prefix)
>         prefix
>       (if (eq t prefix)
>           string
>         ""))))
>
> when it can simply be:
>
>   (string-common-prefix collection nil nil regexp-list)

I wonder how often you've written such code. I've written quite a bit of
completion-related code in recent years and I've rarely had this
problem, or the few additional lines here didn't matter in the greater
context.

It might be good to check if there are call-sites in the Emacs code base
which could be simplified by `string-common-prefix' in its simplest
incarnation and also with additional arguments. Call sites which are
about completion, where `try-completion' is more natural anyway, would
have to be excluded.

I suspect that there are quite a few call-sites where the simple variant
of the function will do. Furthermore I suspect that there will be almost
no sites where the complex variant would be needed, or would be a better
fit than `try-completion'. That's why I think it makes sense to offer
the prefix computation functionality at two levels of difficulty - the
simple form (`string-common-prefix' only with IGNORE-CASE) and the
complex form (the already existing `try-completion').

I think the reason why I am disagreeing with the additional arguments of
`string-common-prefix' is that the order of arguments does not feel
natural. I strongly disagree with the order

(string-common-prefix LIST &optional STRING IGNORE-CASE REGEXP-LIST)

since it will hurt the reasonable use case where I want to compute a
prefix with case folding. I would be more comfortable with this:

(string-common-prefix LIST &optional IGNORE-CASE REGEXP-LIST)

Or with one of these:

(string-common-prefix LIST &optional IGNORE-CASE STRING REGEXP-LIST)
(string-common-prefix LIST &optional IGNORE-CASE REGEXP-LIST STRING)

A non-nil STRING is a special case, an optimization, which is also
covered by REGEXP-LIST by using a regexp with an anchor. It should not
come before IGNORE-CASE.

Daniel