views:

646

answers:

11

Hello SO people,

when programming in Java I practically always, just out of habit, write something like this:

public List<String> foo() {
    return new ArrayList<String>();
}

Most of the time without even thinking about it. Now, the question is: should I always specify the interface as the return type? Or is it advisable to use the actual implementation of the interface, and if so, under what circumstances?

It is obvious that using the interface has a lot of advantages (that's why it's there). In most cases it doesn't really matter what concrete implementation is used by a library function. But maybe there are cases where it does matter. For instance, if I know that I will primarily access the data in the list randomly, a LinkedList would be bad. But if my library function only returns the interface, I simply don't know. To be on the safe side I might even need to copy the list explicitly over to an ArrayList:

List bar = foo();
List myList = bar instanceof LinkedList ? new ArrayList(bar) : bar;

but that just seems horrible and my coworkers would probably lynch me in the cafeteria. And rightfully so.

What do you guys think? What are your guidelines, when do you tend towards the abstract solution, and when do you reveal details of your implementation for potential performance gains?

+3  A: 

Without being able to justify it with reams of CS quotes (I'm self taught), I've always gone by the mantra of "Accept the least derived, return the most derived," when designing classes and it has stood me well over the years.

I guess that means in terms of interface versus concrete return is that if you are trying to reduce dependencies and/or decouple, returning the interface is generally more useful. However, if the concrete class implements more than that interface, it is usually more useful to the callers of your method to get the concrete class back (i.e. the "most derived") rather than aribtrarily restrict them to a subset of that returned object's functionality - unless you actually need to restrict them. Then again, you could also just increase the coverage of the interface. Needless restrictions like this I compare to thoughtless sealing of classes; you never know. Just to talk a bit about the former part of that mantra (for other readers), accepting the least derived also gives maximum flexibility for callers of your method.

-Oisin

x0n
Do you mean that you should always return the concrete implementation? I disagree with this as you are creating unnecessary coupling between consumers of your code and your method. Returning the interface forces the consumer to deal with the returned object in terms of the abstract contract, not the concrete implmentation -- which may have additional methods.
tvanfosson
No, I don't believe you should always return the concrete; I added this clarification probably while you were writing this comment ;)
x0n
Based on your edit, I'd say that we definitely disagree. Allowing callers access to additional methods beyond the interface (for other than internal use), locks you into a specific implementation and should be avoided (except for internal use).
tvanfosson
I think there's middle ground here - it depends on the method, visibility, use cases and the audience for the API. I agree with you in priniciple, but I disagree with absolute statements. I dunno, knee jerk.
x0n
+1  A: 

You use interface to abstract away from the actual implementation. The interface is basically just a blueprint for what your implementation can do.

Interfaces are good design because they allow you to change implementation details without having to fear that any of its consumers are directly affected, as long as you implementation still does what your interface says it does.

To work with interfaces you would instantiate them like this:

IParser parser = new Parser();

Now IParser would be your interface, and Parser would be your implementation. Now when you work with the parser object from above, you will work against the interface (IParser), which in turn will work against your implementation (Parser).

That means that you can change the inner workings of Parser as much as you want, it will never affect code that works against your IParser parser interface.

Alex
Why on earth would this get a negative vote? Looks fine to me.
duffymo
I'm fully aware of what an interface is and what it does. The question was more along the lines of when should a programmer reveal the inner workings of its class to allow the clients of his library to use it more effectively.
n3rd
"That means that you can change the inner workings of Parser as much as you want, it will never affect code that works against your IParser parser interface." - that's exactly what this says.
duffymo
+1 from me, because it's not a bad answer.
duffymo
If the question was "What's an interface?", this would have been a good answer. Seeing how that wasn't the question - this answers seems completely irrelevant.
TheSoftwareJedi
OK, maybe I read too hastily.
duffymo
@duffymo "should I always specify the interface as the return type? Or is it advisable to use the actual implementation of the interface, and if so, under what circumstances?" - that's exactly the question. Please point out how Alex answered it.
TheSoftwareJedi
I answered this in my last sentence, using an example to work my way there. My point is to always use an interface because then your code stays unaffected by implementation changes. I could have just written the last sentence without example, but I thought it may be of higher value to other readers if they get an example with it.
Alex
Alex does make the point to use interfaces always, and he has some clarifying material that n3rd didn't ask for but that perhaps others might find useful in this discussion. Not the best answer, but it's not wrong, and not offtopic enough to justify a downvote, IMO.
Jim Ferrans
@SoftwareJedi, I think I did that when I quoted his last sentence. @Jim, I agree.
duffymo
This is a great answer. Alex grounds his argument in a concise explanation of interface design, then clearly sums up by stating the advantage of interfaces. Any failure to follow the line of reasoning seems willfully obtuse.
erickson
+16  A: 

Return the appropriate interface to hide implementation details. Your clients should only care about what your object offers, not how you implemented it. If you start with a private ArrayList, and decide later on that something else (e.g., LinkedLisk, skip list, etc.) is more appropriate you can change the implementation without affecting clients if you return the interface. The moment you return a concrete type the opportunity is lost.

duffymo
I would agree with that whole-heartedly. However, if someone works on a low-level API where performance is important, then revealing some implementation details may be a good thing, although you would clearly lose flexibility and abstraction. I was hoping someone who actually had to make this trade-off in a real-world application could share some oh his or her thoughts.
n3rd
As I mention below, as a library creator you can mention the relevant details in the documentation, leaving to the user the decision of whether taking the risk of creating code that might break with next versions or not. If you do that in code instead you get no benefit but a lot of cost.
Vinko Vrsalovic
Yes, I can see how that would probably be the best way to go. Thanks.
n3rd
+4  A: 

In general, for a public facing interface such as APIs, returning the interface (such as List) over the concrete implementation (such as ArrayList) would be better.

The use of a ArrayList or LinkedList is an implementation detail of the library that should be considered for the most common use case of that library. And of course, internally, having private methods handing off LinkedLists wouldn't necessarily be a bad thing, if it provides facilities that would make the processing easier.

There is no reason that a concrete class shouldn't be used in the implementation, unless there is a good reason to believe that some other List class would be used later on. But then again, changing the implementation details shouldn't be as painful as long as the public facing portion is well-designed.

The library itself should be a black box to its consumers, so they don't really have to worry about what's going on internally. That also means that the library should be designed so that it is designed to be used in the way it is intended.

coobird
+3  A: 

As a rule, I only pass back internal implementations if I am in some private, inner workings of a library, and even so only sparingly. For everything that is public and likely to be called from the outside of my module I use interfaces, and also the Factory pattern.

Using interfaces in such a way has proven to be a very reliable way to write reusable code.

Mario Ortegón
A: 

You'll find (or have found) that as you return interfaces, they permeate through your code. e.g. you return an interface from method A and you have to then pass an interface to method B.

What you're doing is programming by contract, albeit in a limited fashion.

This gives you enormous scope to change implementations under the covers (provided these new objects fulfill the existing contracts/expected behaviours).

Given all of this, you have benefits in terms of choosing your implementation, and how you can substitute behaviours (including testing - using mocking, for example). In case you hadn't guessed, I'm all in favour of this and try to reduce to (or introduce) interfaces wherever possible.

Brian Agnew
+2  A: 

In OO programming, we want to encapsulate as much as possible the data. Hide as much as possible the actual implementation, abstracting the types as high as possible.

In this context, I would answer only return what is meaningful. Does it makes sense at all for the return value to be the concrete class? Aka in your example, ask yourself: will anyone use a LinkedList-specific method on the return value of foo?

  • If no, just use the higher-level Interface. It's much more flexible, and allows you to change the backend
  • If yes, ask yourself: can't I refactor my code to return the higher-level interface? :)

The more abstract is your code, the less changes your are required to do when changing a backend. It's as simple as that.

If, on the other hand, you end up casting the return values to the concrete class, well that's a strong sign that you should probably return instead the concrete class. Your users/teammates should not have to know about more or less implicit contracts: if you need to use the concrete methods, just return the concrete class, for clarity.

In a nutshell: code abstract, but explicitly :)

NicDumZ
+3  A: 

For instance, if I know that I will primarily access the data in the list randomly, a LinkedList would be bad. But if my library function only returns the interface, I simply don't know. To be on the safe side I might even need to copy the list explicitly over to an ArrayList.

As everybody else has mentioned, you just mustn't care about how the library has implemented the functionality, to reduce coupling and increasing maintainability of the library.

If you, as a library client, can demonstrate that the implementation is performing badly for your use case, you can then contact the person in charge and discuss about the best path to follow (a new method for this case or just changing the implementation).

That said, your example reeks of premature optimization.

If the method is or can be critical, it might mention the implementation details in the documentation.

Vinko Vrsalovic
+1  A: 

The main question has been answered already and you should always use the interface. I however would just like to comment on

It is obvious that using the interface has a lot of advantages (that's why it's there). In most cases it doesn't really matter what concrete implementation is used by a library function. But maybe there are cases where it does matter. For instance, if I know that I will primarily access the data in the list randomly, a LinkedList would be bad. But if my library function only returns the interface, I simply don't know. To be on the safe side I might even need to copy the list explicitly over to an ArrayList.

If you are returning a data structure that you know has poor random access performance -- O(n) and typically a LOT of data -- there are other interfaces you should be specifying instead of List, like Iterable so that anyone using the library will be fully aware that only sequential access is available.

Picking the right type to return isn't just about interface versus concrete implementation, it is also about selecting the right interface.

Kris
+2  A: 

It doesn't matter all that much whether an API method returns an interface or a concrete class; despite what everyone here says, you almost never change the implementiation class once the code is written.

What's far more important: always use minimum-scope interfaces for your method parameters! That way, clients have maximal freedom and can use classes your code doesn't even know about.

When an API method returns ArrayList, I have absolutely no qualms with that, but when it demands an ArrayList (or, all to common, Vector) parameter, I consider hunting down the programmer and hurting him, because it means that I can't use Arrays.asList(), Collections.singletonList() or Collections.EMPTY_LIST.

Michael Borgwardt
+1  A: 

In general use the interface in all cases if you have no need of the functionality of the concrete class. Note that for lists, Java has added a RandomAccess marker class primarily to distinguish a common case where an algorithm may need to know if get(i) is constant time or not.

For uses of code, Michael above is right that being as generic as possible in the method parameters is often even more important. This is especially true when testing such a method.

Kathy Van Stone