I’ve seen a relatively common anti-pattern in Object-Oriented development, although to be fair, I’ve seen something closely akin in non OO languages as well. The following C# code is a demonstration of the issue:
using System; public class C { private int _m; public C(int myInitialValue) { _m = myInitialValue; } private void f() { if (_m > 0) { _m = 1; } else if (_m <= 0) { _m = 0; } } }
Can you spot the problem?
The problem is the constructor and the f function using the class variable _m directly. What could be wrong with that, I hear some of you asking? A few things:
1.) Let’s say I need to use the functionality of f somewhere else. I now need to take _m with the code. Big deal I hear you saying—I need to remember to copy a variable. Now pretend that f accesses not just one member variable but that it accesses three or four member variables. To say it in a little more technical way, there’s now a coupling between f and _m (and any other member variables we might use within f).
2.) By referencing _m within f but not passing it in f’s parameter list, I’ve made f a bit less of a black box. And I’ve modified _m but it’s not obvious outside of the function; I have to look at the contents of f to see that _m is modified. Again, with only one variable this is probably not a big problem, but consider the case where I’m referencing 3 or 4 member variables or maybe even more.
3.) Now consider the case where we need to guard the values put into _m or I need to transform the value in _m when I read it. No problem, you say, simply add an inspector and mutator to the _m member variable. And that would be great but it wouldn’t fix the problem in f because f is accessing the member variable directly.
Basically all of the problems that convinced people that using global variables is a bad practice are present in this way of using class level member variables. The irony is that developers who’ve grown up with the dogma that global variables are a very bad practice which should be avoided at all costs think nothing of writing code like this.
Now, as I often point out to people, we’re discussing engineering not religion; very few things in engineering are absolutely always right or always wrong. However I cannot think of many cases where direct access to a member variable in a class is a better approach than either passing the value explicitly as a parameter, returning the new value explicitly or accessing the member variable via an inspector or a mutatator.
Yeah, internal mutation is one of my pet hates, those dreaded void functions can be troublesome once you get into multi-threading.
Yes I can see where you are going and comming from FP I’m on your side. But in OOP land this is not a anti-pattern but a pattern. If you read Uncle Bob you will find that he usually refactors parameters into member-variables and indeed it is not a problem if you really do SOLID because of the small size your classes will have.
@Carsten,
I think that sort of thing, following the SOLID principle, is more true in theory than in practice. And I still think of this behavior as an anti-pattern regardless of what Uncle Bob has to say about it. It promotes coupling and lowers cohesion.
I guess the question is does one develop patterns based upon ideal behavior or does one develop patterns based upon what real developers actually do.
While I agree that using _m inside the method f directly is bad, initializing _m inside the constructor is just fine. The primary purpose of a constructor is to initialize data members to sane values on instance construction. Initializing a data member by calling the associated mutator method inside a constructor incurs excessive overhead of function calling if there are many instances of the type created in a tight loop. While an instance method can be called many times over the lifetime of an object, a constructor method is only called during the instance construction.
A fair point. I’m more concerned about direct accesses to the member variable from class methods. I think it’s wisest to route all accesses through the same code but I understand your point.
I’m with you there, and it’s a problem others have noted. For instance John Carmack refers to this when he writes “the potentially large set of state in the object” and “many object are large enough to constitute a sort of global state all their own” in his article about functional purity in C++ http://www.altdevblogaday.com/2012/04/26/functional-programming-in-c/
I think that’s one of the reasons why OOP got so popular. It made global variables “clean” again. That and inheritance for code reuse.
Hi Johann,
I had written this before I saw John Carmack’s essay but I think he pretty much nailed it as far as this issue goes.
Don’t misunderstand me; I don’t object to a few module level variables used cleanly. But for most developers, the Single Responsibility Principle for classes seems to be lip service rather than genuine practice.