Fun One Liners

I wouldn’t call this “not very well documented” https://docs.julialang.org/en/latest/base/base/#Base.@pure :

@pure gives the compiler a hint for the definition of a pure function, helping for type inference.

A pure function can only depend on immutable information. This also means a @pure function cannot use any global mutable state, including generic functions. Calls to generic functions depend on method tables which are mutable global state. Use with caution, incorrect @pure annotation of a function may introduce hard to identify bugs. Double check for calls to generic functions. This macro is intended for internal compiler use and may be subject to changes.

In particular, I think it is very clear that you can’t use generic functions inside @pure functions. Please notice that this is incompatible with your usage:

I think it’s OK to depend on implementation details in some private code or maybe even in public code if you are aware that is an implementation detail and hence cannot rely on the semver promises. For example, ForwardDiff.jl uses Threads.atomic_add! inside @generated generator which also is documented that it must be pure. Also, there are (many?) packages using @generated to hoist out argument checking to compile time. Since throw is a side-effect, this is arguably not a valid use case. CUDAnative.jl is mentioning that it can be a real trouble if you want to use it with GPU: https://juliagpu.gitlab.io/CUDAnative.jl/man/hacking/#Generated-functions-1

@NHDaly’s JuliaCon talk is a great summary of the current status on this topic and explaining why you can’t use @pure or @generated in this way safely:

Personally, I often just lift values to type domain as soon as possible and compute things using recursion.

5 Likes