-
Notifications
You must be signed in to change notification settings - Fork 0
Separating pure functions from those with side effects
I think there's benefits to exposing "pureness" to the programmer. I agree that not allowing printf's is annoying, but I don't think it's actually necessary. Depending on input is inherently non-functional in that the function return then depends on evaluation order. Producing output is only non-functional if you view the output of the program as part of the function return. I you don't care what order the output comes in then you can execute printf's in any order and it's fine. I do this all the time in parallel make and rake files. So I think that allowing printf's in pure functions is fine. We could issue a warning in a given session when the user does it the first time.
The syntax is obviously less important than the functionality, but if there's a significant difference in what you allow in the different subroutine constructs I don't actually think using different keywords for them is all that bad. I view procudures as more like matlab script files now, but with parameters and a return value.
The motivating concern for me in thinking about this was comprehensions. It would be really surprising if the expression in a comprehension had side effects. It would also require a well defined evaluation order. We would then have to ensure that at least the appearance of that order was followed. I also think I would almost completely prevent the kinds of optimizations I gave examples of in the comprehensions page.
Even if the compiler can reason about what's pure and what's not, I think it's important—almost equally so—fo the programmer to be able to reason about it. Almost all library code should be side effect free. If it's patently clear when something isn't, this will tend to enforce that. It's just bad library design to use global variables.
And then there's the + issue: the general pint here is that I you expect pure behavior from something and then overload tha behavior, you will be surprised and probably unhappy if the subclassed/overloaded behavior is less restricted than the original behavior. This is kind of like the oo business of having private and protected members—except IMO way more important and deserving of compiler and language support.
What do you do about higher-order functions?
To put this under user control, I much prefer having something that looks more like a declaration so it doesn't look like we threw in two separate constructs where one would do. For example GCC allows declaring functions pure. I also support compiler purity analysis, so the user doesn't have to do anything (that's best of all!) As long as this analysis is only used for optimizations and doesn't affect the behavior of the program it's fine. Maybe it's possible to give warnings for almost-pure functions, or point the user to functions that might be pure so they can add a declaration.
So basically, yes, the purity concept has to be in there eventually, I just think this syntax makes the language look too complex.
Let me just say that I don't think the "not affecting program state" thing should be completely strict. First there's the allowing printf's business. But there's also things like having counters, collecting trace and debugging info, etc. But I think if there's facilities for letting some things safely and appropriately escape in a parallel/optimization friendly way these could be ok. I'm thinking of Cilk hyperobjects and how they allow a lot of operations that would normally be data races to be done without creating a data race.
I like the idea of marking functions as pure. I however do not like the idea that a matlab programmer who uses julia and writes a function discovers that julia will barf if it has side-effects. I am happy to experiment with what this should mean through a directive or a decorator - something that can be subsequently silently modified or ignored.
Viral 07:08, 9 September 2009 (UTC)