in C++, iDevBlogADay, Software engineering

The Const Nazi

Anybody who worked with me or saw any of my code, would know right away why they call me the Const Nazi. That’s because in my coding style, I make use of the keyword const everywhere. But instead of going on about how const is so great, I’m going to let Hitler tell us how he really feels about it.


No Flash? Try the QuickTime video version.

Let me get one thing out of the way to stop all the trigger-happy, const-bashing, would-be-commenters: const doesn’t make any guarantees that values don’t change.

You can change a const variable by casting the constness away, or referencing it through a pointer, but you really had to go out of your way to do that. If it helped with that, const would solve (or improve) the memory aliasing problem like Hitler pointed out. It doesn’t, so const is pretty weak as far as promises go. It just says “I, the programmer, promise not to change this value on purpose (unless I’m truly desperate)”. Still, even a promise like that goes a long way helping with readability and maintenance.

With that out of the way, what exactly do I mean by using const everywhere?

Const non-value function parameters

Any reference or pointer function parameters that are pointing to data that will not be modified by the function should be declared as const. If you’re going to use const just for one thing, this is the one to use. It’s invaluable glancing at a function signature and seeing which parameters are inputs and which ones are outputs.

void Detach(PhysicsObject& physObj, int attachmentIndex, const HandleManager& mgr);

Marking those parameters as const also serves as a warning sign in case a programmer in the future tries to modify one of them. Imagine the disaster if the calling code assumes data never changes, but the function suddenly starts modifying that data! const won’t prevent that from happening, but will remind the programmer that he’s changing the “contract” and needs to revisit all calling code and check assumptions.

Const local variables

This is a very important use of const and one of the ones hardly anyone follows. If I declare a local (stack) variable and its value never changes after initialization, I always declare it const. That way, whenever I see that variable used later in the code, I know that its value hasn’t changed.

const Vec2 newPos = AttachmentUtils::ApplySnap(physObj, unsnappedPos);
const Vec2 deltaPos = newPos - physObj.center;
physObj.center = newPos;

This is one of the reasons why I did a 180 on the ternary C operator (?). I used to hate it and find it cryptic and unreadable, but now I find it compact and elegant and it fulfills my const fetish very well.

Imagine you have a function that is going to work in one of two objects and you need to compute the index to the object to work on. You could do it this way:

int index;
if (some condition)
	index = 0;
else
	index = 2;

DoSomethingWithIndex();

Not only does that take several lines not to do much, but index isn’t const (argh!). So every time I see index anywhere later on in that function, I’m going to have to spend the extra mental power to make sure nothing has changed (and, with my current coding style, I would assume it has changed).

Instead, we can simply do this:

const int index = (some condition) ? 0 : 2;
DoSomethingWithIndex();

Ahhhh… So much better!

Const member variables

This one doesn’t really apply to me anymore because I don’t use classes and member variables. But if you do, I strongly encourage you do mark every possible member function as const whenever you can.

The only downside is that sometimes you’ll have some internal bit of data that is really not changing the “logical” state of an object, but it’s still modifying a variable (usually some caching or logging data). In that case, you’ll have to resort to the mutable keyword.

Const value function parameters

const_nazi.jpgApparently I’m not a total Const Nazi because this is one possible use of const that I choose to skip (even though I tried it for a while because of Charles).

Marking a value function parameter as const doesn’t make any difference from the calling code point of view, but it serves the same purpose as marking local stack variables as const in the implementation of the function. You’re just saying “I’m not going to modify that parameter in this function” so it makes the code easier to understand.

I’m actually all for this, but the only reason I’m not doing it is because C/C++ makes it a pain. Marking parameters as const in the function declaration adds extra verbosity and doesn’t help the person browsing the functions at all. You could actually put the const only in the function definition and it will work, but at that point the declaration and the definition are different, so you can’t copy and paste them or use other automated tools or scripts.

The concept of const is one of the things I miss the most when programming other languages like C#. I don’t understand why they didn’t add it to the language. On something like Python or Perl I can understand because they’re supposed to be so free form, but C#? (Edit: How about that? Apparently C# has const. It was either added in the last few years or I completely missed it before). It also really bugs me that Objective C or the Apple API doesn’t make any use of const.

Frankly, if it were up to me, I would change the C/C++ language to make every variable const by default and adding the nonconst or changeable (or take over mutable) keyword for the ones you want to modify. It would make life much more pleasant.

But then again, that’s why the call me the Const Nazi.

This post is part of iDevBlogADay, a group of indie iPhone development blogs featuring two posts per day. You can keep up with iDevBlogADay through the web site, RSS feed, or Twitter.

39 Comments

    • @SnappyTouch You sure got that video blocked quickly!

    • @SnappyTouch Bah! YouTube blocked your Hitler video due to copyright issues!

    • @SnappyTouch looks like you’ll have to reenact the video yourself πŸ™‚

    • @SnappyTouch Great article! Small error: “which parameters are inputs and which ones are inputs.”.

    • @SnappyTouch I have gone on so many rants…like: Requirement to declare things const OR non-const, not specifying = unacceptable!

  1. If only const in C# behaved the way it did in C++. Unfortunately it means “fixed at declaration time” and is used to create compile-time constants. C# offers up the less-than-helpful “readonly” keyword, which is also limited. There’s no syntax for making the promise “I will not change this variable/parameter” in the way that you can in C++.

  2. C# has *a* const keyword, but it doesn’t do anything like C++ const. It is used for compile-time constants only, and it can’t be used for function parameters or in most of the other cases where you’d use it in C++.

    They also have a ‘readonly’ keyword which is a bit more similar to C++’s const (a readonly class member is initialized from the class’ constructor and can’t be modified afterwards), but again, doesn’t work with function parameters.

  3. “It also really bugs me that Objective C or the Apple API doesnÒ€ℒt make any use of const.”

    On the list of things that bug me about Objective C, that doesn’t even make the top 10.

    I mean, Objective C objects only live on the heap (with very few exceptions). You can mark a pointer to an object as const, but that will just keep the pointer from changing, not the object itself. They somewhat get around this need by marking certain classes as being externally immutable, but even that’s more of a convention than anything in the language itself.

    • @SnappyTouch could not avoid LOL at the “we did it by hand! In assembly!” Now the whole office is looking at me weird

    • @SnappyTouch I use objective c++. I cpp almost entirely for const, and additionally for STL & my own templates.

    • @SnappyTouch we had the mantra “const is your friend” at SCEE Cambridge πŸ™‚ Worked great if used from start, but a bugger to retrofit!

  4. You missed another case:

    bool FooClass::AnswerToEverything( const int arg ) const
    {
    return arg == 42;
    }

    Perhaps in your coding style this isn’t so important but I find it very useful to use this one where possible.

  5. There’s another good reason why reference function parameters that will not be modified by the function should be declared as const: it enables you to build thoses parameters on the stack. Take this example:

    struct Vector
    {
    Vector(float _x, float _y, float _z) : x(_x), y(_y), z(_z) {}
    float x, y, z;
    };

    void IncrementVector(Vector& _vector, const Vector& _increment)
    {
    _vector.x += _increment.x;
    _vector.y += _increment.y;
    _vector.z += _increment.z;
    }

    int main()
    {
    Vector data(1.0f, 2.0f, 3.0f);
    IncrementVector(data, Vector(1.0f, 0.0f, -1.0f));
    }

    Since the second argument of the “IncrementVector()” function as been declared as “const”, it is possible to pass an object constructed on the stack right in the function call. This can be really handy.

    If the “_increment” parameter was not declared as “const”, you would get a compiler warning (a non-const reference may only be bound to an lvalue).

  6. One more case:

    const char *Foo::getString(const char * const somestr) const
    {
    somestr = new char; // Compile error!!
    mSomeMemberVar = 42; // Compile error!!

    return NULL;
    }

    Is a member function which will not modify any member variables. Returns a pointer to memory with contents that cannot be modified. Takes, as a parameter, a pointer which cannot be assigned a different address.

    Thanks for writing this blog entry, and that Hitler spoof is one of the funniest I’ve seen.

  7. “Frankly, if it were up to me, I would change the C/C++ language to make every variable const by default and adding the nonconst or changeable (or take over mutable) keyword for the ones you want to modify. It would make life much more pleasant.”

    OCaml, Clojure, and a host of other fine languages are out there waiting for you.

  8. I have no objections, see, to your immutable philosophy

  9. this reminds me of an article in Game Developer, which can be summed up nicely as:

    #define const

    Of course, because overloaded functions can differ in their const definition, to const_cast a function’s constness away can be done when calling a const function within a non-const function [since the calling function doesn’t promise constness the casting away of const still keeps with the overall intent, although casting is never fun]. Bit of a mouthful that paragraph, isn’t it…

    To give credit where credit is due, my love of const started because of Scott Meyers’ Effective C++.

  10. When I read this I immediately relate to things like NS/NSMutable – and it makes perfect sense.

  11. I think both me and Charles can attest to many days spent going down the rabbit hole, chasing the const correctness pipe dream. “Hm, this one thing could be const. Ops, couple of compile errors. Let me fix those. Hm, some more compile errors. Sigh, let me fix those. Ahhhrrg! I did nothing today but fix const in the codebase. What was I doing again?” πŸ™‚

    But I gotta agree, it gives me some kind of OCD satisfaction to fix them. Wonder if there is a trophy somewhere?

  12. Well if you changed all variables to be const by default you’d be making C/C++ into a more functional type language. Since in general variables in a functional language – if they exist at all – are a write-once read-many thing. You essentially bind a value to a name, which is what you’re doing with making the local variables const. Coincidentally also what you’re doing when making functions const, and function parameters const.

  13. What Jim Tilander said.

    What leaves a bad taste in my mouth is when I have to duplicate methods (or const_cast, which is equally disgusting) to satisfy the inner Hitler. E.g. two world query functions, one of them returning const pointers to objects in range, the other returning mutable pointers.

  14. @Jim, I think it’s only a pain to make something const-correct if you’re retrofitting it as an afterthought. If you find yourself changing something from const to non-const and having to propagate that, it probably means it’s a very serious data flow change (and the compiler “helps” you along to find where your assumptions are now wrong).

    @Ivan Asset, Yes, I completely agree that it’s a pain having to have duplicate const/non-const functions sometimes. I wish there was an easy way around that (first one to mention templates or macros gets banned from posting anymore ;-b

  15. I did a search for “const” in my current C# prototype out of curiosity: I really don’t use it much at all, except for things that are seriously written in stone (such as a cube having “const int vertexCount = 8;” vertices).

    The readonly keyword is useful when creating immutable structs.

  16. Hi Noel, love the video – but then again I’m another Const Nazi. πŸ™‚

    “You could actually put the const only in the function definition and it will work…”

    This is my preferred method.

    “… but at that point the declaration and the definition are different”

    There’s probably some finer points on that but I catch your drift.

    “… so you canÒ€ℒt copy and paste them or use other automated tools or scripts.”

    Just out of curiosity what kind of automated tools or scripts are you talking about here. I get you can’t copy and paste the function signature between the defintion and declaration (which is over little concern to me) but what other tools/methodologies are undone by having const value types in the function defintion?

    Great post, btw. Had a good laugh.

    • Right now the only reason for me not to add const in the value function parameters is because I can’t copy/paste between cpp and header file (or I can, but I bring all the ugly consts along with it). It might sound silly, but minimizing extra busy work is a big deal for me. I hate having to duplicate function signatures in the header and cpp files, so I’m not about to start modifying them.

      At some points in the past we had scripts to parse files and generate information or documentation or whatever. If the function declaraction and definition didn’t match exactly, it would get all confused.

  17. MyObj const * const obj = Manager.GetObject( uuid );

    or

    const MyObj * const obj = Manager.GetObject( uuid );

    or

    const MyObj * obj = Manager.GetObject( uuid );

    ? πŸ™‚

  18. Loved this and I was very encouraged that you’re using const. It’s an easy concept, but readily overlooked in computer science classes. Most students never get exposed to it in school and only some shops actively encourage its use. It is, however, so important that it’s item 3 in “Effective C++”. πŸ™‚
    Thanks for making the case and encouraging folks to use const where possible. Great advice!

  19. You are a “const nazi” while not using classes at all? What a strange combination… I think declaring variables as private is much more important than const.

Comments are closed.

Webmentions

  • Knowing .NET » Blog Archive » Twitter Weekly Updates for 2010-07-18 July 21, 2010

    […] hates undisciplined C developers http://gamesfromwithin.com/the-const-nazi […]