Subject: bug#64127: 30.0.50; mutate-constant warning with pure function

From: Basil Contovounesios <[email-masked]>
Date: Sat, 17 Jun 2023 17:28:01 +0100

Mattias Engdegård [2023-06-17 13:58 +0200] wrote:

> 17 juni 2023 kl. 13.32 skrev Basil Contovounesios <[email-masked]>:
>
>> Given a file foo.el that defines a pure function foo:
>
>> (defun foo (x) (declare (pure t)) (list x))
>
>> and another file bar.el that mutates the result of foo:
>
>> (setcar (foo nil) t)
>
>> byte-compiling bar.el emits a mutate-constant warning, even though the
>> result of foo is a fresh list:
>
> No, the `pure` declaration means that the function can be evaluated at
> compile time which the compiler happily does, yielding a constant
> list, which your code then attempts to modify.
>
> This is why the function `list` itself is not declared `pure` -- while it does
> look like a pure function when speaking informally, users relies on it returning
> a freshly allocated list that can be modified and that makes it non-pure. (If
> lists were immutable, then `list` would naturally be pure.)
>
> Only the mutate-constant warning is new here; previously, the compiler
> would have let you make this mistake undisturbed.
>
> Thus either you remove the pure-declaration from your function, or you
> don't mutate what it returns.

Right.

Which approach do you think the dash.el library in GNU ELPA should
follow?  It generally defines nondestructive operations over lists, some
of which even claim in their docstring that they return a partial or
complete copy of their arguments (modulo the parts changed by the
operation).

Is it okay for a pure function to say it returns a copy in its
docstring, with the onus lying on the caller to realise that a pure
function call may be byte-compiled to a runtime constant?  Or should all
such functions be impurified?

Thanks,

-- 
Basil