Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

I'm developing some code that utilizes generics, and one of my guiding principles was to make it usable for future scenarios, and not just today's. However, several coworkers have expressed that I may have traded off readability for the sake of extensibility. I wanted to gather some feedback about possible ways to resolve this.

To be specific, here is an interface that defines a transform - you start with a source collection of items, and you apply the transform to each element, storing the results in a destination collection. Additionally, I want to be able to return the destination collection to the caller, and rather than forcing them to use a Collection reference, I want them to be able to use whatever collection type they actually provided for the destination collection.

Finally, I make it possible for the type of items in the destination collection to be different from the type of items in the source collection, because maybe that's what the transform does. In my code, for instance, several source items make up one destination item after the transform.

This yields the following interface:

interface Transform<Src, Dst> {
    <DstColl extends Collection<? super Dst>> DstColl transform(
                Collection<? extends Src> sourceCollection,
                DstColl                   destinationCollection);
}

I tried to be all nice and apply Josh Bloch's PECS principle (producer extends, consumer super) to make sure the interface is usable with super- and sub-types where appropriate. The end result is somewhat of a monstrosity.

Now, it would have been nice if I could extend this interface and specialize it somehow. For example, if I don't really care about playing nice with subtypes of the source items and supertypes of the destination items, I could have:

interface SimpleTransform<Src, Dst> {
    <DstColl extends Collection<Dst>> DstColl transform(
                  Collection<Src> sourceCollection,
                  DstColl         destinationCollection);
}

But there is no way to do that in Java. I want to make implementations of this interface something that others would actually consider doing, as opposed to running in fear. I've considered several options:

  • Don't return the destination collection. Seems weird given that you do a transform but get nothing back.
  • Have an abstract class that implements this interface, but then translates the parameters to something easier to use and calls another method "translateImpl()" which has the simpler signature and thus presents less of a cognitive burden for implementers. But then it's weird to have to write an abstract class just to make an interface user-friendly.
  • Forgo extensibility and just have the simpler interface. Possibly couple that with not returning the destination collection. But then that limits my options in the future.

What do you think? Am I missing an approach I could use?

share|improve this question
1  
Trying to predict a future scenario instead of knowing the use case is not a good idea. This is where the KISS principle is in play. –  lorus Feb 13 '13 at 4:15
    
Additionally to the KISS principle, there's also the YAGNI principle suggesting you shouldn't do that. –  Frank Feb 13 '13 at 6:11
    
@lorus - my idea was to have a "transform" interface that I could use for a variety of transforms, as opposed to one specific case that is tailored to a specific combination of source and target item types. A way of summing up my post is "how do I keep it simple in a manner that wouldn't require significant rework in the future". We're in a typical corporate setting where deadlines are king and I can't just go refactor things unless there is a sound business reason. Same concern applies to YAGNI in Frank's comment. –  RuslanD Feb 13 '13 at 7:56
    
Instead of Collection<? extends Src> srcCollection, you should use Iterable<? extends Src> –  kevin cline Feb 14 '13 at 13:29

2 Answers 2

Guava Collections already provides this functionality and if you can hold off a little longer, Java 8 will provide this also :-). FWIW I think your use of ? extends T is the correct idiom, not much you can do given that Java uses Type Erasure

share|improve this answer
    
Unfortunately it's unlikely I'll be able to convince my team and management to jump straight from Java 6 to Java 8 :) In the meantime, could you please clarify what you mean by "Guava Collections already provides this functionality"? Are you talking about transforming collections? A pointer to a relevant resource would be very useful. Thanks! –  RuslanD Feb 13 '13 at 0:35
    
I am confused as to why erasure is significant here. Are you thinking of what C# x.0 call in and out generic parameters? / Using Collection<? super Dst> would be ideal here, if it wasn't also returning the same type (presumably the same reference, which isn't really a great idea (I think Java SE 8 will do that for some methods (into))). It's interesting to note that the likes of Collections.fill use wildcard unnecessarily to be more expressive. / IIRC, Java SE 6 finally becomes unsupported this month. –  Tom Hawtin - tackline Feb 13 '13 at 2:29
1  
Guava is code.google.com/p/guava-libraries –  MatrixFrog Feb 13 '13 at 6:52
2  
+1 for Guava - it's excellent and should be part of every Java developer's toolkit (also Joda Time and Joda Money) –  Gary Rowe Feb 13 '13 at 9:21

I personally do not see much problem with the way you've defined your interface, however I am used to toying with Generics and I can understand that your coworkers would find your code to be a bit of a mouthful if that is not their case.

If I were you, I would go with the third solution you state: make things simpler at the expense of potentially having to go back to it later. Because after all, maybe you won't have to in the end; or you would end up being able to use it fully at some point, but not enough to make up for the effort you've put into making this interface so generic, as well as the effort your coworkers may have made to wrap their heads around it.

Another thing to consider is how often you use this interface, and at which level of complexity. Also, how useful this interface proves to be in your project(s). If it allows for high reusability of some components (and not just potential, but actual), it is a good thing. If a much simpler interface works as well 90% of the time, you could ask yourself whether for the remaining 10% a complex interface would prove useful or not.

I do not think it would be a very good idea to not use super and extend, though if you can do without them for the moment, I am sure your colleagues won't mind seeing them disappear. However, do you really have so many situations where you need to change the type of Collection as well?

Some already given advices are really good, and I agree with Frank about following the YAGNI principle unless you have very good reasons not to. You can still change the code when the need for more complexity will arise, but it is not of much use to develop things you are not pretty sure will be used soon. Also, Martijn's advice of using Guava is one to consider seriously. I haven't had the opportunity to use it yet, but I have heard a lot of good about it, including in a presentation where the Transformer pattern got discussed (you can watch it online on InfoQ if you are interested).

As an aside, wouldn't it be better in your current interface to have destinationCollectionbe of type Class<DstColl>?

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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