Java – this puzzling generic pattern crashes eclipse – can I make it work?
(I am using eclipse Luna 4.4.0, JDK 1.8.0_05)
I'm making a game. The topology of the game world can be roughly divided into world – > level – > tiles. Tiles are a small piece of terrain I set up three projects, one containing some base classes of these structures, and the other two are server and client. They extend the structure in the basic project to meet other contents required by each project like this:
Base project:
public class BaseWorld{/* ...code... */} public class BaseLevel{/* ...code... */} public class BaseTile{/* ...code... */}
In server and client projects:
public class World extends BaseWorld{/* ...extended code... */} public class Level extends BaseLevel{/* ...extended code... */} public class Tile extends BaseTile{/* ...extended code... */}
Now in many parts of the base project, there are some methods that return the base class, but in server and client projects, this usually means that I have to override the method and convert it to subtype, because subprojects specifically use subtype types like this:
public class BaseLevel{ BaseLevel getNextLevel(){/* ...code... */} } public class Level extends BaseLevel{ Level getNextLevel(){ return (Level)super.getNextLevel(); } }
This is an unsustainable pain I found that I can use generics to solve some of these problems, with the following patterns:
public class BaseLevel<Level extends BaseLevel<Level>>{ Level getNextLevel(){/* ...code... */} } public class Level extends BaseLevel<Level>{ //All sorted! getNextLevel() already returns this subclass type. }
Well, I have this crazy idea to bend the above pattern to a breakpoint and be able to use all subclasses in all superclasses Now I must say that I don't agree with the following code as good programming. I just have an idea and take it out as much as possible to see how it works Anyway, I came up with the following monsters
public class BaseWorld<Tile extends BaseTile<Tile,Level,World>,Level extends BaseLevel<Tile,World extends BaseWorld<Tile,World>>{ /* ...code... */ } public class BaseLevel<Tile extends BaseTile<Tile,World>>{ /* ...code... */ } public class BaseTile<Tile extends BaseTile<Tile,World>>{ /* ...code... */ }
Now, whenever I need to return any class from any other class, I don't have to use any build in the subproject!
Unfortunately, because when eclipse rebuilds the workspace:
A stack overflow error has occurred. You are recommended to exit the workbench. [...]
I think when the generics of one class are being resolved, it must resolve the generics of another class and fall into a recursive loop
Question time:
Does the error eclipse editor have a stroke or Java compiler?
Compiler warnings / errors are not highlighted in the editor above – should it be, even if it looks technically valid?
Could this recursion be infinite or just very deep?
Is it possible to avoid this mistake while trying here? (I stress again that it is definitely not a good model, I just want to know if it is feasible)
Solution
Is the eclipse editor a stroke or a java compiler?
The eclipse editor in this case The following declaration (in different files, of course) is valid java code
public class BaseFoo<F extends BaseFoo<F,B>,B extends BaseBar<F,B>> {} public class BaseBar<F extends BaseFoo<F,B>> {} public class Foo<F extends BaseFoo<F,B>> extends BaseFoo<F,B> {} public class Bar<F extends BaseFoo<F,B>> extends BaseBar<F,B> {}
Compiler warnings / errors are not highlighted in the editor above – should it be, even if it looks technically valid?
It probably should (okay, okay, I'm kidding here...) No This is a valid Java Just... Uh
Could this recursion be infinite or just very deep?
Infinite, I guess here (more about my guess)
Consider trying to instantiate an instance of foo
Continue and write out the initializer using the default constructor
Foo<Foo,Bar> foo = new Foo<Foo,Bar>();
There are four errors about the common boundary mismatch
We tried to solve it
Foo<Foo<Foo,Bar>,Bar<Foo,Bar>> foo = new Foo<Foo<Foo,Bar>>();
There are now 12 errors We can continue trying to initialize it
Is it possible to avoid this mistake while trying here? (I stress again that it is definitely not a good model, I just want to know if it is feasible)
Consider the following basic structure:
class World { SomeCollection<Level> levels; } class Level { SomeCollection<Tile> tiles; } class Tile { }
Why?
The basic structure of the above code takes precedence over composition over inheritance. Generics are not used except for some built-in generic collection types A good example of the initialization style provided is the static builder. Finally, write something like this to initialize a world:
World gameWorld = new World.Builder(). .loadLevels(levelSource) .loadTiles(tileset) .build();
I hope it helps
End note
Don't go on This is a possible way to explore the problem Don't go here again