I have a fairly complicated set of generic classes in Java. For example, I have an interface
interface Doable<X,Y> {
X doIt(Y y);
}
and the implementation
class DoableImpl implements Doable<Foo<Bar<Baz,Qux>>,Foo<Bar<Zot,Qux>>> {
Foo<Bar<Baz,Qux>> doIt(Foo<Bar<Zot,Qux>> fooBZQ) { ... }
}
In the real implementation, Doable has quite a few methods and so Foo<Bar<Baz,Qux>>, etc., appear over and over again.
(Believe it or not, the generic types are quite a bit more painful than this. I've simplified them for the example.)
I'd like to simplify these, to save myself typing and to ease the strain on my eyes. What I'd like is to have a simple "type alias" for Foo<Bar<Baz,Qux>>, etc., say FooBBQ and FooBZQ.
My current idea is to define wrapper classes:
class FooBBQ {
public static FooBBQ valueOf(Foo<Bar<Baz,Qux>> fooBBQ) {
return new FooBBQ(fooBBQ);
}
private Foo<Bar<Baz,Qux>> fooBBQ;
private FooBBQ(Foo<Bar<Baz,Qux>> fooBBQ) {
this.fooBBQ = fooBBQ;
}
public Foo<Bar<Baz,Qux>> toGeneric() {
return fooBBQ;
}
}
class FooBZQ { /* pretty much the same... */ }
class DoableImpl implements Doable<FooBBQ,FooBZQ> {
FooBBQ doIt(FooBZQ fooBZQ) { ... }
}
This works well, but it has a few drawbacks:
We need to define separate wrappers for each generic instance. The wrapper classes are short and stylized, but I can't figure out a way to macro-ize them.
We have the translation overhead (conceptually, if not operationally) of calling valueOf and toGeneric to convert between FooBBQ and Foo<Bar<Baz,Qux>>. For example, if doIt calls into some library routine that expects a Foo<Bar<Zot,Qux>> (which the real implementation does), we end up with something like
return FooBBQ.valueOf( libraryCall( fooBZQ.toGeneric() ) )
where we would originally have had
return libraryCall(fooBZQ);
Is there some other way to get the "type alias" behavior I want here? Perhaps using some third-party macro toolset? Or do I need to accept that I'm going to have to do a lot of typing, one way (using the generic types in the implementation) or the other (writing wrappers for them)? Maybe having this many generic parameters flying around is just a bad idea and I need to re-think the problem?
[UPDATE] OK, I'm banning any further "don't do that" answers. Take it as a given that Foo<Bar<Baz,Qux>> has genuine value in my problem domain (Pete Kirkham may be right that it has enough value to get a proper wrapper class with a descriptive name). But this is a programming problem; don't try to define the problem away.
If you want full type safety, I don't think you can do better without some kind of wrapper classes. But, why not make those classes inherit/implement the original generic versions, like this:
public class FooBBQ extends Foo<Bar<Baz,Qux>> {
...
}
This eliminates the need for toGeneric() method, and it is more clear, in my opinion, that it is just a type alias. Also, generic type can be cast into FooBBQ without a compiler warning. It would be my personal preference to make Foo, Bar, Baz... interfaces, if possible, even if some code duplication would occur in implementation.
Now, without knowing concrete problem domain, it is hard to say whether you need, say FooBBQ, like in your example, or perhaps a:
public class FooBar<X, Y> extends Foo<Bar<X, Y>> {
...
}
On the other hand, have you thought about simply configuring Java compiler not to show some of the generic warnings, and simply omit the parts of generic definition? Or, use strategically placed #SuppressWarnings("unchecked")? In other words, can you make DoableImpl only "partly genericized":
class DoableImpl implements Doable<Foo<Bar>>,Foo<Bar>> {
Foo<Bar> doIt(Foo<Bar> foobar) { ... }
}
and ignore the warnings for the sake of less code clutter? Again, hard to decide without a concrete example, but it is yet another thing you can try.
Scala has nice support for type aliases. For example:
type FooBBQ = Foo[Bar[Baz,Qux]]
I realize that this answer won't be helpful if you don't have the option of switching to Scala. But if you do have the option of switching you might have an easier time.
Maybe having this many generic parameters flying around is just a bad idea and I need to re-think the problem?
Very probably. Do need to specialise 'Doit' in 8 dimensions?
In a lot of cases, these types don't exist in a vacuum and you should be thinking what domain objects your 'wrapper' represents rather than using them as a coding convenience.
Well, Java has no type aliases so you're out of luck. However, type aliases sometimes can be replaced with type variables! So we solve the problem of too many generics with even more generics!
As you've stripped all content from your example I can't guess where or whether it makes sense to introduce additional type variables, but here is one possible decomposition:
class DoableImplFoo<A,B> implements Doable<Foo<A>,Foo<B>> {
public DoableImplFoo(SomePropertyOf<A,B> aAndBAreGoodEnough) { ... }
Foo<A> doIt(Foo<B> fooB) { ... }
}
When you instantiate A to Bar<Baz,Qux> and B to Bar<Zot,Qux> later you may find that there is some boilerplate again, but it could be less than what you originally had.
I would say that, yes, you need to rethink the problem. The declaration
class DoableImpl implements Doable<Foo<Bar<Baz,Qux>>,Foo<Bar<Zot,Qux>>> {
Foo<Bar<Baz,Qux>> doIt(Foo<Bar<Zot,Qux>> fooBZQ) { ... }
}
is a pretty clear case of overusing generics.
Related
I am working with a pet project trying to practice (pure?) OO and can not figure out how to factorize a common behavior from a couple of classes.
public Solution improve(Solution initialSolution)
{
stopCondition.setInitialSolution(initialSolution);
Solution nextSolution = initialSolution;
do
{
nextSolution = nextSolutionGenerator.generate(nextSolution);
}
while(!stopCondition.isStopConditionReached());
return nextSolution;
}
As you can see, generate is common to both BinaryNextSolutionGenerator and PermutationNextSolutionGenerator. I know that Solution generate(Solution solution) should be in NextSolutionGenerator, however I do not want to lose the type verification at compile time if I send a PermutationSolution instance into a BinaryNextSolutionGenerator instance.
Looks like I have to use generic programming or my design is fundamentally wrong (or is a common tradeoff?), but I would prefer some experienced opinion before.
BTW, generate only calls doGenerate because I am planning to add some common logging code in there.
Make/refactor Solution and Generator to interfaces.
a "good place" for generics would be to refactor Integer getVariable(int idx) to <V extends java.lang.Number> getVariable(int idx)
another "good generic place" is the (exact) type of Soultion "generator.generate"...
Introduce abstract implementations of that interfaces! And put there as much common code as you can (public Solution<V> generate() {...}), enforce needed methods (<S extends Solution<V>> proteced abstract S doGenerate(S prev);) AbstractGenerator is also the place, where you would put the imporve (and public generate) methods.
Extend these abstract classes and implement the enforced methods (with concrete implementations of the solutions)
same with solution builder: work with abstraction, extension
...
https://github.com/xerx593/soq54317950 explains my points better... also outlined improve() and StopCondition<V extends Number, S extends Solution>.
If I am creating a java class to be generic, such as:
public class Foo<T>
How can one determine internally to that class, what 'T' ended up being?
public ???? Bar()
{
//if its type 1
// do this
//if its type 2
// do this
//if its type 3
// do this
//if its type 4
// do this
}
I've poked around the Java API and played with the Reflection stuff, instanceof, getClass, .class, etc, but I can't seem to make heads or tails of them. I feel like I'm close and just need to combine a number of calls, but keep coming up short.
To be more specific, I am attempting to determine whether the class was instantiated with one of 3 possible types.
I've used a similar solution to what he explains here for a few projects and found it pretty useful.
http://blog.xebia.com/2009/02/07/acessing-generic-types-at-runtime-in-java/
The jist of it is using the following:
public Class returnedClass() {
ParameterizedType parameterizedType = (ParameterizedType)getClass()
.getGenericSuperclass();
return (Class) parameterizedType.getActualTypeArguments()[0];
}
In contrast to .NET Java generics are implemented by a technique called "type erasure".
What this means is that the compiler will use the type information when generating the class files, but not transfer this information to the byte code. If you look at the compiled classes with javap or similar tools, you will find that a List<String> is a simple List (of Object) in the class file, just as it was in pre-Java-5 code.
Code accessing the generic List will be "rewritten" by the compiler to include the casts you would have to write yourself in earlier versions. In effect the following two code fragments are identical from a byte code perspective once the compiler is done with them:
Java 5:
List<String> stringList = new ArrayList<String>();
stringList.add("Hello World");
String hw = stringList.get(0);
Java 1.4 and before:
List stringList = new ArrayList();
stringList.add("Hello World");
String hw = (String)stringList.get(0);
When reading values from a generic class in Java 5 the necessary cast to the declared type parameter is automatically inserted. When inserting, the compiler will check the value you try to put in and abort with an error if it is not a String.
The whole thing was done to keep old libraries and new generified code interoperable without any need to recompile the existing libs. This is a major advantage over the .NET way where generic classes and non-generic ones live side-by-side but cannot be interchanged freely.
Both approaches have their pros and cons, but that's the way it is in Java.
To get back to your original question: You will not be able to get at the type information at runtime, because it simply is not there anymore, once the compiler has done its job. This is surely limiting in some ways and there are some cranky ways around it which are usually based on storing a class-instance somewhere, but this is not a standard feature.
Because of type erasure, there is no way to do this directly. What you could do, though, is pass a Class<T> into the constructor and hold onto it inside your class. Then you can check it against the three possible Class types that you allow.
However, if there are only three possible types, you might want to consider refactoring into an enum instead.
The Problem is that most of the Generic stuff will disappear during compilation.
One common solution is to save the type during the creation of the Object.
For a short introduction in the Type Erasure behaviour of java read this page
If you know a few specific types that are meaningful, you should create subclasses of your generic type with the implementation.
So
public class Foo<T>
public ???? Bar()
{
//else condition goes here
}
And then
public class DateFoo extends Foo<Date>
public ???? Bar()
{
//Whatever you would have put in if(T == Date) would go here.
}
The whole point of a generic class is that you dont need to know the type that is being used....
It looks like what you want is in fact not a Generic class, but an interface with a number of different implementations. But maybe it would become clearer if you stated your actual, concrete goal.
I agree with Visage. Generics is for compile-time validation, not runtime dynamic typing. Sounds like what you need is really just the factory pattern. But if your "do this" isn't instantiation, then a simple Enum will probably work just as well. Like what Michael said, if you have a slightly more concrete example, you'll get better answers.
I have a situation where I have have a lot of model classes (~1000) which implement any number of 5 interfaces. So I have classes which implement one and others which implement four or five.
This means I can have any permutation of those five interfaces. In the classical model, I would have to implement 32-5 = 27 "meta interfaces" which "join" the interfaces in a bundle. Often, this is not a problem because IB usually extends IA, etc. but in my case, the five interfaces are orthogonal/independent.
In my framework code, I have methods which need instances that have any number of these interfaces implemented. So lets assume that we have the class X and the interfaces IA, IB, IC, ID and IE. X implements IA, ID and IE.
The situation gets worse because some of these interfaces have formal type parameters.
I now have two options:
I could define an interface IADE (or rather IPersistable_MasterSlaveCapable_XmlIdentifierProvider; underscores just for your reading pleasure)
I could define a generic type as <T extends IPersistable & IMasterSlaveCapable & IXmlIdentifierProvider> which would give me a handy way to mix & match interfaces as I need them.
I could use code like this: IA a = ...; ID d = (ID)a; IE e = (IE)e and then use the local variable with the correct type to call methods even though all three work on the same instance. Or use a cast in every second method call.
The first solution means that I get a lot of empty interfaces with very unreadable names.
The second uses a kind of "ad-hoc" typing. And Oracle's javac sometimes stumbles over them while Eclipse gets it right.
The last solution uses casts. Nuff said.
Questions:
Is there a better solution for mixing any number of interfaces?
Are there any reasons to avoid the temporary types which solution #2 offers me (except for shortcomings in Oracle's javac)?
Note: I'm aware that writing code which doesn't compile with Oracle's javac is a risk. We know that we can handle this risk.
[Edit] There seems to be some confusion what I try to attempt here. My model instances can have one of these traits:
They can be "master slave capable" (think cloning)
They can have an XML identifier
They might support tree operations (parent/child)
They might support revisions
etc. (yes, the model is even more complex than that)
Now I have support code which operates on trees. An extensions of trees are trees with revisions. But I also have revisions without trees.
When I'm in the code to add a child in the revision tree manager, I know that each instance must implement ITtree and IRevisionable but there is no common interface for both because these are completely independent concerns.
But in the implementation, I need to call methods on the nodes of the tree:
public void addChild( T parent, T child ) {
T newRev = parent.createNewRevision();
newRev.addChild( foo );
... possibly more method calls to other interfaces ...
}
If createNewRevision is in the interface IRevisionable and addChild is in the interface ITree, what are my options to define T?
Note: Assume that I have several other interfaces which work in a similar way: There are many places where they are independent but some code needs to see a mix of them. IRevisionableTree is not a solution but another problem.
I could cast the type for each call but that seems clumsy. Creating all permutations of interfaces would be boring and there seems no reasonable pattern to compress the huge interface names. Generics offer a nice way out:
public
<T extends IRevisionable & ITree>
void addChild( T parent, T child ) { ... }
This doesn't always work with Oracle's javac but it seems compact and useful. Any other options/comments?
Loosely coupled capabilities might be interesting. An example here.
It is an entirely different approach; decoupling things instead of typing.
Basically interfaces are hidden, implemented as delegating field.
IA ia = x.lookupCapability(IA.class);
if (ia != null) {
ia.a();
}
It fits here, as with many interfaces the wish to decouple rises, and you can more easily combine cases of interdepending interfaces (if (ia != null && ib != null) ...).
If you have a method (semicode)
void doSomething(IA & ID & IE thing);
then my main concern is: Couldn't doSomething be better tailored? Might it be better to split up the functionality? Or are the interfaces itself badly tailored?
I have stumbled over similar things several times and each time it proved to be better to take big step backward and rethink the complete partitioning of the logic - not only due to the stuff you mentioned but also due to other concerns.
Since you formulated your question very abstractly (i.e. without a sensible example) I cannot tell you if that's advisable in your case also.
I would avoid all "artificial" interfaces/types that attempt to represent combinations. It's just bad design... what happens if you add 5 more interfaces? The number of combinations explodes.
It seems you want to know if some instance implements some interface(s). Reasonable options are:
use instanceof - there is no shame
use reflection to discover the interfaces via object.getClass().getInterfaces() - you may be able to write some general code to process stuff
use reflection to discover the methods via object.getClass().getMethods() and just invoke those that match a known list of methods of your interfaces (this approach means you don't have to care what it implements - sounds simple and therefore sounds like a good idea)
You've given us no context as to exactly why you want to know, so it's hard to say what the "best" approach is.
Edited
OK. Since your extra info was added it's starting to make sense. The best approach here is to use the a callback: Instead of passing in a parent object, pass in an interface that accepts a "child".
It's a simplistic version of the visitor pattern. Your calling code knows what it is calling with and how it can handle a child, but the code that navigates around and/or decides to add a child doesn't have context of the caller.
Your code would look something like this (caveat: May not compile; I just typed it in):
public interface Parent<T> {
void accept(T child);
}
// Central code - I assume the parent is passed in somewhere earlier
public void process(Parent<T> parent) {
// some logic that decides to add a child
addChild(parent, child);
}
public void addChild(Parent<T> parent, T child ) {
parent.accept(child);
}
// Calling code
final IRevisionable revisionable = ...;
someServer.process(new Parent<T> {
void accept(T child) {
T newRev = revisionable.createNewRevision();
newRev.addChild(child);
}
}
You may have to juggle things around, but I hope you understand what I'm trying to say.
Actually solution 1 is a good solution, but you should find a better naming.
What actually would you name a class that implements the IPersistable_MasterSlaveCapable_XmlIdentifierProvider interface? If you follow good naming convention, it should have a meaningful name originating from a model entity. You can give the interface the same name prefixed with I.
I don't find it a disadvantage to have many interfaces, because like that you can write mock implementations for testing purposes.
My situation is the opposite: I know that at certain point in code,
foo must implement IA, ID and IE (otherwise, it couldn't get that
far). Now I need to call methods in all three interfaces. What type
should foo get?
Are you able to bypass the problem entirely by passing (for example) three objects? So instead of:
doSomethingWithFoo(WhatGoesHere foo);
you do:
doSomethingWithFoo(IA foo, ID foo, IE foo);
Or, you could create a proxy that implements all interfaces, but allows you to disable certain interfaces (i.e. calling the 'wrong' interface causes an UnsupportedOperationException).
One final wild idea - it might be possible to create Dynamic Proxies for the appropriate interfaces, that delegate to your actual object.
If I am creating a java class to be generic, such as:
public class Foo<T>
How can one determine internally to that class, what 'T' ended up being?
public ???? Bar()
{
//if its type 1
// do this
//if its type 2
// do this
//if its type 3
// do this
//if its type 4
// do this
}
I've poked around the Java API and played with the Reflection stuff, instanceof, getClass, .class, etc, but I can't seem to make heads or tails of them. I feel like I'm close and just need to combine a number of calls, but keep coming up short.
To be more specific, I am attempting to determine whether the class was instantiated with one of 3 possible types.
I've used a similar solution to what he explains here for a few projects and found it pretty useful.
http://blog.xebia.com/2009/02/07/acessing-generic-types-at-runtime-in-java/
The jist of it is using the following:
public Class returnedClass() {
ParameterizedType parameterizedType = (ParameterizedType)getClass()
.getGenericSuperclass();
return (Class) parameterizedType.getActualTypeArguments()[0];
}
In contrast to .NET Java generics are implemented by a technique called "type erasure".
What this means is that the compiler will use the type information when generating the class files, but not transfer this information to the byte code. If you look at the compiled classes with javap or similar tools, you will find that a List<String> is a simple List (of Object) in the class file, just as it was in pre-Java-5 code.
Code accessing the generic List will be "rewritten" by the compiler to include the casts you would have to write yourself in earlier versions. In effect the following two code fragments are identical from a byte code perspective once the compiler is done with them:
Java 5:
List<String> stringList = new ArrayList<String>();
stringList.add("Hello World");
String hw = stringList.get(0);
Java 1.4 and before:
List stringList = new ArrayList();
stringList.add("Hello World");
String hw = (String)stringList.get(0);
When reading values from a generic class in Java 5 the necessary cast to the declared type parameter is automatically inserted. When inserting, the compiler will check the value you try to put in and abort with an error if it is not a String.
The whole thing was done to keep old libraries and new generified code interoperable without any need to recompile the existing libs. This is a major advantage over the .NET way where generic classes and non-generic ones live side-by-side but cannot be interchanged freely.
Both approaches have their pros and cons, but that's the way it is in Java.
To get back to your original question: You will not be able to get at the type information at runtime, because it simply is not there anymore, once the compiler has done its job. This is surely limiting in some ways and there are some cranky ways around it which are usually based on storing a class-instance somewhere, but this is not a standard feature.
Because of type erasure, there is no way to do this directly. What you could do, though, is pass a Class<T> into the constructor and hold onto it inside your class. Then you can check it against the three possible Class types that you allow.
However, if there are only three possible types, you might want to consider refactoring into an enum instead.
The Problem is that most of the Generic stuff will disappear during compilation.
One common solution is to save the type during the creation of the Object.
For a short introduction in the Type Erasure behaviour of java read this page
If you know a few specific types that are meaningful, you should create subclasses of your generic type with the implementation.
So
public class Foo<T>
public ???? Bar()
{
//else condition goes here
}
And then
public class DateFoo extends Foo<Date>
public ???? Bar()
{
//Whatever you would have put in if(T == Date) would go here.
}
The whole point of a generic class is that you dont need to know the type that is being used....
It looks like what you want is in fact not a Generic class, but an interface with a number of different implementations. But maybe it would become clearer if you stated your actual, concrete goal.
I agree with Visage. Generics is for compile-time validation, not runtime dynamic typing. Sounds like what you need is really just the factory pattern. But if your "do this" isn't instantiation, then a simple Enum will probably work just as well. Like what Michael said, if you have a slightly more concrete example, you'll get better answers.
Before the introduction to generics to the Java language I would have written classes encapsulating collections-of-collections-of-collections. For example:
class Account {
private Map tradesByRegion; //KEY=Region, VALUE=TradeCollection
}
class TradeCollection {
private Map tradesByInstrument; //KEY=Instrument, Value=Trade
}
Of course, with generics, I can just do:
class Account {
private Map<Region, Map<Instrument, Trade>> trades;
}
I tend to now opt for option #2 (over a generified version of option #1) because this means I don't end up with a proliferation of classes that exist solely for the purpose of wrapping a collection. But I have a nagging feeling that this is bad design (e.g. how many nested collections should I use before declaring new classes). Opinions?
2 is better because:
Less code accomplishes the same
effect (better, actually, as in #1
some of your type information exists
only in comments)
It's completely clear what's going
on.
Your type errors will be caught at compile time.
What is there to recommend 1? admittedly the Map< Integer , < Map < String, < Map< ... generics are a bit hard to get used to, but to my eye it's much easier to understand than code with maps, and lists of maps, and maps of lists of maps, and custom objects full of lists of maps.
Combination of the two. While you can use generics to replace custom classes, you still will want to use a class to encapsulate your concepts. If you're just passing maps of maps of maps of lists to everything, who controls what you can add? who controls what you can remove?
For holding the data, generics is a great thing. But you still want methods to validate when you add a trade, or add an account, and without some kind of class wrapping your collections, nobody controls that.
Normally there will also be some code to operate on the collections. When this becomes nontrivial I package up the collection with the behavior in a new class. The deeper the nesting is the more likely this will be the case.
I have made this simple rule for me: Never more than two <'s and two commas in a generics declaration and preferably only one comma. After that I introduce custom types. I think this is the point where the readability suffers enough to warrant additional concepts.
There is a real good reason to avoid too deep generics: The complexity is not only in the actual declaration but usually tends to be equally visible in the construction logic. So a lot of code has a tendency to become convoluted if you nest these declarations too deeply. Creating intermediate classes can help a lot. The trick is often to find the proper intermediate classes.
I definitely think you should go a slight bit back towards your old standard. Actually your second sample is the exact pain-point where I'd still accept generics-only.
I think it's better to keep objects in mind and emphasize the collections a bit less. Reification is your friend.
For example, it's natural to have Student and Course objects if you're modeling a system for a school. Where should grades be captured? I'd argue that they belong in an object where Student and Course meet - a ReportCard. I wouldn't have a GradeCollection. Give it some real behavior.
I prefer #2. It is clearer what is going on, and is typesafe at compile time (I prefer having as many things go wrong at compile time as possible, as opposed to having them happen at runtime... in general I like it when nothing goes wrong).
Edit:
Well there are two ways that I can see... I guess it depends on which you would use:
class Account
{
private Map<Region, TradeCollection> tradesByRegion;
}
class TradeCollection
{
private Map<Instrument, Trade> tradesByInstrument;
}
or
class Account<R extends Region, I extends Instrument, T extends Trade, C extends TradeCollection<I, T>>
{
private Map<R, C> tradesByRegion;
}
class TradeCollection<I extends Instrument, T extends Trade>
{
private Map<I, T> tradesByInstrument;
}
I think the answer to this is that it depends on the situation. Generally, introducing a type is useful if that also introduces methods related to the type, if those intermediate types are passed around independently, etc.
You might find this bit of advice from Rich Hickey (the creator of Clojure) about creating interoperable libraries kind of interesting:
http://groups.google.com/group/clojure/browse_thread/thread/e0823e1caaff3eed
It's intended as specific advice to Clojure library writers but I think is interesting food for thought even in Java.