Function attribute best practices
H. S. Teoh
hsteoh at qfbox.info
Mon Sep 12 18:58:33 UTC 2022
On Mon, Sep 12, 2022 at 02:29:58PM -0400, Steven Schveighoffer via Digitalmars-d-learn wrote:
> If your intent is to *enforce* pure functions only, then that's what
> you do. If your intent instead is to ensure that given proper
> parameters, the function will be pure, then the answer is to unittest.
> I will say, sometimes this gets really annoying. Like if the unittest
> fails, you get very little information about *why* it's not working.
> i.e. you expect the inference to be pure, but it's not. All you get is
> "impure unittest can't call impure function foo(...)". Figuring out
> the misinference cause is a chore today. I wish it would be easier.
+1, we need better diagnostics around this.
I wonder if it could be done this way: whenever the compiler infers
attributes for some function F, along with the inferred attributes it
also attaches a list of locations where each attribute was excluded from
the inference. For example, if F was inferred as impure, the compiler
would also keep a reference to the first line where an impure operation
was performed in F. Whenever pure code tries to call F, the compiler
would print out this reference (file + line + column) along with the
error message. I.e., "pure function G cannot call impure function F
because impure was inferred from line 1234 in F."
Obviously, this applies only to functions with inferred attributes; if
the attribute was explicitly in the code, then there's nothing else to
say. Since functions with inferred attributes always must have their
bodies accessible (otherwise inference cannot be done), it's guaranteed
that the aforementioned reference can always be found.
In the meantime, my usual approach to debugging this sort of problem is
to explicitly (temporarily) mark the target function pure, and recompile
to find out what in the function made it impure. If it's a call to
another inferred function, then mark *that* function pure too, and
recompile, etc., until I arrive at the statement that first made it
impure. This doesn't always work, though. Sometimes forcefully marking
something pure will break the compile in other places, making it a pain
to debug (usually involving making a local copy of the function and
redirecting calls to/from it).
The compiler really should be giving us this information rather than
making us figure it out ourselves.
Ignorance is bliss... until you suffer the consequences!
More information about the Digitalmars-d-learn