What can _not_ be marked pure?
Jonathan M Davis via Digitalmars-d-learn
digitalmars-d-learn at puremagic.com
Wed Mar 9 05:12:18 PST 2016
On Wednesday, March 09, 2016 09:56:05 Guillaume Piolat via Digitalmars-d-learn
wrote:
> If I understand purity correctly
> (http://klickverbot.at/blog/2012/05/purity-in-d/), every function
> out there can be marked pure as long as it doesn't modify
> globals, shared variables or do I/O?
>
> It seems more function can be marked pure that I previously
> thought.
Basically, a pure function cannot call a function which is not pure, and it
can't access any global or static variables which are mutable (or const if
the type has indirections - the variable has to be completely unchangeable
to be accessible). And that's it. shared has nothing to do with it one way
or the other, and I/O isn't explicitly forbidden, but not being able to
access mutable globals or non-pure functions naturally kills I/O. The
exception is that inside of debug{} blocks, purity is ignored, so you can do
I/O there, but it's intended purely for debugging purposes.
So, in general, you can slap pure on most anything, though it will rarely
buy you anything in terms of performance. What it primarily buys you is the
knowledge that you're not messing with global variables unless the
function's arguments give you access to them. The second major gain is that
in many cases, a pure function's return type can have its constancy
inferred, making it possible to allocate a mutable object inside of a pure
function, do whatever needs to be done to it to set it up, and then have it
implicitly converted to immutable when it's returned (for that to work
though, the compiler has to be able to guarantee that the return value
didn't come from any of the function arguments).
The main place where performance gains could take place would be in cases
where a pure function is called multiple times in the same expression with
the same arguments, and the compiler is able to determine that it's
impossible for those arguments to have been mutated between calls, allowing
the compiler to just make the call once and reuse the result. AFAIK, that
currently requires that the function parameters be immutable or implicitly
convertible to immutable, though in theory, it should be possible for const
parameters when the arguments are immutable. Regardless, it's occasionally
useful but not very often. Having lots of pure functions makes it easier to
have useful functions with immutable arguments, whereas when pure functions
always required that the parameters be immutable (or implicitly convertible
to immutable), the really couldn't do much. But the result is that most pure
functions can't really be optimized base on their purity.
The two places that you need to be careful with pure though are virtual
functions and templated functions. If a base class function is pure, then
the derived class overrides also have to be pure, whereas if the base class
function isn't pure, then the derived class function can't normally be pure
(it _might_ be able to be pure if it doesn't call the base class function).
So, when dealing with virtual functions, you have to be careful about
whether you want to avoid restricting virtual functions from being used in
pure code (by not marking the base class function pure) or whether you want
to restrict what derived class functions can do (by marking the base class
function pure).
The reason to avoid pure with templated functions is that whether a
templated function can really be pure or not usually depends on its
arguments. If the types it's instantiated with use pure functions, then it
can be pure, whereas if they don't, then it can't be. So, you'd have a
similar problem to that of virtual functions except that pure, nothrow, and
@safe are inferred for template functions, so if the function doesn't do
anything which makes it so that it can't be pure, the compiler should infer
it to be pure without you needing to mark it as pure.
In general though, you should use pure wherever possible.
- Jonathan M Davis
More information about the Digitalmars-d-learn
mailing list