Using code generation in your game.

Missed cache in assembly language. At first it was fine and a valid technique, but after introduction of L1/L2 cache it was becoming very bad (since you can’t cache self rewritten machine code, cache has to be invalidated and the code read again).

Sure, you might say it is not relevant in this case NOW. But hey, back then it was not considered bad at first as well, it is later they invented the cache and it was all messed up. The same story is PHP eval() function and the Zend Optimizer, which again was invented later (you can’t tokenize a code that is dynamic generated). It happened at least twice so far, so it is only fair if I post about history of this kind of techniques. That’s relevant enough to justify a post IMHO :slight_smile:

[quote]And please don’t say that you told us that it might not necessarily be relevant in this context, because the provided use case is trivial and could be taken into consideration before posting.
[/quote]
You are not very friendly you know :slight_smile: And being angry all the time is bad for skin :slight_smile:

I hate to repeat myself, but we’re discussing code generation at compile-time here. It would have performed just as well in ASM / PHP.

If you have many (IMO more than ~20) instances where you need to generate code… I can see it’s benefit. Otherwise, I see it as overkill.

Feel free to prove me wrong – I find code generation interesting and would like to learn some practical uses for it in gereral game development (assuming such a thing even exists).

This is not “self-rewriting code”, it’s simply static class generation, an extra compile step. These weird tangents about cache misses are comparing apples to drive shafts. It’s a perfectly sound methodology, and while I might consider it overkill for a few instances, I can’t see anything wrong with it. It’s certainly safer than stuffing every attribute into a Map at runtime, where one typo will throw everything out of whack.

We should all try to steer clear of code generation. On the other hand, we should also try to steer clear of mundane tasks, like writing repetitive and/or overly verbose struct-like code in Java. In the end it’s about finding the balance in usability and maintainability.

For example, when you generate code for primitive lists, sets and maps, not using code generation becomes undefendable. Java falls short in some areas and verbosity can certainly be one of them. We even have IDE plugins that take the burden of writing such code off of the developer - needless to say they all use code generation behind the scenes.

So I have time again to reply.
I think, when uyou use normal java classes you won’t need to write that much more code.
Instead of extending the Event class all the Time, why not just add generic event data.


class Event<E>
{
  private final E data;
  public E getData();
}

class AttackData
{
  public final AttackType type;
  public final int amount;
}

...
Event<AttackData> e = new Event<>(new AttackData(FIRE, 50));
...

I don’t see how writing this simple class is more work then adding your config to a textfile.
With the class you can use all the benefits of the IDE, like code completion which maks writing the class over 9000 times faster then the config file.
Also you can do refactoring and so on, which you can’t do with your config file. And I would thingk that stuff like alot of event datas can change a lot while devoloping.

The whole problem is that the above code doesn’t work. You need ‘a lot’ of boilerplate, which is the mundane/verbose part I was talking about and what the original poster was trying to get rid of.

Java is verbosity.

To avoid verbosity you usually go to other programming languages, for instance Python.

The errors you mentions, except said verbosity, is handled by avoiding double maintenance.

For instance if the programmer has a specific attribute he wish to aquire and he knows he otherwise would’ve generated with his code generator, the programmer usually creates a static final enum as to avoid double maintenance. Thereby IDE refactoring works, typo errors are impossible and you can’t assume the wrong type of property.

As long as the kind of events aren’t changed constantly during runtime there isn’t even any performance issues if you use for example an enummap.

Code generation is a classic code smell.

An example of this solution is unit/object retrieval for a game.

As the main difference between these are just parameter values you create a master class, and then you load at runtime the units/objects you wish to have from for example a textfile. Each master class with given parameters are put into an enummap and then can be aquired by a getter with an enum parameter.

I don’t see how your proposed solution makes it better. The added abstraction layer of getters and enums will lead to increased code verbosity throughout the project, which is (IMHO) an even bigger problem than typing out all those classes by hand.

Maybe I’m mistaken, and you could enlighten us with a code sample.

Sorry, there is no way that writing out a new class is 9000x faster than updating my config file. Let’s say you want to create a new Event called ShipArrived that has 4 parameters, the entity id of the ship that has arrived, and it’s x, y, and z parameters. I would type:

+ ShipArrived entity int x float y float z float

Save it, right click on the project in my IDE and click run and the message class would be available for me to use. Literally 10 seconds from the time I open the config file to the time i can start using it in my game. Are you saying that writing out a new class would be 9000x faster?

Also, on the usage side, I can now say
AttackEvent e = new AttackEvent(FIRE,50);

or

int damage = 10 * e.amount;

which is cleaner than what you have above.

Part of the motivation for doing it in the first place is that I often find myself, adding, removing, and editing message types and this config file is an easier place to do this.

Offtopic: regarding “over 9000”, that is an internet meme, see:

[tr][td]
http://seemslegit.com/_images/f32358a3bacde8ac9fba1da358aa5aff/948%20-%20animals%20cat%20kitten%20over-9000%20saiyan%20super.jpg
[/td][td]

[/td][/tr][tr][td]

[/td][td]
http://troll.me/images/jackie-chan-whut/its-over-9000-.jpg
[/td][/tr]

This is one of the worst arguments…
“If you don’t like a piece of X, abandon X and use Y instead”

The world isn’t that black and white. We can workaround problems instead of completely discarding X.

ctrl+n, enter, “ShipArrived”, enter – created new class
“pf”, tab, “f”, enter, “x,y,z;”, enter – expands to public final float x, y, z;
“pf”, tab, “i”, enter, “entity;”, enter
ctrl+space, down, enter – creates constructor

finished
41 vs 49 keystrokes
and this only gets alot worse when you use classes, cause you have to write out the hole class path.

Besid this silly counting :)^^
What I wanted to explain to you is that refactoring is a big thing. And you can’t do this with your approach. I also wanted to point out that you don’t save any time with your code generation.

changing stuff == refactoring
which is much easier when you do it in the IDE, i.e. you change the name of a parameter
also when you change a single attribut of an message type, you have to rebuild all your messages, which is a lot of time you would waste. Editing a java class in your IDE doesn’t take 10sec.

Furthermore lets look at a example


[In the Entity class, what I think you do]

public void processEvent(Event ev)
{
...
if(ev instanceOf AttackEvent)
{
AttackEvent tmp = (AttackEvent)ev;
  takeDamage(tmp.amount * getTypeMultiplier(tmp.type));
}
...
}

[with my code you just would "if else" over the data instead of over the event]

ps: don’t get me wrong, writing such tools by yourselfs is always a quite interesting thing to do, but in alot of cases it doesn’t really is that usefull in the end. I don’t want to bash your idea, but my problem with it is that you are just writing the classes in an own DSL which doesn’t save you anything in the end(time, and characters to type)

You bring up a good point. If I have an event type that is already in use in a number of places and I decide to change a parameter name (attackScore to damageDealt), make the change and run the code gen, then change it where it is used, or I could do the refactoring in the IDE, in which case the generated class and then change the config file to match. Altering generated code is generally considered a big no-no though.

I prefer Java because of it’s verbosity. Makes it easy to maintain even months after I stopped using the code, comparable to C++ or Python where you rather will gain more in rebuilding the whole thing.

Though I can’t see why you would prefer Java over all other languages except as of it’s verbosity. It’s a nice language though it’s not better than all other languages except if you consider verbosity a virtue.

Going from OP:

[quote]System.out.println("BOOM " + explosion.getFloat(STRENGTH));
[/quote]
Where the basic thing is to just do in this case enum STRENGHT instead of “strength”.

You can even make it more fun with:

[quote]System.out.println("BOOM " + EXPLOSION(STRENGHT));
[/quote]

[quote]“Whoever does not understand LISP, he is doomed to reinvent it”.
[/quote]
Metaprogramming makes perfect sense. Your problem is a very common problem that all developers reach at some point of their careers, because it is impossible not to notice certain repetitive tasks that could be automated somehow.

The problem is, Java is a terrible tool for that. That’s why there are so many “frameworks” around. The language itself doesn’t offer an easy way of generating code.

Dynamic languages like Python and Ruby are also bad, because their “metaprogramming” happens at runtime, not compilation.

Lisp has allowed developers to do what you want to do for the last 50 years. No extra libraries or frameworks needed, just the language itself.

I’m all for code generation, but I’m not seeing the need in this case with any of the given examples unless you’re attempt some meta-uber-engine thingy. Why not just classify types of events and use a data-driven model where the parameters are specified in a configuration file? Do whatever works, but codegen seems like overkill without some concrete examples to show what “the problem is”.

LISP is a fantastic language and very worthwhile to learn. And I sincerely hope to never need to (directly) programming in it ever again.

Java is too verbose, but the larger problem here (IHMO) is lack of design. Too little data-driven, too little composition over inheritance, etc.

Hi,

Not wanting to derail the thread but wanting to know more on expanding from “pf” to public final. Is this an eclipse thing? if so which plugin do I need to install? Google search did not reveal anything to me.

Thanks
Paul

I think it’s a customizable thing in the Eclipse preferences menu.

Thanks

I will take a look when I get home.

Paul