Should every variable be const by default?

Author: Chloé Lourseyre

A bit of terminology

In the title, I used the word “const” because const is a keyword every C++ developer knows (I hope). However, the generic concept this article is about is actually called “immutability”, and not “constness”. const is a keyword used in some languages (C++, Javascript, etc.) but the concept of immutability exists in other languages (in some of them, there is even no keyword attached to the concept, like in Rust).

To be a little more inclusive, I will use the words immutable and immutability instead of const and constness.

Nota bene: in C++ the keyword const does not completely refer to immutability. For instance, you can use the keyword const in a function prototype to indicate you won’t modify it, but you can pass a mutable object as this parameter. However, this article only refers to const as a way to render data immutable, so I would be grateful if you ignore situations where const does not refer to inherently immutable data. That is also another reason I wish to use the word immutable and not const.

Some very good reasons to make your variables immutable

Safety

What is called const-correctness in C++ is the fact that if you state that a given variable is immutable, then it won’t be modified.

Const-correctness is reached when you use the const keyword to tell when a variable won’t be modified. Then, you won’t be able to inadvertently modify something you shouldn’t and you give insight to the compiler and the developers of the data you manipulate.

Documentation

These five characters tell a lot. If you find yourself in a reliable code, where you are sure that const is used properly, then this keyword -or its absence- serves as an indication of the intended mutability of the variable.

Optimization

The compiler can (and will) optimize the code according to the const directives.

Knowing that some values are immutable, the compiler will be able to make assumptions and use syntactic shortcuts.

You can feed on J. Turner’s talk on the subject of practical performance: Jason Turner: Practical Performance Practices – YouTube.

Source

If you still doubt that immutability is useful in C++ (or are just curious, which you should be), please read these:

Are there downsides to using immutability whenever possible?

Since immutability is a technical restriction, there is no technical downside to using it.

However, there may be some non-technical downside of using const. First, it increases the verbosity. Even if it’s a 5-letters word that often has the same color as the type (in most IDEs), some people might find this impairing. There is also inertia: if you need to modify the variable, you’ll have to go and remove the keyword. Some may consider it a safeguard, others an impairment.

Are these arguments enough to not use immutability as soon as you can? It’s up to you, but in my humble opinion, I think not.

Other languages?

Other languages make variables immutable by default.

One famous example is the Rust language. In Rust, you don’t have the const keyword. Instead, every variable is by default immutable, and you can add the mut keyword to make them mutable.

For instance, in Rust, the following code doesn’t compile:

fn main() {
    let foo = 2;
    println!("Foo: {}", foo);
    foo += 40; // error[E0384]: cannot assign twice to immutable variable `foo`
    println!("Foo: {}", foo);
}

But this is correct:

fn main() {
    let mut foo = 2;
    println!("Foo: {}", foo);
    foo += 40;
    println!("Foo: {}", foo);
}

The reason mentioned in the Rust Handbook is the following: “This is one of many nudges Rust gives you to write your code in a way that takes advantage of the safety and easy concurrency that Rust offers.”

Rust is a pretty modern language that aims to provide safety to the developer along with top-tier performances. I agree with its intention to make variables immutable by default because of the safety it brings.

Is it reasonable to change the standard to make variables immutable by default?

If one fateful day the C++ committee decides to make every variable const by default… no one will upgrade to the vNext of C++.

Retro compatibility is important to smooth the transition between vPrevious and vNext. There are few historical examples where a feature has been removed from the standard, and for each, there is a really good reason why (often being years of deprecation).

But we can’t seriously consider removing the keyword const and add the keyword mut just for the sake of what is, in the end, syntactic sugar.

What to do then?

I for one chose to use the const keyword every single time I declare a variable. I only remove it when I actually write an instruction that requires it to be mutable (or when the compiler realizes it needs to modify a constant variable and outputs an error). This is a little blunt, but in my opinion, it’s the best way to ensure to catch the habit of putting const by default.

Of course, you may try to be smart at the moment you declare the variable and try to foresee the use you’ll make of it, but I guarantee you will not be 100% reliable and miss opportunities to make variables immutable.

So here’s my advice: until you catch the habit of putting const everywhere, use const by default without double thinking. You may have regular easy-to-solve compilation errors, but you’ll catch a good habit.

And what about constexpr?

constexpr is a modifier that indicates that the value of a variable can be evaluated at compile time. Its purpose is to transfer some evaluation to the compilation phase.

In a sense, it is stronger immutability than the keyword const. All I said in this article about immutability applies to constexpr: use it as often as you can.

However, unlike const, I don’t advise trying to use it everywhere and see afterward if it needs to be removed, since it’s way rarer and a bit more obvious to use. But keep in mind to check if you can use constexpr every time to declare a variable.

Thank you for reading and see you next week!

Author: Chloé Lourseyre

10 thoughts on “Should every variable be const by default?”

  1. Good one. I’m 10000% with you. Recently, maybe 3 years ago I started const everything (and constexpr whenever possible) and it’s just a simple habit. Thank you again for such a nice writeup.

  2. 🤔 If a variable (something that “varies”) is constant (meaning it never “varies”). So the article title is an oxymoron. How about constant “field” or constant “definition”? That said, I default to putting “const” before every local definition, and I wish that “const” alone implied “auto” too. That is “const x = 5;” would just work as “const auto x = 5”. I believe this should be safe now in the grammar, given default int has been deprecated for a long while.

  3. Great, I think this article will fundamentally change my programming style 🙂 Has anyone gone so far to make all parameters passed by value consts?
    e.g.
    int BigAlgo(const int x, const int y, const int z);

Leave a Reply