• Post Reply Bookmark Topic Watch Topic
  • New Topic

Reflection to reduce boilerplate code  RSS feed

 
Bartholomew Benson
Greenhorn
Posts: 19
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I have the following classes:

(doesn't have to be abstract if not necessary, but currently there is no need for it not to be abstract)



Now, I want to get the elements like follows:



I know I could do something like this:



and override getters as necessary in the inherited classes:



But this introduces an awful lot of boilerplate code, especially in the BaseClass class. In my current plans, there could easily be over a hundred different Data classes, and I would have to write a method that simply returns null for each.

I read about the @Inject annotation and reflection. Is it possible to reduce or eliminate the boilerplate code with these tricks, possibly by putting new methods into the classes?
 
Knute Snortum
Sheriff
Posts: 4270
127
Chrome Eclipse IDE Java Postgres Database VI Editor
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Why don't you just put



in InheritedClassB and InheritedClassC?
 
Bartholomew Benson
Greenhorn
Posts: 19
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
That's actually similar to the setup I have right now, where there are no inherited classes, just a class with all the possible Data objects inside it and null to indicate whether they have or don't have a particular piece of data. The thing is, I have thousands of objects of type BaseClass at a time. With a hundredish Data objects, that leads to a lot of memory being used on null entries, especially since individual inherited classes usually only have a small number of data members. I'm trying to run my code on a platform with a relatively low amount of memory and possibly running other programs at the same time, so I'd like to try to see if it's possible to redesign my classes to take advantage of the fact that there are only a few types of data-holding classes, without requiring additional boilerplate code for each Data object I want to add. I'm expecting that the memory used on the methods will be less than the memory spent on the data members since there are only a handful of inherited classes and methods relative to the thousands of actual objects.
 
Henry Wong
author
Sheriff
Posts: 23295
125
C++ Chrome Eclipse IDE Firefox Browser Java jQuery Linux VI Editor Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Bartholomew Benson wrote:
I know I could do something like this:



But this introduces an awful lot of boilerplate code, especially in the BaseClass class.


How about having a Map<String, Object> as part of the base class. And instead of having hundreds of getters and setters, you have one of each. They take an additional parameter, which is the name of the now former variable, which will be the key in the map?

Bartholomew Benson wrote:
and override getters as necessary in the inherited classes:




With this change, you won't need to have any variables in the subclass. Heck, you won't need to override the getters either.

Henry
 
Henry Wong
author
Sheriff
Posts: 23295
125
C++ Chrome Eclipse IDE Firefox Browser Java jQuery Linux VI Editor Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Of course, with this change, you will have some typing issues -- meaning you are responsible for casting the type.



Henry
 
Henry Wong
author
Sheriff
Posts: 23295
125
C++ Chrome Eclipse IDE Firefox Browser Java jQuery Linux VI Editor Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Bartholomew Benson wrote:That's actually similar to the setup I have right now, where there are no inherited classes, just a class with all the possible Data objects inside it and null to indicate whether they have or don't have a particular piece of data. The thing is, I have thousands of objects of type BaseClass at a time. With a hundredish Data objects, that leads to a lot of memory being used on null entries, especially since individual inherited classes usually only have a small number of data members.


What a minute? You don't have any inherited classes now? And the only reason you are considering subclasses is to limit the scope of variables? That's a silly thing to do. Just have your one class use a Map instead, and your are done.

Bartholomew Benson wrote:I'm trying to run my code on a platform with a relatively low amount of memory and possibly running other programs at the same time, so I'd like to try to see if it's possible to redesign my classes to take advantage of the fact that there are only a few types of data-holding classes, without requiring additional boilerplate code for each Data object I want to add. I'm expecting that the memory used on the methods will be less than the memory spent on the data members since there are only a handful of inherited classes and methods relative to the thousands of actual objects.


Or you can just use a Map, and not have the need for additional classes or lots of unused variables.

Henry
 
Bartholomew Benson
Greenhorn
Posts: 19
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
A HashMap would work well for my purposes, although I don't know how much worse its get/set performance is on direct data member access. The inherited and base classes are expected to be put into the core of my code, and each object is accessed multiple times every frame at 60 FPS. My current implementation doesn't seem to have performance issues around accessing, so using a HashMap will probably work without too much trouble, I guess. In fact, the design I was talking about with null values and no inherited classes was actually only an initial design that was functionally similar to what I posted earlier; I went in a completely different direction since then and created another design using mostly arrays, which worked very well, was simple to access, had a low memory footprint, and had good performance. I could stick to what I currently have and probably do well enough for myself.

But I ask about using annotations/reflection in particular, though, because I don't know a whole lot about those areas of Java yet, and am wondering about what I can and cannot do with them, especially if I'm not too worried about how long my code takes to compile or initially set up. In some ways, it's a learning exercise for me. It might also be beneficial to go back to inheritance if I'm able to eliminate/automate the boilerplate code, which is why I also bring up the question: it would make the design more type-safe than what I already have and would allow me to check at a glance which data fields a particular inherited class has, which would be a little more convoluted in my current design. And, of course, it would be much cleaner in general to use inherited getters than the series of array accesses and casts that my current code performs.

When I made the thread, I was under the impression that using annotations and reflection, I could 'inject methods' into the superclass, which I took to mean that I could create new methods at runtime and call them from within my code. But after reading more into reflection and looking at the API, I'm not so sure if this is possible anymore. I also found information on annotation processors (http://deors.wordpress.com/2011/10/31/annotation-generators/), which also sound like what I'm looking for. But if what I read isn't mistaken, I can't modify the source code for existing classes, only create new classes. I'm wondering if the following is possible (or if there's a better way to achieve what I would like to happen):

Starting with the following classes,


could I generate the following class out of the @DataField annotations and have everything link together properly without any errors?
 
Paul Clapham
Sheriff
Posts: 22813
43
Eclipse IDE Firefox Browser MySQL Database
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Well, we're handicapped by having to look at meaningless class names, so it's difficult for us to know what you are trying to achieve. I get the impression that you have an actual use case for what you're asking about here, so why don't you tell us what it is? That would make it much easier to talk about.

Also, if you're concerned about code eating up your 1/60-second increments, you should bear in mind that code executes on the scale of nanoseconds. You have to execute a whole lot of code to use a microsecond, unless it starts accessing databases or disk files or other external hardware. If you calculate how many microseconds there are in 1/60 of a second, you'll see that you are committing the sin of premature optimization.

(Edited: I should have said "microseconds" not "milliseconds".)
 
Bartholomew Benson
Greenhorn
Posts: 19
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I am playing around with different designs for an Entity Component System for a game architecture (http://cowboyprogramming.com/2007/01/05/evolve-your-heirachy/).

My current design works much like it's described in the article: a database-like table, where the rows are equivalent to individual entity objects, and the columns for the individual fields inside the entity objects. However, after thinking about the problem some more, I decided to split up the single table into multiple tables as one would do so in an actual database; a lot of memory was being wasted on, for example, thousands of 'Particle' type entities that didn't need components for 'AI' or 'Inventory'.

This worked pretty well, but now I'm considering switching back to an OOP style of implementing the major features of my current table-based design as a possibility. Although, canonically, it seems that the strictest interpretation of an ECS system has only a single Entity class, with the available components determining exactly what kind of Entity it is rather than subclassing, there are other features of OOP styles (ie. type safety, ease of reading) which are particularly appealing to me. In essence, I'm trying to see if there's a possible design that implements both the positive features of OOP styles, and that of a database/blob style. But then I ran into the problem of having tons of boilerplate code. Another issue is that, ideally, I want to make the base class as independent as possible from the inherited classes so that the code in the base class isn't dependent on the code in the inherited classes. But I would like to access data members using polymorphism as well, because Systems still shouldn't need to know what type of Entity it's dealing with, but knowing the kind of Entity can still be handy when accessing Entities from outside Systems. I read a little bit about annotations and reflection before and was wondering if they could help alleviate my specific problem somehow; a lot of sources say that you can greatly reduce boilerplate code using annotations. I'm thinking that, even if it's a pointless exercise or just plain impossible, I'll at least have learned more about using them and what their limitations are with respect to generating code.

Does this make more sense?
 
Knute Snortum
Sheriff
Posts: 4270
127
Chrome Eclipse IDE Java Postgres Database VI Editor
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
If you don't want to do the Map implementation for some reason, can I suggest creating an interface with all getters needed for all data types, then create an abstract class with all the getters implemented to return null, then extend this abstract class and only implement the getters that actually return something. That way you don't code anymore than you have too, but you get all the "getters return null" that you need.
 
Campbell Ritchie
Marshal
Posts: 56518
172
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
The whole thing sounds like iffy design to me. You get out of one hole and blunder into another. The compiler will be only too happy to let you return null from a million getXXX methods but you are now risking injecting nulls left right and centre.
 
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!