Subject: Re: bug#75318: Lisp_Subr header and layout

From: Pip Cet <[email-masked]>
Date: Wed, 22 Jan 2025 16:07:52 +0000

"Eli Zaretskii" <[email-masked]> writes:

>> Date: Wed, 22 Jan 2025 14:25:22 +0000
>> From: Pip Cet <[email-masked]>
>> Cc: [email-masked], [email-masked], [email-masked]
>>
>> > For example, in the below:
>> >
>> >>    static union Aligned_Lisp_Subr Swatch_gc_cons_percentage =
>> >> -     {{{ PSEUDOVECTOR_FLAG | (PVEC_SUBR << PSEUDOVECTOR_AREA_BITS) },
>> >> -       { .a4 = watch_gc_cons_percentage },
>> >> -       4, 4, "watch_gc_cons_percentage", {0}, lisp_h_Qnil}};
>> >
>> > what is lisp_h_Qnil is relatively easy to understand, whereas the
>> > replacement, viz.:
>>
>> >> +#define SUBR_INITIALIZER(lname, fnname, minargs, maxargs, intspec_value) \
>> >> +  {{ .header = SUBR_HEADER,						\
>> >> +    .function = { .a ## maxargs = fnname },				\
>> >> +    .min_args = minargs,						\
>> >> +    .max_args = maxargs,						\
>> >> +    .symbol_name = lname,						\
>> >> +    .intspec = { .string = intspec_value },				\
>> >> +    .command_modes = LISPSYM_INITIALLY (Qnil),			\
>> >
>> > requires one to look up LISPSYM_INITIALLY, which is
>>
>> If you're saying that LISPSYM_INITIALLY is bad, I agree completely.
>
> It isn't bad, it's that replacing lisp_h_Qnil with it makes the code
> harder to understand (without going crazy with M-.).

> As for LISPSYM_INITIALLY, its name is the main source of confusion:
> the INITIALLY part all but prevents any attempt to get a clear idea
> what the macro does, without actually looking up all the way to the
> basics.  Unless on remembers that by heart, of course (I don't).

I think that second paragraph means that LISPSYM_INITIALLY is, at best,
an unfortunate workaround which may one day be retired.  So, IMHO, yes,
it's bad in an absolute way, but it may be the best option anyway.

(In GDB, with .gdbinit loaded, "p LISPSYM_INITIALLY (Qnil)" prints an
unhelpful "{0x0}"; "p lisp_h_Qnil" prints "{0}".  ptype thinks the first
is a Lisp_Object (but expands the type to its obscure definition), the
second claims to be a singleton array of int.  While all of these are
unhelpful, the last one is dangerous, and we can avoid it by using the
unfortunately-named LISPSYM_INITIALLY.

However, I think Qnil should be usable in static context.  If someone
working on a new GC can't do that (I speak from experience)), they most
likely cannot implement LISPSYM_INITIALLY at all, and have to resort to
some kind of constructor extension; GNU C has one, C++ supports them
natively.

None of that means we should be forced to keep the name, which is
confusing and misleading.

>> > To make the depth of the proverbial rabbit hole at least to some
>> > extent smaller here, could we please refrain from defining
>> > SUBR_NATIVECOMP_INITIALIZER, and instead include the necessary stuff
>> > directly in SUBR_INITIALIZER, with an #ifdef?  Or do you envision
>> > enough other users of SUBR_NATIVECOMP_INITIALIZER to justify yet
>> > another macro?
>>
>> Do you mean
>>
>> #ifdef HAVE_NATIVE_COMP
>> #define SUBR_INITIALIZER(lname, fnname, minargs, maxargs, intspec_value) \
>>   {{ .header = SUBR_HEADER,						\
>>     .function = { .a ## maxargs = fnname },				\
>>     .min_args = minargs,						\
>>     .max_args = maxargs,						\
>>     .symbol_name = lname,						\
>>     .intspec = { .string = intspec_value },				\
>>     .command_modes = LISPSYM_INITIALLY (Qnil),				\
>>     .native_comp_u = LISPSYM_INITIALLY (Qnil),		\
>>     .lambda_list = LISPSYM_INITIALLY (Qnil),		\
>>     .type = LISPSYM_INITIALLY (Qnil),
>>     }}
>> #else
>> #define SUBR_INITIALIZER(lname, fnname, minargs, maxargs, intspec_value) \
>>   {{ .header = SUBR_HEADER,						\
>>     .function = { .a ## maxargs = fnname },				\
>>     .min_args = minargs,						\
>>     .max_args = maxargs,						\
>>     .symbol_name = lname,						\
>>     .intspec = { .string = intspec_value },				\
>>     }}
>> #endif
>>
>> (and, I assume, the same thing for SUBR_HEADER?)
>
> No.  I meant to use #ifdef inside the macro.  But if that is
> impossible in a C macro, I'd even support making this an inline
> function.

My understanding is you cannot use #ifdef inside a macro in GNU C; there
might be a way to use _Pragma in other C versions, but it's horrible.

Similarly, as the standard C we're attempting to use doesn't have
constexpr and inlining functions is always optional, I'm pretty sure
it's still impossible to statically initialize a variable with the
result of calling a function, inline or otherwise.

Pip