One pain point with pure functions is you can't insert debug logging statements. D has a special case for that - purity for a statement isn't checked if it is prefixed with the `debug` keyword:
pure int square(int x) {
debug printf("called square\n");
return x * x;
}
which is very, very handy.I.e. it's for conditionally inserting debugging code where you don't care about purity, you just want to find the bug.
https://d.godbolt.org/z/Rwu4Cq (remove "-d-debug" to see)
Allocators are often pure in D, they probably shouldn't be but that would mean allocating outside the function which would be ugly and probably buggy too
Forgive me I'm just a small brained firmware programmer.
That's not a very useful distinction, and usually one talks about "purity" at a conceptual level. The language provides a layer of abstraction in which things can be considered pure (or not), even if the underlying implementation e.g. makes optimizations that require mutation. The language is just a guarantee that you can ignore these aspects of its implementation.
A function that allocates memory isn't pure, except perhaps iff it frees that memory either itself or by compiler magic. Then perhaps it is.
You can even promise a func is pure without even implementing it in the same translation unit! That produces lots of improvement. See these two godbolt links:
Actually that's the main point, as if it's in the same TU, the compiler can probably figure out a function is pure.
If you're actually not accessing any global state at all (including making no memory allocation), shouldn't the compiler figure that out anyway? That doesn't seem like something that would be very hard to check for.
void* __attribute__((const)) getGlobals(void) {
void* ret;
asm (
" ldr %0, [r9] \n"
" ldr %0, [%0, %1] \n"
: "=r"(ret)
: "I"(MY_MODULE_ID)
:
);
return ret;
}And it doesn’t do anything unintended if you’re lying to it by accessing the global state that you know to be constant?
For even more aggressiveness, try __attribute__((const)) which tells it that the func accesses NOTHING but the params, not even global vars. Of course this is quite limiting. You can also use this as a trick when YOU know that the only accessed global state is itself constant but gcc does not know that. This can produce substantial savings in number of calls of funcs that, for example, do lookups in large constant data tables, like table-based versions of sin() and cos().
In the example the article gives, adding __attribute__((pure)) to constFunc() does produce the behaviour author wanted and then some
LWN has more: https://lwn.net/Articles/285332/