There have been quite a number of mis-uses of @pure, and in some cases the resulting discussion about why reduces to "ask Jameson." Let's make it "read the docs" instead. Here's a possible head start:
"""
Base.@pure function f(args...)
#body
end
Marks function `f` as "pure," which means that the compiler should be allowed to replace `#body` with its resulting output. Marking a function as pure allows the operations to be performed at compile time rather than run time, potentially improving performance. In practice, it is only useful to mark functions taking only type or hard-coded constant inputs, since only in such cases does the compiler know the runtime values of the arguments.
To be a candidate for `@pure`, `f` must satisfy strict requirements:
- its output depends only on its arguments (it cannot depend on any additional state)
- it cannot have any side effects (no changes to any global variables, etc.)
- it cannot engage in I/O, even on an error path
Marking an impure function with `@pure` can lead to serious errors, including both incorrect results and runtime crashes.
"""
see #24817
I wonder if adding an 1.0 milestone would make sense; this should be fixed before Julia is released to reduce misunderstandings.
It's a good idea to clarify certainly, but documenting a non-exported macro is hardly release-blocking.
In the meantime (since the 1.0 release), it has become very common on the discourse forum to suggest/apply optimizations by simply annotating code with @pure. I think that a large fraction of these applications don't fulfil the requirements (I won't link examples as I don't want to single out anyone).
The fact that it is not exported or documented in detail does not seem to be enough to discourage users from using @pure. In the meantime, the compiler is getting smarter and smarter, making its use less necessary than users seem to believe.
It would be great to at least extend the documentation of @pure with examples of violations of the requirements, eg subtle changes in global state, including throwing errors, method definitions, etc.
These would be useful starting points for a PR to the docs:
Example (on 1.0.3), dependency on method redefinition:
julia> @noinline f(x)=x+1;
julia> Base.@pure g(x) = f(x);
julia> h()=g(3);
julia> h()
4
julia> f(x)=x+2;
julia> h()
4
I wonder if this could be revisited once eg #32368 is merged.
Base.@pure at least has a docstring as of #27949. I will say that the current docstring is somewhat unsatisfying as far as actually understanding usage of @pure in Base. Many places where @pure is used rely on generic functions, and some even have side-effects.