13

On page 45 of Robert C. Martin's Clean Code: A Handbook of Agile Software Craftsmanship, Martin writes that output arguments should be avoided. I'm having trouble understanding the meaning of "output argument" and why they should be avoided.

Martin's example for an output argument appendFooter(s); calls the function public void appendFooter(StringBuffer report). His improvement of the code is report.appendFooter();

Maybe it is due to the lack of code context, but I don't see how using output arguments is considered poor coding. Could someone explain the concept or give addition example of code to understand this?

Would the following function also be considered an example of unclean code by the above principle?

int[] numberArray = {3, 5, 7, 1};
sortArray(numberArray);

If the above is a violation of Martin's principle of not using output arguments, would it be better to have an object that has an array as a field and a function that can be called to sort the array?

ObjectWithArrayField numberArray = new ObjectWithArrayField(3, 5, 7, 1);
numberArray.sort();
10

Bob Martin is simply talking about readability.

The problem with the appendFooter example is, if you find the code line appendFooter(s) somewhere in a program, it is not immediately obvious if that call takes s as an input and appends it somewhere, or if s is just passed to take the output of that function. To be sure, you need to check the function's documentation. A call like report.appendFooter(), however, avoids that problem: it is much more obvious now what happens.

Note, however, Bob Martin does not say "never ever use output arguments", he says "in general, you should avoid it, because it will help you to keep your code a bit more cleaner". So this is not a braindead cargo-cult rule one should follow blindly.

Sort methods for standard arrays and collections are a little bit different. Having the sort method a member function of each standard array datatype would have a few drawbacks from the language designer's point of view, for example, having a method like Array.sort allows to keep this in the standard library, outside of the Java runtime. But if you would create an individual collection type which has to be sorted sometimes, adding sort as a member function might be indeed a better idea than putting that into a separate class.

  • 2
    sortArray(numberArray), of course, sorts numberArray in place. Or does it make a copy of numberArray, sort the copy, and return the sorted copy without altering numberArray at all? – 8bittree Jun 16 '16 at 21:57
  • @8bittree: that is true, but that is not the point of dicussion here - a sort() method of a container can work in-place as well, without using an "output argument". So just because sortArray(numberArray) is an in-place method is absolutely no reason which justifies the "output argument form". – Doc Brown Jun 17 '16 at 6:11
  • 1
    My point was more that it's not entirely obvious what sortArray(numberArray) is doing. It can be obvious if it does not return the same type that it accepts, then it must be in place. But without seeing the return type, or if the return type matches the input type, its unclear without looking at the definition. – 8bittree Jun 17 '16 at 13:28
  • 1
    @8bittree: Ok, you got me, I removed the statement in stake from my answer. However, the problem your describe does not vanish by using a member function - even a "sort" member function could behave that way. – Doc Brown Jun 17 '16 at 13:41
10

It's a matter of using an unexpected mechanism for returning a value from the function, which is usually a result of doing too much in the function or having misaligned responsibilities. By far, the best way to communicate a function's result is to use the return value. I hope that's self-evident. In object-oriented languages, the second-best method is to mutate the object.

Between those two options, there are so many clean, obvious ways to communicate a function's result that if you ever find yourself wanting to mutate the arguments as the only means, something has gone awry in your architecture. You need to rearrange your class responsibilities so the one doing the mutating owns the data in the first place.

The one exception is for very generic algorithms. For example, a sorting algorithm might rightfully be separate from the containers it sorts, if it can be generically applied to any type of container using its public interface. A one-shot appendFooter function doesn't have that excuse.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.