Improvement in pure functions specification

Jonathan M Davis via Digitalmars-d digitalmars-d at puremagic.com
Fri Dec 23 03:11:09 PST 2016


On Thursday, December 22, 2016 18:04:51 Observer via Digitalmars-d wrote:
> It seems to me that a pure function could have a variety of
> acceptable side effects which don't modify active memory and
> that don't work around the type system or necessarily eat
> significant CPU time, and that you probably don't want to
> have elided.  Here are some examples.
>
> (1) Serve as a convenient breakpoint handle in the debugger,
> perhaps
>      as a kind of centralized this_cannot_ever_happen() function.

I suppose, but that doesn't really have anything to do with what a purity.
Any function could be a point to break in the debugger.

> (2) conditionally_die(conditions);

Depending on what you mean by conditionally die, yes, that's legit. Errors
can be thrown from pure functions (even strongly pure functions), and the
spec specifically allows a pure function to terminate the program (so
calling exit should be legit, though I'm not sure if it's actually marked as
pure).

> (3) Sleep for some run-time-computable length of time.

This doesn't really make sense. It _might_ make sense for a weakly pure
function to do so via a function argument, but once we're talking strongly
pure functions, this doesn't make sense at all. At that point, we're talking
functional purity. The same input is supposed to give the exact same output,
and the compiler is free to optimize out calls to the pure function when
it's called multiple times with the same arguments. So, relying on anything
to do with timing simply wouldn't work, and sleeping in a strongly pure
function just doesn't make sense. It's questionable as to whether it even
makes sense in a weakly pure one. Regardless, right now, it certainly isn't
legal, because there is no sleep function marked as pure in druntime.

> (4) Yield the thread so other threads can take execution priority.
>
> (5) Yield the entire process so other processes can take execution
>      priority.

These both have basically the same problem as sleeping. They may no sense
for strongly pure functions and questionable sense for weakly pure ones and
are not currently allowed in pure functions.

> (6) Wait for an external trigger (perhaps a hardware interrupt,
> for
>      instance).

This definitely does not sound legit. It explicit depends on the OS state,
which is the sort of thing that's generally banned in pure functions.

> (7) Invoke a pass of garbage collection.

This, however, would probably be legit for the same reasons that new and
malloc are considered pure. Certainly, most of core.memory.GC is either
marked as pure or /* FIXME pure */, and given that GC.free is already pure,
having GC.collect be pure would make sense.

> My point here is that when considering what functions do, mutating
> memory is only part of the story.  Control of time and other
> resources
> can be a critical part of overall program execution, and you
> don't want
> the compiler assuming it can ignore such aspects.

Conceptually, it makes no sense to be doing any of that sort of thing in a
strongly pure function, because at that point, we're really talking
functional purity. The same input is supposed to give the same output, and
while it's debatable whether timing is part of that, it would have to at
least be taking the same actions given the same input. And if the compiler
has to worry about how the timing of a pure function affects the program,
then it could _never_ elide a call to a pure function, which would defeat
one of the main reasons that the feature was introduced in the first place.
So, I'm inclined to think that anything with regards to timing has no
business in a pure function.

- Jonathan M Davis



More information about the Digitalmars-d mailing list