views:

180

answers:

5

The project I'm working on requires me to write lots of repetitive code. For example, if I want to load a image file called "logo.png" in my code, I would write something like this: Bitmap logoImage;

...
// Init
logoImage = load("logo.png")

...
// Usage
logoImage.draw(0, 0);

..
// Cleanup
logoImage.release();

Having to write this code to use every new image is a pain, including having to specify that logoImage should load the file "logo.png".

As I'm working on a Java Android game and images are used a lot in inner loops, I really want to avoid slow things like making virtual function calls and e.g. accessing arrays/maps/object fields when I can avoid it. Copying an idea from the Android API (the generated R class), I thought I could run a utility before compiling to generate some of this repetitive code for me. For example, the actual code in the project file would be reduced to just this:

logoImage.draw(0, 0);

Using some command-line tools (e.g. grep, sed), I can look for every instance of "Image.draw(..." and then generate the other required code automatically i.e. code to load/release the file .png and declare "Bitmap logoImage" somewhere. This code could either be added to a new class or I could add placeholders in my code that told the code generator where to insert the generated code.

To display a new image, all I would need to do is just copy the image file to the right directory and add one line of code. Nice and simple. This avoid approaches like creating an array of images, defining labelled int constants to references the array and having to specify which filename to load.

Is this a really bad idea? It seems a bit of a hack but I can see no easier way of doing this and it does seem to drastically clean up my code. Are there any standard tools for doing this simple kind of code generation (i.e. the tool doesn't need to understand the meaning of the code)? Does anyone else do things like this to make up for language features?

+2  A: 

Avoid code-generation. It often makes code hard to maintain.

In your case why don't you just make:

public class ImageUtils {
    public static void drawAndRelease(String name) {
        logoImage = load(name)
        logoImage.draw(0, 0);
        logoImage.release();
    }
}

and then just call:

ImageUtils.drawAndRelease("logo.png");

If there is more code between these methods - well, then they are atomic methods and you won't know where to put them in case you use code-generation.

Bozho
"used a lot in inner loops".
Anon.
ehm, so what..?
Bozho
Anons point is correct: it's a game so loading and releasing images every frame will kill my framerate. I don't understand your point about atomic methods: I just need to tell my tool where to put all the load and release calls e.g. inside a generated class.
Bob Page
then you have to think of your algorithm optimization, rather than program shortness. My point was that you won't be able to instruct your tool where to put these methods. But then - I don't see the full picture, so I might be wrong.
Bozho
A: 

Several ways:

Eclipse code2code, you cod in template using template language such as FreeMarker, groovy, etc

eclipse sqLite plugin for Android autogenerates sqlite code

MotoDevStudio4android has code snippets which yo could use

Fred Grott
+1  A: 

I second Bozho's answer about avoiding code generation, but if you have to write repeatable snippets of code, any good IDE usually has some built in support for specifying your own snippets with variables and everything. IntelliJ IDEA has this feature, it's called Live Templates. I would guess both Eclipse and NetBeans has similar functionality.

rlovtang
I agree with using IDE features, but I cannot see how a template will know where to put the load/release code.
Bob Page
+1  A: 

You transfer complexity to code generation, and it (generation) is not trivial and may be buggy. Code is harder to read and maintain. Some clear rules to design and coding are more helpful here.

p4553d
Both options are not great though in terms of complexity. I'd say my generation one is much easier to maintain. Without my code generation idea, the original code is quite complex and it gets a lot worse the more images you work with. I don't intend to do much generation beyond what I've stated, except using the idea for e.g. sounds.
Bob Page
+4  A: 

It would be a bad idea to use code generation for something like this. (IMO, code generation should be reserved for situations where you need to generate vast amounts of code, and this doesn't sound like that situation.)

If the boilerplate code in your current solution concerns you, a better solution (than code generation) is to implement an image registry abstraction; e.g.

public class ImageRegistry {
    private Map<String, Image> map = new HashMap<String, Image>();

    public synchronized Image getImage(String filename) {
        Image image = map.get(filename);
        if (image == null) {
            image = load(filename);
            map.put(filename, image);
        }
        return image;
    }

    public synchronized void shutdown() {
        for (Image image : map.valueSet()) {
            image.release();
        }
        map.clear();  // probably redundant ...
    }
}

Replace logoImage.draw(0, 0) and the like with:

registry.getImage("logo.png").draw(0, 0);

remove all of the load calls, and replace all of the release calls with a single call to registry.shutdown().

EDIT in response to the OP's comments below:

... but I mention that I'm writing a game for a phone. A HashMap lookup every time I'm drawing a sprite will kill performance.

Ah ... I remember you from another thread.

  1. You are (yet again) making assumptions about performance without any basis in actual performance measurements. Specifically, you are assuming that HashMap lookup is going to be too expensive. My gut feeling is that the time taken to do the lookup will be a small percentage ( < 10% ) of the time taken to draw the image. At that point, it is approaching the level at which it is unnoticable to users.

  2. If your measurements (or gut feeling) tells you that a hashmap lookup is too expensive, it is a trivial modification to write this:

    Image image = registry.getImage("logo.png"); while (...) { ... image.draw(0, 0); }


For example, Google even go as far as to recommend you don't use iterators in inner loops because these cause the GC to fire when the Iterator objects are deallocated.

That is irrelevant and inaccurate.

  1. A HashMap lookup using a String key does not generate garbage. Not ever.

  2. Using an iterator in an inner loop does not "cause the GC to fire when the Iterator objects are deallocated". In Java, you don't deallocate objects. That is C/C++ thinking.

  3. Instantiating an iterator in an inner loop does new an object, but the GC will only fire if the new operation hits the memory threshold. This happens only occasionally.


*Also, writing "file_that_does_not_exist.png" will not be picked up as a compile time error with your example.*

Neither your original solution, or the code generation approach can give you a compile time error for a missing file either.

Stephen C
Thanks for the code example, but I mention that I'm writing a game for a phone. A HashMap lookup every time I'm drawing a sprite will kill performance. For example, Google even go as far as to recommend you don't use iterators in inner loops because these cause the GC to fire when the Iterator objects are deallocated. Also, writing "file_that_does_not_exist.png" will not be picked up as a compile time error with your example.
Bob Page
"You are (yet again) making assumptions about performance..." I'm just exploring the alternatives. If a 10% faster way is 90% ugly I'm not going to use it. My link to the google doc was to demonstrate that google themselves (from experience) recommend similar small optimizations."it is a trivial modification to write this:": This is the exact kind of redundant code I want to avoid."Neither your original solution...": It would be trivial to add a file check to the generation tool. This is what google's tool for R classes does.
Bob Page
I don't think there's much point in me responding to this anymore. You have obviously made up your mind, and you don't seem to be taking on-board anything I'm saying. Good luck.
Stephen C
I'm not being closed minded: I'm simply critiquing your suggested approaches, the same as I have done with mine. Neither solution is perfect.I just benchmarked Hashmap.get: only 21 calls (could be optimised a little but this is a modest number anyway) per game frame took 10% of the CPU time, more time than updating the game state each frame! Each call took about 25% of the time it took to draw one bitmap. This approach is clearly very wasteful for a game compared to using direct references to the images or arrays+constants. I don't even see what advantage HashMap offers here.
Bob Page
By the way, I'm aware of points 1,2 and 3 you made. My comment was slightly ambiguous but I was trying to be brief. I'm not sure much android programming you've done, but, seriously, creating a few strings or a few iterators each frame in inner loops will create garbage (you cannot recycle these), giving your game 300ms pauses every 5 or 10 seconds. It's very noticeable. I recommend this google talk which has related tips and some benchmarks: http://code.google.com/events/io/2009/sessions/WritingRealTimeGamesAndroid.html.
Bob Page