Main point: Object oriented programming is inherently stateful. This fits well for some applications and can confuse and reduce reliability for others.
Take a look at following code snippet:
optimizer = new SGD(...)model1.train(example, optimizer)model2.train(example, optimizer)
A question bids: Should i initialize an optimizer for each model, or can I expect the optimizer to be stateless and merely reference static functions?
From the above example, it is not clear if the newly initialized object is stateful or stateless. Whether a computation unit is stateful or not is architecturally important. In the above example, the difference would yield bugs that are near impossible to locate.
On the other hand, take a look at following example:
optimizer = lambda x : ...model1.train(example, optimizer)model2.train(example, optimizer)
In that example, it is much more clear that the optimizer indeed is pure (if
that was intended). However, this is not idiomatic in a language like Python.
Furthermore, we are not ensured that the optimizer
function as defined is
stateless. In languages like Python, JavaScript, Typescript, variables
outside of scope can be mutated.
In some languages, like Haskell, all functions are pure and all state has to be supplied directly to the function. Here mutable structure can be implemented in monads. But when just skimming a program, the programmer always knows what data a function has access to.
Pure functions are nice to use when statelessness is guaranteed. They are versatile, can be reused and worked into programs in flexible ways. The knowledge that a function is pure gives us peace at night. It is easier to verify that we did not overlook something.
Stateful objects are useful when working on complex data structures that benefit from mutability. The class definitions allow for a clear separation between a clean interface a messy internal state. Classes provide the tools to ensure only operations that satisfy the invariants are publicly available. Key examples are tensors where we don't want to be wary about access to individual elements but want to expose functions like addition, subtraction, multiplication, dot product, etc.