It's a function that computes the same value, every time you call it with the same arguments, and depends only on those. The value can not depend on time or any mutable state outside of it.
It also can not have any side effects, like throwing exceptions or printing to the console.
This has a lot of benefits for reasonability, testability and compiler/runtime optimization, but can sometimes lead to code that's painfully explicit.
Not really - having each function do a precise task is a general good practice, not a quality of pure functions. A setter, for example, is an impure function that does a precise task.
I converted the array to an object, but the function is still pure(or, more precisely, can be pure - I didn't write Obj.__init__'s body and Python does not guarantee function purity). We still have the original array - we did not change existing values, only returned new ones.
A better example will adding an element to an array:
FP is not about eliminating side effect at all, because a software that does not has any side effect has no use at all. Instead, FP is about making as much area of your code to be pure function so that they are predictable and consistent, while allow only specific module to be impure, i.e. having side effect.
I would think so, yes. You find that most Smalltalk-inspired OOP advocates tend to view sharing of data as a bad thing. Instead, data is private to an object, and you just tell the object what you want it to do (by sending it a message or invoking a method). The object then induces local mutations to itself. It's still not technically a pure function, but this flavor of OOP follows the spirit of not mutating a shared external state. Because that's what makes programs hard to change over time.
A pure function has additional benefits like thread safety.
The two conditions you need for a function to be pure.
The return value of a function depends only on the input parameters.
External values cannot be mutated (input values, globals, etc.).
Example violations.
letmutablex=1letaddXvalue=value+x// violates #1// x is not an input parameter.// probably would still be ok if x was immutable.
typeMyType={mutableAnInt:int}letaddxmyType=// violates #2, mutates the inputmyType.AnInt<-myType.AnInt+x
Mutations to shared data are what makes code hard to follow and hard to fit in your head. This is sometimes called hard to "reason about".
The challenge of FP is figuring out how to get all significant decisions into pure functions. That way they are easy to test and reason about. Then push all side effects out to the impure edges of the application.
Yep. Technically, a mutation of a local, private variable (i.e. not passed by reference in or out), or using a out-of-scope (e.g. global) variable which doesn't change during program execution... both still allow a function to be pure. Such side effects do not affect the caller or any callees.
However, these are not great habits for FP learners to start with. I tend to only do local mutation for performance optimizations. Most of the time they aren't needed.
Modeling with pure functions is difficult at first, particularly if you know imperative programming well. In fact it took me a while to get used to it. But it eventually becomes familiar, and not any harder to do than procedural or OOP. Then you start to wish you had discovered it a lot sooner.
The payoff is well worth it. Primarily because pure functions have linear risk/cost to refactor. I don't know about you, but my experience previously has been that refactors to core code can have an unknown risk of breaking other things... but not so with pure functions. When you look at a function, what you see is what you get... no mysterious external, runtime state changes to account for. Refactorability is a benefit that pays dividends for many years to come. And as I said, once it becomes familiar its not even any more work (and perhaps less) than other methods. The main trade-off is the upfront cost of learning it.
Pure functions are also quite easy to test. If all your significant decisions are in pure functions, you don't really need mocks, fakes, and extensive test frameworks. You just need to vary the inputs and check the outputs. Testing logic is low-cost and easy. Testing side effects becomes integration testing (part of CI workflow, not in unit tests).
For further actions, you may consider blocking this person and/or reporting abuse
We're a place where coders share, stay up-to-date and grow their careers.
What's a "pure function"?
It's a function that computes the same value, every time you call it with the same arguments, and depends only on those. The value can not depend on time or any mutable state outside of it.
It also can not have any side effects, like throwing exceptions or printing to the console.
This has a lot of benefits for reasonability, testability and compiler/runtime optimization, but can sometimes lead to code that's painfully explicit.
I get it, each function have to do a precise task.
Thanks man :)
Not really - having each function do a precise task is a general good practice, not a quality of pure functions. A setter, for example, is an impure function that does a precise task.
Ok, but you sometimes NEED to do impure function no ?
How could you not change the type of some variables ?
Ex :
You want to get array data to convert into object, you need to do an impure function no ?
Not really:
I converted the array to an object, but the function is still pure(or, more precisely, can be pure - I didn't write
Obj.__init__
's body and Python does not guarantee function purity). We still have the original array - we did not change existing values, only returned new ones.A better example will adding an element to an array:
foo
is impure, because it changes an existing value.bar
is pure, because it does not change an existing value - it creates a new one.Now I got it !
Last question, why do we have to do this ?
FP is not about eliminating side effect at all, because a software that does not has any side effect has no use at all. Instead, FP is about making as much area of your code to be pure function so that they are predictable and consistent, while allow only specific module to be impure, i.e. having side effect.
.. So, pure function could also be a priority for OOP no ?
I would think so, yes. You find that most Smalltalk-inspired OOP advocates tend to view sharing of data as a bad thing. Instead, data is private to an object, and you just tell the object what you want it to do (by sending it a message or invoking a method). The object then induces local mutations to itself. It's still not technically a pure function, but this flavor of OOP follows the spirit of not mutating a shared external state. Because that's what makes programs hard to change over time.
A pure function has additional benefits like thread safety.
Ahah thread.. I'm doing PHP :(
The two conditions you need for a function to be pure.
Example violations.
Mutations to shared data are what makes code hard to follow and hard to fit in your head. This is sometimes called hard to "reason about".
The challenge of FP is figuring out how to get all significant decisions into pure functions. That way they are easy to test and reason about. Then push all side effects out to the impure edges of the application.
Just "the input values"?
Yep. Technically, a mutation of a local, private variable (i.e. not passed by reference in or out), or using a out-of-scope (e.g. global) variable which doesn't change during program execution... both still allow a function to be pure. Such side effects do not affect the caller or any callees.
However, these are not great habits for FP learners to start with. I tend to only do local mutation for performance optimizations. Most of the time they aren't needed.
"The input values cannot be mutated" implies that global or closure variables can be mutated.
Nice catch. I revised the wording.
It seem to me ok but.. really hard and annoying.
Why do FP need pure function ?
Modeling with pure functions is difficult at first, particularly if you know imperative programming well. In fact it took me a while to get used to it. But it eventually becomes familiar, and not any harder to do than procedural or OOP. Then you start to wish you had discovered it a lot sooner.
The payoff is well worth it. Primarily because pure functions have linear risk/cost to refactor. I don't know about you, but my experience previously has been that refactors to core code can have an unknown risk of breaking other things... but not so with pure functions. When you look at a function, what you see is what you get... no mysterious external, runtime state changes to account for. Refactorability is a benefit that pays dividends for many years to come. And as I said, once it becomes familiar its not even any more work (and perhaps less) than other methods. The main trade-off is the upfront cost of learning it.
Pure functions are also quite easy to test. If all your significant decisions are in pure functions, you don't really need mocks, fakes, and extensive test frameworks. You just need to vary the inputs and check the outputs. Testing logic is low-cost and easy. Testing side effects becomes integration testing (part of CI workflow, not in unit tests).