27

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();

3 Answers 3

20

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 used as an output argument, only passed into the method 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.

8
  • 3
    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
    Commented Jun 16, 2016 at 21:57
  • 2
    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
    Commented Jun 17, 2016 at 13:28
  • 2
    @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
    Commented Jun 17, 2016 at 13:41
  • 2
    @DocBrown I understand that avoiding output argument contributes in a more readable code, but I can find a proper meaning of output argument in your answer. Can you help me with it ? Commented Jun 11, 2021 at 10:02
  • 1
    @KalsangDorjee He means an argument passed into the function for the purpose of taking output. In a technical sense any argument which the function mutates in place would be an "output argument", but I think the term is also meant to convey intention, not just a technical definition. Commented Jul 11, 2022 at 3:34
13

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.

2

I believe this speaks more of avoiding side effects in a function, a function should be clear on what it is doing and should return it well and not just have a subtle change on the system that we might not easily see.

If a function is actually mutating an entity, then maybe it should be a method on that entity context.

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