Jon Lang wrote:
I'm not saying that it needs to decide whether or not you have a
halting problem; I'm saying that if there's any possibility that you
_might_ have one, you should stop looking.  Let's take it as a given
that things such as exceptions, threads, and co-routines make the
automated establishment of whether or not a given function is pure a
nightmare.  The easy solution for this would be to say that if a given
function makes use of exceptions, threads, or co-routines, it will not
be auto-tagged as pure.  The process of auto-tagging pure functions
would not be perfect, in that there are likely to be a number of
functions that are in fact pure but don't get auto-tagged as such; but
it could still be _good_, in the sense that a useful set of pure
functions _would_ be auto-tagged.

One thing I want to make clear is that any validation of purity or auto-tagging of said should be based on a whitelist, not on a blacklist. You have to think of this like you think of security. Don't look for a list of things that might give you problems, rather look to see if you have anything at all that isn't known to be safe. A given entity (type/routine/etc) is pure iff all of its dependencies (referenced types or operators etc) are pure. Any unknown means unpure. To start off with, all the system-defined (defined in the Perl 6 synopsis documents) types and operators should be explicitly tagged as either pure or impure. Then when compiling user code, we know that code is pure iff all of its dependencies are either said system-defined pure ones or are each other. And yes, as you said, if in doubt, mark unpure.

I would also like to disagree with the idea that using exceptions means impure; I believe they can go together fine.

Specifically, I believe it is just fine for a pure routine to throw an exception, though on the other hand perhaps a pure routine shouldn't be allowed to catch an exception; a thrown exception in the pure sandbox would cause that particular in sandbox call stack to return early with the net result being a no-op (save thrown exception), and an impure caller routine can then catch it if it wants.

The fact the contents of the call stack could be arbitrarily compiler reordered doesn't change these semantics as seen outside the sandbox. In fact, one point of a pure sandbox is that an outside caller can in some respects just see the thing they directly call as an opaque thing which either succeeds and returns a valid answer for its declared type or it fails with an exception.

One reason that supporting exceptions from pure routines is good is that a runtime exception is how you handle the general case of bad input. I say the general case because, while some things can be caught by the compiler (such as passing a Str typed variable to something wanting an Int), some arbitrary input constraints are too complicated and effectively become runtime checks anyway, since even determining if you have a violation at all could require a lot of runtime calculations and many routine calls.

There are also other exceptions you can have due to, what in the broad sense isn't a type violation but in the strict sense is, such as numerical division. I don't think anyone would argue that numeric division is a pure function, and yet you can't get a normal answer if you give it a divisor of zero. Attempting to do so, you'd probably want an exception as a result.

Now this all said, one alternative is Perl's Failure type, the unthrown exception, which may be a way around actual exceptions. I suppose that if all the pure routines knew how to special case an input of Failure and just abort and return Failure themselves, we can skip an actual exception. Particularly useful in those cases where you don't want your rocket to shutdown because one of a hundred redundant sensors failed. Except in some ways that is a bad example because reading from the environment like a sensor would never happen within the pure sandbox; it would have to happen prior to entering the sandbox and the sandbox be given a Failure input and hence abort. So in the end we effectively still have a thrown exception. I think our code would be cleaner if we can just use exceptions and not have to check return values.

Now, all this assumes that throwing an exception has no side-effect besides the sandbox returning/throwing failure, and I assume an exception object is effectively pure itself.

So, I see no problems with exceptions in a pure environment.

I also don't think threads are necessarily a problem. If all the inputs to the pure sandbox are immutable values, and all called routines, that is the metamodel / classes / etc, are an immutable snapshot as of the sandbox entry time, and the pures don't see globals, then no thread can interfere with another within the pure sandbox.

Co-routines, if they are pure routines, I don't expect to be a problem either, but I'm less sure about that one. Actually, doesn't Haskell have co-routines, or am I mistaken; how does Haskell do laziness relative to thoughts for Perl 6?

-- Darren Duncan

Reply via email to