Make A5 API const-correct?


consider the A5 API function al_get_bitmap_width(ALLEGRO_BITMAP* b). I assume that this function will never modify *b. Nonetheless, the API doesn't declare it as al_get_bitmap_width(const ALLEGRO_BITMAP* b), which would give usercode stronger guarantees.

Does al_get_bitmap_width really never modify the pointed-to bitmap, or does merely the API promise less than it could?

Is it feasible to make the Allegro 5 API const-correct?

I'm calling A5 through SiegeLord's DAllegro5 bindings, have D's const in my usercode wherever possible, but then have to cast the const away before calling DAllegro5. I have considered to move the responsibility to DAllegro5, but ideally, the responsibility should be with A5 itself, and its API.

I would love to see a const-correct API. This would not merely help in D usercode, but also in C, C++, ..., and should be fully backwards-compatible with the non-const-correct API.

On the other hand, once you introduce const in the A5 API, you cannot remove it without breaking bindings or usercode. I would understand if you preferred to be really careful here. Would you then suggest that the bindings guarantee const, or that I cast in usercode every time I call the bindings, or that I omit const whatsoever with anything from Allgero 5?

-- Simon


I'm not well versed on the specifics, but it is my understanding that C doesn't really honor const to the full extent that C++ does. It's more of a suggestion than a rule (which says something since even in C++ you can always override it). Since Allegro is a C library written and maintained mostly by C programmers it seems unlikely that they'll go to any lengths to revise the library this way.

That said, I think that the contents of a bitmap structure are considered internal to the library and not meant to be manipulated by you. If there is a library function that changes the behavior or content of a variable in a meaningful way it would be documented, but the library might need to modify the internals without impacting the usage. Adding const-correctness can complicate matters. It could be that originally a function doesn't need to modify the contents and so it can define the interface as const. Later it might need to modify the contents, but still without affecting the user. But then they couldn't make that change (painlessly) because the library API would already be established and changing it could break user code.

Of course, the internal code could always force a cast to non-const to modify it anyway, which would solve the problem without modifying the interface. However, it kind of defeats the purpose of const-correctness in the first place that this is possible.

I'm not a developer. I'm not opposed to them doing this. Just chiming in with what I think the response will be based on my experiences here. :) If it becomes a problem in D then perhaps it is something that the D bindings should address.


I agree -- if the A5 team feels like const restricts the implementation in the slightest way, the API will stay const-less, with good reason. If A5 had to cast internally, it shouldn't promise constness.

I would merely like a high-level reply from upstream here before finding the best D-specific solution with SiegeLord. :-)

-- Simon

Chris Katko


The dev mailing list would probably be the best way to get the devs attention.

Bruce Perry
bamccaig said:

the library might need to modify the internals without impacting the usage

In C++, that's what mutable is for. I suppose C doesn't have it though.


I personally think that certainly in c const "correctness" is more trouble than it's worth. Even for something simple like the size of a bitmap, it might be a cached value that is calculated on first access. For something like fonts this might even mean loading on demand.

Chris Katko
beoran said:

Even for something simple like the size of a bitmap, it might be a cached value that is calculated on first access.

Aside: I've actually been planning on making a cached_handle type for my D games! The idea is that all/most/many objects have "handles" to each other so I can easily save games (or serialize data for network) without worrying about pointers being different. You literally just send binary copies of the data. However, for speed, those handle structures (which could work by string, "CLOUD_SPRITE", for example) retrieve the relevant object pointer (though an associated array in this example) and then save that pointer. Then, a resource_handler class actually maintains an array of references to every handler and can mark them as invalidated/dirty. So if that handle's data actually changes location (like rarer but necessary edge case where an object moves around in physical memory) then it will automatically re-grab the proper lookup on the next access.

So I could have user-friendly static resource names like bitmap["CLOUD_SPRITE"], as well as serialization for dynamic data (objects that know about other objects), while having almost zero overhead for the benefit.


The Allegro API is const correct (it does use const for many API methods after all).

The question here is should al_get_bitmap_width in particular get a const bitmap reference. As was pointed out, many bitmap functions are a gray area as even just reading a property may require updating a cache or modifying a locked state.

But in general any Allegro function which does not modify a pointer passed to it marks it as const and if one is missing that is a bug and we will fix it.


Thanks for all the replies!

If al_get_bitmap_width changes hidden state, then the argument should indeed remain non-const.

In my particular case, since D's const is transitive (everything reached through const is again treated const), it would even be a typesystem violation to take a pointer to an immutable bitmap, then modify hidden state. In practice, it wouldn't be an issue since we allocate only through create_bitmap, but in theory, it allows undefined behavior from compiler optimization. Therefore, neither A5 nor SiegeLord's bindings should allow const, but instead push the responsibility to the usercode.

Alternatives for a D user project, then, are

  • Chris's extra handles instead of the pointer itself, or

  • usercode-private wrappers around bitmap functions that cast away const, with a codebase-wide rule to never call them with immutable, only with const.

-- Simon


I think const in C is not recursive, so we could just do this:

    ALLEGRO_BITMAP *internal;

int internal_width(ALLEGRO_BITMAP *bitmap) {
    bitmap->cache = 5;
    return bitmap->cache;

int al_get_bitmap_width(ALLEGRO_BITMAP const *bitmap) {
    return internal_width(bitmap->internal);

But this probably just shows that the concept of const in C is not all that useful.

Thread #617173. Printed from