If you push the idea of 'minimize state' a little farther, you end up at immutable objects. They're pretty common in functional languages (I think Haskell and most/all of the ML family treat variables as immutable by default), but they can be super useful in OO code too. Most OO languages have immutable string objects, for example (Ruby is the notable exception I can think of). You get huge benefits in terms of how easy it is to reason about your code when you're dealing with strictly immutable objects. Consider the following pseudocode:
- Code: Select all
define foo(arg):
temp = arg
bar(arg)
assert_equal(temp, arg)
If arg is an immutable type, we know the assertion will always pass. No matter what bar() does, it can't modify arg, only make copies of it. If arg is a mutable type, then we can't know whether the assertion will pass without also knowing the entire implementation of bar() and everything it calls. I once spent several person-days digging through around a dozen KLOC whose original authors were sadly missing to ensure that a set of objects weren't changed by any of the functions that used them so that I could reorder some method calls near the top of the code. Not pleasant, and could have been avoided my type system could have assured me that the types were immutable.
Another thing that I've noticed myself doing differently after spending more time working in functional code is paying a lot more attention to the order of arguments to my functions. When I have partial application and currying it makes a lot of difference to my future happiness whether I make a function map(func, list) or map(list, func). The first is more often reusable. It doesn't come up as often in OO code, but I like being able to voice a reason why my arguments in in a particular order.
Fundamentally, a lot of what gets lumped together as 'functional' style are techniques and language features that tend to make it easier to reason more clearly about code. Part of this is because a lot of functional languages can trace their ancestry back to lisp, which (especially when expressed as Scheme) is pretty close to raw lambda calculus. Part of it is because functional languages, historically, have been more popular in academia, where being able to reason about a program is often more important than getting it shipped for the Q3 sales cycle. And part of it is because those things do actually tend to make it easier to reason about the code.
As long as I am alive and well I will continue to feel strongly about prose style, to love the surface of the earth, and to take pleasure in scraps of useless information.
~ George Orwell