How Sutter’s Wrong About const in C++ 11

Herb Sutter recently gave a talk about how the const keyword and the mutable keyword have subtle but profoundly different semantics in C++ 11. In a nutshell, he says that C++ 11 corrects the wishy-washy definition of const in C++ 98; const used to mean “logically constant,” but now it means thread-safe. And mutable now means thread-safe as well. His summary slide says:

const == mutable == thread safe (bitwise const or internally synchronized)

Editor’s note: Since this post was written, Herb has updated his slide. See Herb’s note in the comment stream below.

Now, I think Herb’s talk is quite informative, and I don’t dispute the core of what he was trying to convey. It’s a good insight, well worth the community’s attention. I learned something important; I recommend that you watch the talk. Using const well is an essential skill. But I think in his enthusiasm about the way the language has evolved to make semantics clearer, Herb does us a disservice by oversimplifying.

When Herb uses the C++ == operator to boil his point down to a pithy summary, he’s implying true equivalence; what’s on one side of the operator is, for all intents and purposes, identical to or indistinguishable from what’s on the other side. And while const and mutable and thread-safe are highly related concepts, they are not equivalent enough to each other for ==.

To understand why, answer the following question: Why would good code use const and/or mutable even if it’s single-threaded?

Ah. I imagine you nodding your head sagely. You see where I’m going, don’t you?

These two keywords don’t just define semantics for cross-thread access; they define the semantics a variable or object supports when accessed by various scopes (e.g., subroutines or code blocks) on the same thread. If you pass a const Widget & to a function, that function can’t call Widget::modifyState() even if it’s the only thread in the universe. If you declare a m_lazy_init member variable to be mutable, you are telling the compiler to let you change it where it would normally be disallowed, including on the same thread.

So: const means unchangeable in whatever scope sees const (including many threads), which is why it also implies thread-safe (if all threads see const); mutable means changing safely in one or many threads, which is why it also implies thread-safe (if all threads see const). In C++ 98, these semantics were a bit loose. You could use them carelessly, cast away parts of their guarantees, and generally operate as a law unto yourself. In C++ 11 the semantics of const and mutable are explicit and exacting; the standard library demands thread-safe copy construction. As a result, their role in thread safety is clarified, and we all write better code. Mutexes and atomics and certain kinds of queues are inherently safe to change from any thread; they deserve and require the mutable keyword.

Instead of Herb’s final equation, I’d propose a Venn diagram:

The const and mutable keywords are not equivalent in C++ 11, but they do share guarantees about thread safety.

The const and mutable keywords are not equivalent in C++ 11, but they do share guarantees about thread safety.

How Enums Spread Disease — And How To Cure It

Poorly handled enums can infect code with fragility and tight coupling like a digital Typhoid Mary.

Say you’re writing software that optimizes traffic flow patterns, and you need to model different vehicle types. So you code up something like this:

vehicle_type.h

enum VehicleType {
    eVTCar,
    eVTMotorcycle,
    eVTTruck,
    eVTSemi,
};

Then you press your enum into service:

route.cpp

if (vehicle.vt == eVTSemi || vehicle.vt == eVTTruck) {
    // These vehicle types sometimes have unusual weight, so we 
    // have to test whether they can use old bridges...
    if (vehicle.getWeight() > bridge.getMaxWeight()) {

Quickly your enum becomes handy in lots of other places as well:

if (vehicle.vt == eVTMotorcycle) {
    // vehicle is particularly sensitive to slippery roads

And…

switch (vehicle.vt) {
case eVTTruck:
case eVTSemi:
    // can't use high-occupancy/fuel-efficient lane
case eVTMotorcycle:
    // can always use high-occupancy/fuel-efficient lane
default:
    // can only use lane during off-peak hours
}

Diagnosis

The infection from your enum is already coursing through the bloodstream at this point. Do you recognize the warning signs?

  • Knowledge about the semantics of each member of the enum are spread throughout the code.
  • The members of the enum are incomplete. How will we account for cranes and bulldozers and tractors and vans?
  • Semantics are unsatisfying. We’re saying cars are never gas guzzlers or gas savers; what about massive old steel-framed jalopies and tiny new hybrids?

A vehicle that challenges our tidy enum. Photo credit: Manila Imperial Motor Sales (Flickr)

The infection amplifies when we want to represent the enum in a config file or a UI. Now we need to Continue reading

Unencapsulate Yourself

We loved to escape the boxes when we were kids… Photo credit: thewoodenshoes (Flickr)

If I had to make a “top 5” list of foundational tools in software development, encapsulation would certainly make the cut. It’s a major enabler of abstraction; it’s what makes conceptual complexity tractable.

Recognizing its importance, most modern programming languages encourage encapsulation in one way or another. For example, languages friendly to OOP lead coders to think about the world in terms of well encapsulated objects and the messages they pass.

I’m a big fan of encapsulation.

But if you never leave your boxes, you miss half the fun.

Layers and silos

As cells grow into tissues in biology, so similar objects in an OOP mindset often coalesce into horizontal layers composed of entities with compatible composition and duties. These strata get names: “the business logic layer”, “the display layer”, “middleware”, “core engine”, and so forth. If you’ve worked on anything MVC or n-tier or client-server, you know this mindset.

Less commonly, objects align on a vertical axis, producing semi-independent silos that span layers to produce decoupled top-level features. An optional accounting module that has its own db and middleware might be modeled as an independent stack in a vertical architecture. Aspect-oriented programming also spans layers, though in a less siloed way.

In either case, the boxes you draw to model your architecture tend to correspond to teams, and those teams tend to use different tools and processes, and those differences tend to isolate rather than converge organizations.

This is a problem.

You should encapsulate code. People, not so much.

Generalists and specialists

Specialists have their place. But if your dev organization is overly skewed toward specialists Continue reading

Progressive Disclosure Everywhere

If you google “progressive disclosure,” you’ll get hits that describe the phrase as an interaction design technique. UI folks have long recognized that it’s better to show a simple set of options, and allow users to drill into greater detail only when they need it. (Thanks to James Russell–a brilliant UI designer–for teaching me PD years ago.)

But calling progressive disclosure a “technique” is, I think, a serious understatement. Progressive disclosure aligns with a profound cognitive principle, and its use is (and should be) pervasive, if you have eyes to see.

The Principle

Here’s my best attempt to distill the operative rule behind progressive disclosure:

Focus on essence. Elaborate on demand.

In other words, begin by addressing fundamentals without cluttering detail. When more detail is needed, find the next appropriate state, and move there. Repeat as appropriate.

Stated that way, perhaps you’ll see the pattern of progressive disclosure in lots of unexpected places. I’ve listed a few that occur to me…

Manifestations

The scientific method is an iterative process in which hypotheses gradually align to increasingly detailed observation. We learn by progressive disclosure.

Good conversationalists don’t gush forever on a topic. They throw out an observation or a tidbit, and wait to see if others are interested. If yes, they offer more info.

The development of a complex organism from a one-celled zygote, through differentiation and all subsequent phases, into adulthood, could be considered a progressive disclosure of the patterns embedded in its DNA. The recursive incorporation of the golden mean in many morphologies is another tie to biology.

A nautilus grows–progressively discloses–the protective covering it requires over its lifespan. The golden mean, repeated and repeated… Photo credit: Wikimedia Commons.

In journalism, the inverted pyramid approach to storytelling is a form of progressive disclosure. So are headlines.

Depending on how you’re reading this post, you might see a “Read more…” link that I’ve inserted right after this paragraph. Making below-the-fold reading optional is progressive disclosure at work. TLDR…

Continue reading