Subject: bug#75784: Typo "unreadeable" in print.c; was exposed to Lisp

From: Pip Cet <[email-masked]>
Date: Fri, 24 Jan 2025 13:50:20 +0000

"Stefan Kangas" <[email-masked]> writes:

> Pip Cet via "Bug reports for GNU Emacs, the Swiss army knife of text
> editors" <[email-masked]> writes:
>
>> print.c contains the following code:
>>
>> static void
>> print_create_variable_mapping (void)
>> {
>>   Lisp_Object total[] = {
>>     list3 (intern ("length"), intern ("print-length"), Qnil),
>>     list3 (intern ("level"), intern ("print-level"), Qnil),
>>     list3 (intern ("circle"), intern ("print-circle"), Qnil),
>>     list3 (intern ("quoted"), intern ("print-quoted"), Qt),
>>     list3 (intern ("escape-newlines"), intern ("print-escape-newlines"), Qnil),
>>     list3 (intern ("escape-control-characters"),
>> 	   intern ("print-escape-control-characters"), Qnil),
>>     list3 (intern ("escape-nonascii"), intern ("print-escape-nonascii"), Qnil),
>>     list3 (intern ("escape-multibyte"),
>> 	   intern ("print-escape-multibyte"), Qnil),
>>     list3 (intern ("charset-text-property"),
>> 	   intern ("print-charset-text-property"), Qnil),
>>     list3 (intern ("unreadeable-function"),
>> 	   intern ("print-unreadable-function"), Qnil),
>>     list3 (intern ("gensym"), intern ("print-gensym"), Qnil),
>>     list3 (intern ("continuous-numbering"),
>> 	   intern ("print-continuous-numbering"), Qnil),
>>     list3 (intern ("number-table"), intern ("print-number-table"), Qnil),
>>     list3 (intern ("float-format"), intern ("float-output-format"), Qnil),
>>     list3 (intern ("integers-as-characters"),
>> 	   intern ("print-integers-as-characters"), Qnil),
>>   };
>>
>>   Vprint_variable_mapping = CALLMANY (Flist, total);
>> }
>>
>> Unfortunately, "unreadable" is spelled in two different ways: the first
>> instance is "unreadeable-function", with an "e", the second is
>> "print-unreadable-function", without the "e".
>>
>> I think this was a simple typo at one point, but it was exposed as part
>> of the Lisp API and people may have used it.  OTOH, it wasn't introduced
>> too long ago, so we might want to fix it and see whether anyone
>> complains.
>>
>> The documentation also needs to be updated, either to change it to the
>> correct spelling or to mention the typo so Lisp hackers know this is
>> another kdb-macro-redisplay.
>
> Thanks for catching this typo.

Thanks for suggesting I report it.

> I think we will have to support both spellings, at least for a while.

Okay.

> Do we have a way to add an obsoletion warning to both names?

I'm sorry: why both names?  The new name should be permanent, unless we
decide to move to a different name entirely to get rid of the typo (this
is what happened with kdb-macro-redisplay, IIRC).

While we could check for an obsoletion property on the symbol in
question in print_bind_overrides, it's very likely that if anyone
actually uses this code, they use it in an automated loop, so the
warning would need rate-limiting as well.  My suggestion is to print the
warning just once, increasing the risk it'll be missed but saving us
having to write a rate-limiting facility for Emacs which, if I
understand the context directly, cannot use Lisp.

> Would you like to suggest a patch?

diff --git a/src/print.c b/src/print.c
index 8c10ffa883e..918cef107b7 100644
--- a/src/print.c
+++ b/src/print.c
@@ -677,6 +677,8 @@ print_create_variable_mapping (void)
 	   intern ("print-escape-multibyte"), Qnil),
     list3 (intern ("charset-text-property"),
 	   intern ("print-charset-text-property"), Qnil),
+    list3 (intern ("unreadable-function"),
+	   intern ("print-unreadable-function"), Qnil),
     list3 (intern ("unreadeable-function"),
 	   intern ("print-unreadable-function"), Qnil),
     list3 (intern ("gensym"), intern ("print-gensym"), Qnil),

should allow using the correct spelling, but not add the obsoletion
warning.

I do not know how to make a symbol that is unbound but used to indicate
a keyword (I don't understand why no ":" is present, or how this would
change the situation) obsolete.

How would you like to proceed?

As is, unfortunately, normal for loops that attempt to avoid
FOR_EACH_TAIL, print_bind_overrides misses a corner case and infloops
unquittably for:

(prin1 "foo" nil (quote #1=(t . #1#)))

Maybe we should build on the useful parts of this first attempt and
review it carefully for a second version.

Pip