I am reading about common code smells in Martin Fowler's Refactoring book. In that context, I was wondering about a pattern I am seeing in a code base, and wether one could objectively consider it an anti-pattern.
The pattern is one where a object is passed as an argument to one or more methods, all of which change the object's state, but none of which return the object. So it is relying on the pass by reference nature of (in this case) C#/.NET.
var something = new Thing(); // ... Foo(something); int result = Bar(something, 42); Baz(something);
I find that (especially when methods are not named appropriately) I need to look into such methods to understand if the object's state has changed. It makes code comprehension more complex, since I need to track multiple levels of the call-stack.
I'd like to propose to improve such code to return another (cloned) object with the new state, or anything that is needed to change the object at the call-site.
var something1 = new Thing(); // ... // Let's return a new instance of Thing var something2 = Foo(something1); // Let's use out param to 'return' other info about the operation int result; var something3 = Bar(something2, out result); // If necessary, let's capture and make explicit complex changes var changes = Baz(something3) something3.Apply(changes);
To me it seems the first pattern is chosen on the assumptions
- that it is less work, or requires less lines of code
- that it allows us to both change the object, and return some other piece of information
- that it is more efficient since we have less instances of
I illustrate an alternative, but to propose it, one needs to have arguments against the original solution. What, if any, arguments can be made to make the case that the original solution is an anti-pattern?
And what, if anything, is wrong with my alternative solution?