5

So let's say I have a 'Transformer' interface that can transform one file-type to another. Let's say I also wish to use streams to provide the data to the Transformer. Which is the approach that is considered 'best practise';

public InputStream transform(InputStream data);

OR

public void transform(InputStream originalData, OutputStream newData);

Although the first method seems to be slightly more concise to me (ie, you get an inputstream that you can consume immediately) it seems to violate the whole 'creator of a stream should be the one who closes it' principle.

The second method, whilst needing a bit more work on the part of the client to handle the outputstream, seems like it might be more useful in some cases (ie, passing a ServletOutputStream as the 'newData' argument) and the client code will handle all opening/closing of streams.

I am leaning towards the second method but I have seen both used in various APIs I have come across and am wondering if there are situations where one would be preferred over the other?

1

3 Answers 3

3

Returning an Input Stream enables your calculation to be performed on an ongoing basis as data is read from it, potentially even in a separate thread. It is equivalent to a unix command line pipe. If the processing takes a significant time to complete, this will effectively hide that processing time from the user by distributing it (or shunting it off to another core) and returning results a little at a time. You can easily build up multiple stages of transformation.

When passing an output stream, it's like using the old pre-windows DOS prompt: fine if all you're doing is sending data straight back to the user, but if not you'll have to store it temporarily somewhere (either a file or a ByteArrayOutputStream) before continuing the processing. This will introduce delays before any output is produced, makes taking advantage of multiple cores harder, and uses resources unnecessarily.

Additionally, you state that there is a general rule that the opener of a stream should close it, but I don't think this is the complete rule. I believe the rule that the java IO system is built around is best phrased as "the opener of a stream should be responsible for closing it, unless it is later wrapped in another object which also provides a close method, in which case the opener should call that method instead, which should then close the original stream on the opener's behalf." This is what you do, for example, when using a BufferedInputStream.

All of this suggests that the former should generally be preferred, but it is worth noting that for many complex transformations, the latter is much easier to implement (assuming you do not wish to use multiple threads). This may way in favour of the former in some cases, but note that if a multithreaded solution is preferred, code in the latter style can be adapted to the former interface by placing in its own thread and using a Piped*Stream pair for communication. Thus I'd say that other than very simple cases the former is best, but the latter might be acceptable and easier if you have a simple case and/or don't want to get involved with threads.

2

Generally speaking, using output parameters is considered bad practice. After all, the return value is meant to be the result of the computation that the function performs. The parameters are supposed to be the inputs for that computation and exporting the result through a parameter is just semantically wrong.

I found a more detailed answer on StackOverflow. The question there is about c# but the answer applies to other programming languages too.

If you want an answer more specific to your problem, please post the body of your methods.

1

This is an interesting question that goes deeper than it looks. Here's my view on the topic.

First of all, just by looking at the two method signatures, I can tell that the semantics and behaviour are different, so picking one or the other is not just a stylistic choice.

In particular, the second form has a built-in side-effect of writing the result of the transformation into the output stream. Also, the second form implementation has to be fully synchronous and blocking, that is, it returns to the caller only after the full InputStream is consumed and transformed and written into the output stream.

On the other hand, the first form suggests an asynchronous, lazy interface that immediately returns control to the caller.

The other big difference between the two is in terms of composability. The first form can easily allow chaining of multiple transformations with the added benefit of reducing the memory footprint.

Based on the above, the first, more functional form, should be preferred.


Unfortunately, there are still other relevant characteristics that are left out unspecified by the type system and the method signature. These are usually worth documenting. For example:

  • Is the implementation single-threaded or based on threading/multi-processing? This could be a relevant information for the caller to understand it's performance and parallelization capabilities.
  • Is the function pure and side-effect free?
  • Is the transformation fully async/lazy or does it have to consume all input before being able to produce some output?
2
  • Would the 3 points you listed in the bottom have to do with which method signature it's better to choose?
    – lennon310
    Dec 31, 2020 at 12:40
  • 1
    I would say that there is almost no reason to use the public void transform method. Keeping functions free from side-effects makes them more testable, parallelizable and understandable in general.
    – mrucci
    Dec 31, 2020 at 16:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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