4 ms·
A function simply annotated with pure is sometimes called "weakly pure". If its arguments are declared immutable, it is "strongly pure" which essentially matche
by qznc 12y ago
A function simply annotated with pure is sometimes called "weakly pure". If its arguments are declared immutable, it is "strongly pure" which essentially matches your definition.
All languages I know (e.g. Haskell) make concessions to pragmatism. For example, even pure function can somehow create debug output. Every memory allocation does mutate global state.
The weakly pure class of functions is useful. It limits the potential side-effects to stuff reachable from mutable arguments. For example, a image filter function can be weakly pure while it mutates the image provided as an argument. It removes the need allocate a return image or wrap computations in monads and thunks.
To get really strong guarantees in D, you declare your functions pure, nothrow, and @safe. The nothrow means no exceptions are thrown and @safe means all the low-level tricks (casts,assembly,etc) to break type safety are disabled.
- T-R 12y agoThat still means the function can't be treated as referentially transparent (whereas a Haskell function with debug output still can be, for the most part). Don't get me wrong, that's still somewhat useful - it tells me "this function doesn't do anything too crazy", but it doesn't tell me "it should be safe to refactor this without having to read the function bodies of the entire call graph below this point", which makes calling it "pure" seem a bit disingenuous.
- qznc 12y agoGiven pure + @safe + immutable arguments, how is it not referentially transparent? (we ignore the practical concessions: debug statements, memory management, termination, floating point hardware state)
- T-R 12y agoI'm not saying it isn't - it's certainly good that it's also possible to declare something as referentially transparent, but defining the keyword "pure" to imply something much less than referential transparency is still a poor choice. Edit: To be clear, I don't really feel too strongly about it. It's still leagues ahead of many other languages - I just think that particular choice of keyword is likely to confuse things a bit.
- sophacles 12y agoIn D, if a function is pure, can it call a function that modifies global state? That is to say (in not necessarily real D, just close enough) given: int global_var void modify_global(int z) { global_var += z; return global_var; } pure int foo(int x) { return x + modify_global(2); } What happens? Does the compiler barf because it causes modification to something not passed? If so, assuming that you can only modify the object passed (via methods of it, and presumably, the things that object points to in its members), then it maintains something much closer to referential transparency than you are implying.
- nbm 12y agoThe compiler says: /d111/f857.d(9): Error: pure function 'f857.foo' cannot call impure function 'f857.modify_global'
- T-R 12y agoBut that's a pretty low bar. Using just 'pure', can you mutate an argument in a function called in a conditional expression (making it unsafe to check again)? Can it matter what order a list gets processed in a call to `map` or `filter`? Preventing mutation of global variables narrows the scope of the damage, but having just that still means that if you're maintaining someone else's code, you need to double check everything for side effects, even if they'd be limited to the inputs.
- WalterBright 12y agoDeclare the parameter as 'const' and you know the pure function cannot mutate it. Declare it as 'immutable' and you know that nobody else can mutate it, either.
- WalterBright 12y ago> In D, if a function is pure, can it call a function that modifies global state? Nope (it would be a useless feature if it could).
- jahewson 12y ago> All languages I know (e.g. Haskell) make concessions to pragmatism. For example, even pure function can somehow create debug output. Every memory allocation does mutate global state. This still satisfies the definition of a pure function because debug output via trace is not a "semantically observable" side-effect. I think that D would be better off inventing some new terminology instead of misusing existing formalisms: a function which modifies its own arguments isn't even close to being pure.
- WalterBright 12y agoA "strongly pure" function in D is a traditionally pure function, and can be detected by the parameters having const types. const types in D are transitive, meaning that any data reachable through those types is also const. I.e. "turtles all the way down."
- wyager 12y ago>All languages I know (e.g. Haskell) make concessions to pragmatism. For example, even pure function can somehow create debug output. From the Debug.Trace docs: "should not be used in production code." >Every memory allocation does mutate global state. Yes, Haskell is approximately pure just like computers are approximately Turing machines. Computers are technically FSMs, but they're practically so close to Turing machines that we usually don't care. Haskell is so close to pure that we don't care. It's also guaranteed to be semantically pure, until you start to run into those edge cases where computers don't act like Turing machines (i.e. when you run out of RAM). >It removes the need allocate a return image or wrap computations in monads and thunks. No one is arguing that impurity/mutability is (frequently) useful. I'm just arguing that it's disingenuous to call what you've described "pure", or that this extra "purity" is very useful.
- deleted 12y ago[deleted]
- WalterBright 12y agoThe reason for "weakly pure" was first discovered by Don Clugston (as far as I can tell). Suppose I have a struct with a member function: struct S { int s; pure void set(int i) { s = i; } Now, even in a strongly pure function, I can use the weakly pure function even though it is mutating state through its arguments: pure int foo(int i) { S s; s.set(i); ... return whatever; } I.e. when the effects of a weakly pure function are localized like in the example, they can be called from a strongly pure function and the strongly pure one will remain strongly pure. It's a really cool idea and it took me a bit to get it, but Don was persistent in explaining it to me :-)