High Programmer > Alan De Smet > Rants > C++'s mutable and conceptual constness

C++'s mutable and conceptual constness

Here is what About.com claimed about the C++ keyword "mutable" (at least until recently):

Mutable

The keyword mutable is used to allow a particular data member of const object to be modified. This is particularly useful if most of the members should be constant but a few need to be updateable. Suppose we add a "salary" member to our Employee class. While the employee name and id may be constant, salary should not be. Here is our updated class.

class Employee {
public:
    Employee(string name = "No Name", 
        string id = "000-00-0000",
        double salary = 0)
    : _name(name), _id(id)
    {
        _salary = salary;
    }
    string getName() const {return _name;}
    void setName(string name) {_name = name;}
    string getid() const {return _id;}
    void setid(string id) {_id = id;}
    double getSalary() const {return _salary;}
    void setSalary(double salary) {_salary = salary;}
    void promote(double salary) const {_salary = salary;}
private:
    string _name;
    string _id;
    mutable double _salary;
};

Now, even for a const Employee object, the salary may be modified.

const Employee john("JOHN","007",5000.0);
....
....
john.promote(20000.0);

No, no! A thousand times, no!

I've seen this sort of terrible idea before. This sort of madness leads to flawed code and defeats the entire purpose of const in C++. I can only conclude that the people writing this sort of nonsense themselves don't understand the purpose of mutable. So they teach a mistake, passing on this nonsense to the next group of C++ programmers who pass it on themselves. This must stop.

When you mark a variable const, you are promising (and asking C++ to enforce) that you will never logically modify the contents of that object. Perhaps the most useful reason to do this is when you pass an object into a function by reference or pointer. By making it const, the function promises to not mess with your object. For example, say you have a class Robot that inherits from Person. You want to pass your Robot into the function take_pulse. You want take_pulse to use Robot's overridden methods, so take_pulse takes the object by reference. Because it's const, you can be confident that take_pulse won't modify the Robot, just read from it:

class Person {
public:
    virtual bool has_pulse() const { return true; } 
    void set_name() { /* ... */ }
};

class Robot : public Person {
public:
    virtual bool has_pulse() const { return false; }
    void set_name() { /* ... */ }
};

/*
Because Person is const, take_pulse cannot call set_name().
Because Person is a reference, we can pass in a Robot robot
and get the correct answer (false).
*/
bool take_pulse( const Person & X ) {
    return X.has_pulse();
}

It's nonsense to make the salary mutable; you're just making it possible for code that gets a constant object to mess with the salary. If the employee is constant, you shouldn't be messing with his salary.

So what if you want the employee's name and id to be constant, but not the salary? Well, just say so!

class Employee {
public:
    Employee(string name = "No Name",
        string id = "000-00-0000",
        double salary = 0)
    : _name(name), _id(id)
    {
        _salary = salary;
    }
    string getName() const {return _name;}
    string getid() const {return _id;}
    double getSalary() const {return _salary;}
    void setSalary(double salary) {_salary = salary;}
    void promote(double salary) {_salary = salary;}
private:
    const string _name;
    const string _id;
    double _salary;
};

Now they're constant. Of course, this means you can only set them in the constructor.

So if the above madness isn't what mutable is for, what is it for? Here's the subtle case: mutable is for the case where an object is logically constant, but in practice needs to change. These cases are few and far between, but they exist.

Here's one example: You have a constant object, but for debugging purposes want to track how often a constant method is called on it. Logically you're not changing the object. Note that if you're making decisions in your program based on a mutable variable, you've almost certainly violated logical constness and need to rethink things.

class Employee {
public:
    Employee(const std::string & name) 
        : _name(name), _access_count(0) { }
    void set_name(const std::string & name) {
        _name = name;
    }
    std::string get_name() const {
        _access_count++;
        return _name;
    }
    int get_access_count() const { return _access_count; }

private:
    std::string _name;
    mutable int _access_count;
};

As a more complex example, you might want to cache the results of an expensive operation:

class MathObject {
public:
    MathObject() : pi_cached(false) { }
    double pi() const {
        if( ! pi_cached ) {
            /* This is an insanely slow way to calculate pi. */
            pi = 4;
            for(long step = 3; step < 1000000000; step += 4) {
                pi += ((-4.0/(double)step) + (4.0/((double)step+2)));
            }
            pi_cached = true;
        }
        return pi;
    }
private:
    mutable bool pi_cached;
    mutable double pi;
};

Now we don't calculate pi until someone asks for it, but when they do we cache the result, which is good because we're calculating it in a really slow and stupid way. Logically the function is still const (pi isn't about to change).

Ultimately you almost certainly do not need mutable at any given moment. I've gone years between wanting the mutable keyword. If you think you need mutable, think twice. Be sure that the object will still be logically constant, even as its internals change.

Footnote

I'd link to the about.com article, but it's gone. Perhaps they deleted it because it was so terrible. However, I've had all too many links to content at About.com break. Apparently no one there realizes that the key to maintaining a good reputation and inbound links is to keep old links valid. Here's a copy of maintained at archive.org.

(Update 2006-11-28: Released under a Creative Commons license. Fixed a few typos, cleaned up some phrasing, re-wrapped code.)

(Update 2006-12-30: Fixed two mistakes in my "correct" Employee example with _access_count. _access_count is now mutable, and get_name returns a name instead of trying to set it. Thanks to K. Rose for letting me know.)

(Update 2007-02-20: Replaced old Google cache link that has since expired with a link to archive.org.)

(Update 2008-03-07: Removed "const" from the promote() function in my "correct" Employee example. Since it modifies the salary, it's hardly constant. Thanks to Kenneth Porter for letting me know.)

This page can be discussed over in my comments. There are currently comments.

Contact webmaster - Copyright © 2006 Alan De Smet (2006-10-16)
Creative Commons License
This web page is licensed under a Creative Commons Attribution 2.5 License. Attribution should be to "Alan De Smet". If possible a hyperlink to http://www.highprogrammer.com/alan/rants/mutable.html should be provided, otherwise print the URL "http://www.highprogrammer.com/alan/rants/mutable.html".