Subject: Re: bug#30373: Support finalizers for functions created in dynamic modules

From: Philipp Stephani <[email-masked]>
Date: Mon, 23 Dec 2019 21:41:16 +0100

Am Di., 6. Feb. 2018 um 22:43 Uhr schrieb Samir Jindel <[email-masked]>:
>
> Hi,
>
> I'm very excited by the possibilities opened through the new dynamic module interface, "emacs-module.h".
>
> However, I have a concern about the API for creating Lisp functions bound to native functions:
>
> ```c
>
>   emacs_value (*make_function) (emacs_env *env,
>         ptrdiff_t min_arity,
>         ptrdiff_t max_arity,
>         emacs_value (*function) (emacs_env *env,
>                ptrdiff_t nargs,
>                emacs_value args[],
>                void *)
>           EMACS_NOEXCEPT,
>         const char *documentation,
>         void *data);
>
> ```
>
> I presume the "data" pointer here is provided to enable native functions to work like closures,
> carrying additional, possibly dynamically allocated data. However, this functionality is limited by
> the absence of a finalization function pointer, like the "user_ptr" values have:
>
> ```c
>
>   emacs_value (*make_user_ptr) (emacs_env *env,
>         void (*fin) (void *) EMACS_NOEXCEPT,
>         void *ptr);
>
> ```
>
> Without the ability to provide a finalizer, a module can only safely make the "data" pointer to
> "make_function" point to static memory.
>

Sorry for not responding for so long. I think this makes a lot of
sense, and we should definitely introduce function finalizers.
I can think of three possible interface choices for this:
1. Add a make_finalizable_function environment function that is like
make_function but accepts a finalizer.
2. Add a set_function_finalizer(env, emacs_value, void(*)(void))
environment function.
3. Allow set_user_finalizer to also set function finalizers.
I'd lean away from (1) since it makes an already complex interface
even more complex. (2) seems cleanest, but requires adding a new
environment function. (3) would require the least amount of changes,
but it would also be slightly less clean than (2), and would break
backwards compatibility in a subtle way (users relying on
set_user_finalizer raising an error if a non-user-pointer object is
passed would break). Overall, I'd slightly lean towards (2).
Other opinions?