Trip Report: October 2007 ISO C++ Standards Meeting

The ISO C++ committee met in Kona on October 1-6. Here’s a quick summary of what we did, and information about upcoming meetings.

What’s in C++0x, and When?

As I’ve blogged before (most recently here and here), the ISO C++ committee is working on the first major revision to the C++ standard, informally called C++0x, which will include a number of welcome changes and enhancements to the language itself as well as to the standard library.

The committee is determined to finish technical work on this standard in 2009. To that end, we plan to publish a feature-complete draft in September 2008, and then spend the next year fine-tuning it to address public feedback and editorial changes.

Note that this represents essentially a one-year slip from the schedule I blogged about at the beginning of the year. Why the slip? There are a few major features that haven’t yet been "checked in" to the working paper and that are long poles for this release. Here are three notable ones:

  • concepts (a way to write constraints for templates that lets us get way better error messages, overloading, and general template usability)
  • advanced concurrency libraries (e.g., thread pools and reader-writer locks)
  • garbage collection

Probably the biggest thing we did at this meeting was to choose time over scope: We decided that we can’t ship C++0x without concepts, but we can and will ship without some or all of the other two.

Concurrency: This was a pivotal meeting for concurrency. We voted a slew of concurrency extensions into the working draft at this meeting, as they happily all got to the ready point at the same time (see below for details):

  • memory model
  • atomics library
  • basic threads, locks, and condition variables

And we decided to essentially stop there; we still plan to add an asynchronous future<T> type in C++0x, but features like thread pools are being deferred until after this standard.

Garbage collection: For C++0x, we’re not going to add explicit support for garbage collection, and only intend to find ways to remove blocking issues like pointer hiding that make it difficult to add garbage collection in a C++ implementation. In particular, the scope of this feature is expected to be constrained as follows:

  • C++0x will include making some uses of disguised pointers undefined, and providing a small set of functions to exempt specific objects from this restriction and to designate pointer-free regions of memory (where these functions would have trivial implementations in a non-collected conforming implementation).
  • C++0x will not include explicit syntax or functions for garbage collection or related features such as finalization. These could well be considered again after C++0x ships.

What we voted into draft C++0x

Here is a list of the main features we voted into the C++0x working draft at this meeting, with links to the relevant papers to read for more information.

nullptr (N2431)

This is an extension from C++/CLI that allows explicitly writing nullptr to designate a null pointer, instead of using the unfortunately-overloaded literal 0 (including its macro spelling of NULL) which makes it hard to distinguish between an null and a zero integer. The proposal was written by myself and Bjarne.

Explicit conversion operators (N2437 and N2434)

You know how in C++ you can make converting constructors only fire when invoked explicitly?

class C {
public:
  C( int );
explicit C( string );
};

void f( C );

f( 1 ); // ok, implicit conversion from int to C
f( "xyzzy" ); // error, no implicit from string literal to C
f( C("xyzzy") ); // ok, explicit conversion to C

But C++ has two ways to write an implicit conversion — using a one-argument constructor as above to convert "from" some other type, or as a conversion operator "to" some other type as shown below, and we now allow explicit also on this second form:

class C {
public:
  operator int();
explicit operator string(); // <– the new feature
};

void f( int );
void g( string );

C c;
f( c ); // ok, implicit conversion from C to int
g( c ); // error, no implicit from C to string
g( string(c) ); // ok, explicit conversion to C

Now the feature is symmetric, which is cool. See paper N2434 for how this feature is being used within the C++ standard library itself.

Concurrency memory model (N2429)

As I wrote in "The Free Lunch Is Over", chip designers and compiler writers "are under so much pressure to deliver ever-faster CPUs that they’ll risk changing the meaning of your program, and possibly break it, in order to make it run faster." This only gets worse in the presence of multiple cores and processors.

A memory model is probably of the lowest-level treaty between programmers and would-be optimizers, and fundamental for any higher-level concurrency work. Quoting from my memory model paper: "A memory model describes (a) how memory reads and writes may be executed by a processor relative to their program order, and (b) how writes by one processor may become visible to other processors. Both aspects affect the valid optimizations that can be performed by compilers, physical processors, and caches, and therefore a key role of the memory model is to define the tradeoff between programmability (stronger guarantees for programmers) and performance (greater flexibility for reordering program memory operations)."

Atomic types (N2427)

Closely related to the memory model is the feature of atomic types that are safe to use concurrently without locks. In C++0x, they will be spelled "atomic<T>". Here’s a sample of how to use them for correct (yes, correct!) Double-Checked Locking in the implementation of a singleton Widget:

atomic<Widget*> Widget::pInstance = 0;

Widget* Widget::Instance() {
  if( pInstance == 0 ) { // 1: first check
    lock<mutex> hold( mutW ); // 2: acquire lock (crit sec enter)
    if( pInstance == 0 ) { // 3: second check
      pInstance = new Widget(); // 4: create and assign
    }
  } // 5: release lock
  return pInstance; // 6: return pointer
}

Threading library (N2447)

You might have noticed that the above example used a lock<mutex>. Those are now in the draft standard too. C++0x now includes support for threads, various flavors of mutexes and locks, and condition variables, along with s
ome other useful concurrency helpers like an efficient and portable std::call_once.

Some other approved features

  • N2170 "Universal Character Names in Literals"
  • N2442 "Raw and Unicode String Literals; Unified Proposal (Rev. 2)"
  • N2439 "Extending move semantics to *this (revised wording)"
  • N2071 "Iostream manipulators for convenient extraction and insertion of struct tm objects"
  • N2401 "Code Conversion Facets for the Standard C++ Library"
  • N2440 "Abandoning a Process"
  • N2436 "Small Allocator Fix-ups"
  • N2408 "Simple Numeric Access Revision 2"

Next Meetings

Here are the next meetings of the ISO C++ standards committee, with links to meeting information where available.

  • February 24 – March 1, 2008: Bellevue, Washington, USA (N2465)
  • June 8-14, 2008: Sophia Antipolis, France
  • September 14-20, 2008: San Francisco Bay area, California, USA (this is the anticipated date)

The meetings are public, and if you’re in the area please feel free to drop by.

Effective Concurrency: Apply Critical Sections Consistently

The latest Effective Concurrency column, "Apply Critical Sections Consistently", just went live on DDJ’s site, and will also appear in the print magazine. Here’s a teaser from the article’s intro:

The critical section is our One True Tool for guaranteeing mutual exclusion on mutable shared variables. …

[But critical sections] must be applied consistently, and with the intended meanings. A program must ensure that every use of a mutable shared object is properly protected using exactly one of these mechanisms at any given point in its lifetime. Chaos can erupt if code tries to avoid or invert these meanings (e.g., trying to abuse taking a lock or reading an atomic variable as a "critical section exit" operation; see Example 3), or tries to use inconsistent synchronization techniques at the same time.

I hope you enjoy it.
Next month’s article is already in post-production. It delves into what I think is a really interesting rule, both because it’s widely ignored and because it’s full of surprises: "Avoid Calling Unknown Code While Inside a Critical Section." I’ll blog here when it hits the web about a month from now.
Finally, here are links to previous Effective Concurrency columns (based on the dates they hit the web, not the magazine print issue dates):

Suggestion for “Required Viewing”: Machine Architecture Talk Online

Over the past 15 years or so that I’ve been giving software development talks, I’ve never had the chutzpah to suggest one of my own talks be considered "required viewing" for serious developers regardless of language or platform. But I’m going to suggest it now.

Two years ago, several highly experienced software architects I know (whose names many of you gentle readers would recognize) complained to me privately that "we shouldn’t let developers labor in ignorance" of how the enormous complexity of modern commodity computers affects our code’s performance and correctness. From that seed and others like it sprang this talk, now freely available online:

Section of a slide imageMachine Architecture: Things Your Programming Language Never Told You (117 minutes)

Video: Google video (recorded live on Sep 19, 2007)
Slides: PDF slides

Abstract: Programmers are routinely surprised at what simple code actually does and how expensive it can be, because so many of us are unaware of the increasing complexity of the machine on which the program actually runs. This talk examines the “real meanings” and “true costs” of the code we write and run especially on commodity and server systems, by delving into the performance effects of bandwidth vs. latency limitations, the ever-deepening memory hierarchy, the changing costs arising from the hardware concurrency explosion, memory model effects all the way from the compiler to the CPU to the chipset to the cache, and more — and what you can do about them.

Teaser: Would you be surprised to discover that only about 1% (one percent) of all the transistors on your modern CPU exist to ever compute anything? And that the other 99% (ninety-nine percent) of your CPU’s transistors are essentially dedicated to nothing but hiding memory latency? Those are round numbers, of course. But you get the idea…

So how do we cope with latency...?This is a talk I wish I’d been able to attend years ago. Consider making this required viewing for your team, including for new hires in software development roles. I guarantee it’ll be time well invested.

Here’s one suggestion: Roll your own training session. Arrange an extended lunch brownbag for your developers in a conference or training room, give each person a printout of the PDF slides to follow along and make notes, and display the video on the big screen. For extra benefit, leave a little time for group discussion, both during the session (the Pause feature is your friend) and afterwards ("how does this apply to our projects?"). Presto, instant training session — and you don’t even have to put your developers on a plane to attend a class somewhere, or arrange for a speaker to fly out to your site.

Finally, if you like the material and agree that it’s worthwhile, please help spread the word. For example, you can tell Slashdot by going to Submit Story. Or, if you prefer, you can tell Digg, or Reddit, or one of the others… you know the rest of the usual suspects.

Enjoy!

Omit Needless Words (in C++)

In C++ as in life, some people tend to use more words than they need to. As Strunk and White put it: Omit needless words.

Here’s an example I saw again yesterday in a recent peer-reviewed online magazine article showing how to write some C++ code to solve a particular problem. There’s nothing wrong with the code I’m going to show; but it tries to use a technique to "save typing" while accomplishing the opposite because of being unaware of a clever little C++ feature.

I’ll rearrange the particular code I saw to disguise the example (lots of people do this, and it would be unfair to target one person). The code started something like this:

template<
  typename T1,
  typename T2,
  typename T3,
  template <typename A1, typename A2 >class CreationPolicy,
  template <typename A1, typename A2 >class MemoryPolicy,
  template <typename A1, typename A2 >class SnarkPolicy,
  template <typename A1, typename A2 >class HumptyPolicy,
  typename SomeHelperType,
  typename StillAnotherType>
class MyClass
{

So far, so good; these words are needed for the purpose the author is trying to accomplish (it’s a heavy-duty template with enough type parameters to make Andrei proud).

Next comes the definition of MyClass, and some part of that may want to refer to "my type (this particular MyClass instantiation)." Now, it could spell it out as "MyClass< T1, T2, T3, CreationPolicy, MemoryPolicy, SnarkPolicy, HumptyPolicy, SomeHelperType, StillAnotherType >" — but, yuck, who wants to write all that every time?

In an attempt to avoid that verbosity, the class author next writes a convenience typedef:

  // Typedef — to save typing (?)
  typedef MyClass< T1, T2, T3, CreationPolicy, MemoryPolicy, SnarkPolicy, HumptyPolicy, SomeHelperType, StillAnotherType > ThisClass;

(Some of you may be about to interrupt our program with a "but why would he write that when he can just…" — right, but just wait for it.)

Then the code can go on to name "this particular MyClass instantiation" easily, say to pass "my type" to someone else:

public:
  static bool SomeFunc()
  {
    // instantiate some other template with "my type"
    vector<ThisClass> v;

    // call another static function of "my own type"
ThisClass::OtherFunc();

    … more code …
  }

There are two cases of needless words here.

First, the typedef doesn’t save any writing on the call to "ThisClass::OtherFunc()," because that call doesn’t need any qualification at all. It could simply have been written as "OtherFunc();" since that call is already inside MyClass.

Second, and more to the point, the typedef is completely unnecessary in the first place. Why? Because inside a class template, the simple name of the class template automatically implies "this instantiation" including the full parameter list. That is, in the above example there is no difference between typing

MyClass< T1, T2, T3, CreationPolicy, MemoryPolicy, SnarkPolicy, HumptyPolicy, SomeHelperType, StillAnotherType >

and just typing

MyClass

when inside the template.

So the typedef is completely unnecessary, and the original code:

  // Typedef — to save typing (?)
  typedef MyClass< T1, T2, T3, CreationPolicy, MemoryPolicy, SnarkPolicy, HumptyPolicy, SomeHelperType, StillAnotherType > ThisClass;

public:
  static bool SomeFunc()
  {
    // instantiate some other template with "my type"
    vector<ThisClass> v;

    // call another static function of "my own type"
ThisClass::OtherFunc();

    … more code …
  }

could have been written simply (and a bit more clearly) without any typedef, using just the class template’s name or nothing at all:

public:
  static bool SomeFunc()
  {
    // instantiate some other template with "my type"
    vector<MyClass> v;

    // call another static function of "my own type"
    OtherFunc();

    … more code …
  }

Ironically, the typedef not only didn’t save typing, but actually added a little.

Sometimes less is more. Where possible, use fewer words.

Webcast (via Intel) on September 25

On Tuesday September 25, I’ll be doing the kickoff webcast in Intel’s fall 2007 developer "webinar" series. It’ll be closely based on a talk I’ve given before on "Software and the Concurrency Revolution," but I’m going to update-and-trim material to try to leave more time for some interactive discussion. Here’s the info:

Webcast: "The Concurrency Revolution"

Date: Tuesday, September 25, 2007
Time: 9:00am U.S. Pacific Time (click here for more time zones) *
Length: 1 hour

Although driven by the industry-wide shift to multi-core hardware architectures, concurrency is primarily a software revolution. We are now seeing the initial stages of the next major change in software development, as over the next few years the software industry brings concurrency pervasively into mainstream software development, just as it has done in the past for objects, garbage collection, generics, and other technologies. Sutter summarizes the issues involved, gives an overview of the impact, and describes what to expect over the coming decade.

They’ll be doing a concurrency-related webcast every two weeks. The second talk in the fall series will be "Steps to Parallelism NOW" by James Reinders, author of the new book Threading Building Blocks about Intel’s cool (and recently open-sourced) C++ template library for concurrency. Should be good.

Footnotes

* I love timeanddate.com.

Trip Report: July 2007 ISO C++ Standards Meeting

The ISO C++ committee met in Toronto on July 15-20. Here’s a quick summary of what we did, and information about upcoming meetings.

Features voted into draft C++0x

enum class (N2347)

This is an extension from C++/CLI that allow writing enums that has a predictable size and underlying type, has its own scope (to the enumerators don’t get injected into the enclosing scope where they can conflict with similar names), and doesn’t have a nasty implicit conversion to int (or anything else). The proposal was written by David Miller, myself, and Bjarne.

Saving exceptions (N2179)

Added language and library support for saving an exception: This feature is useful in plain old sequential code if you want to catch and store an exception to be rethrown later. But it’ll be especially useful in concurrent code, so that we can catch an exception and transport it across threads (e.g., when waiting on an asynchronous function call).

constexpr (N2235 and N2349)

This feature permits generalized constant expressions — or, in English, being able to write your own compile-time constants that really act like compile-time constants. To illustrate, here’s one simple example from the paper:

constexpr int square(int x) { return x * x; }

What’s the point? Now if you call square() with an argument that is a compile-time constant, then the result of calling square() is still a compile-time constant, and you can use it anywhere you can use compile-time constants, such as specifying the length of an array:

float arr[ square(9) ]; // ok, array of length 81

Note that the above is not a C99 variable length array. It’s a normal fixed-size array, but we have more flexibility and convenience in specifying its size.

See the linked paper for more details and examples. And to see how this new language feature is immediately also being used in the C++ standard library, here’s your source: N2349, "Constant Expressions in the Standard Library — Revision 2."

decltype (N2343 and N2194; for discussion see N2115 and N1978)

The decltype feature lets you get the type of an expression, so that you can do things with the type (e.g., declare more variables of that type) without knowing in advance what the type is or how to spell it.

This is a great boon to generic programming with templates, and without the runtime cost of reflection in other languages. For example, say that you’re handed an iterator, and you want to know what type it refers to. Today, you need to ask the iterator for its value_type, which is a manual "traits" convention everyone is expected to follow when writing and using iterators:

template<typename Iter>
void f( Iter it ) {
Iter::value_type v = *it;
  …
}

With decltype, we could instead write:

template<typename Iter>
void f( Iter it ) {
decltype(*it) v = *it;
  …
}

Are you curious to see how decltype is being used in the C++0x standard library itself? Here’s the paper for you: N2194, "decltype for the C++0x Standard Library."

alignof (N2341)

A nice portable way to get aligned storage and inquire about the alignment requirements of types without performing system-dependent backflips.

=default and =delete (N2346 and N2292)

If you’ve ever wished you could control the four default special member functions (default constructor, copy constructor, copy assignment, and destructor) and especially how they’re inherited from base classes, this is the paper for you.

How could these be useful in the C++0x standard library itself do you ask? Here’s where to find the answer: N2292, "Standard Library Applications for Deleted Functions."

Some other approved features

  • N2340 "C99 Compatibility : _ _ func _ _ and predeclared identifiers (revision 2)"
  • N2342 "POD’s Revisited; Resolving Core Issue 568 (Revision 5)"
  • N2293 "Standard Library Applications for Explicit Conversion Operators"
  • N2348 "Wording for std::numeric_limits<T>::lowest()"
  • N2350 "Container insert/erase and iterator constness (Revision 1)"
  • N2351 "Improving shared_ptr for C++0x, Revision 2"
  • N2299 "Concatenating tuples" (except change the name of the four functions named concatenate to tuple_cat)
  • N2007 "PROPOSED LIBRARY ADDITIONS FOR CODE CONVERSION" (hey, don’t blame me for screaming, that’s the title…)
  • N2308 "Adding allocator support to std::function for C++0x" (except change the pass-by-value Allocator argument to pass-by-const-reference)
  • N2321 "Enhancing the time_get facet for POSIX® compatibility, Revision 2"
  • N2353 "A Specification for vector<bool>" into the C++0X Working Paper. (After all, no meeting would be complete without some discussion of vector<bool>…)

Next Meetings

Here are the next meetings of the ISO C++ standards committee, with links to meeting information where available.

  • October 1-6: Kona, Hawaii, USA [N2289]
  • February 24-29, 2008: Bellevue, Washington, USA
  • June 8-13, 2008: Sophia Antipolis, France

The meetings are public, and if you’re in the area please feel free to drop by.

Effective Concurrency: Use Critical Sections (Preferably Locks) to Eliminate Races

"In a race, no one can hear you scream."
That’s my tagline for the third Effective Concurrency column, "Use Critical Sections (Preferably Locks) to Eliminate Races." It just went live on DDJ’s site, and will also appear in the print magazine.
This article focuses on two main things:
  • The detailed facts of life about why most or all bets are off if you have a data race. You really, really, really don’t want to have any races in your code.
  • The commonality that unifies all synchronization constructs you’ve ever used or will use, from locking to lock-free styles to fences to transactional memory.

Here’s the article’s intro:

Everyone knows the basics of how to use locks:

  mut.lock(); // acquire lock on x
  … read/write x …
  mut.unlock(); // release lock on x

But why do locks, lock-free styles, and other synchronization techniques work at all, never mind interoperate well with each other and with aggressive optimizers that transform and reorder your program to make it run faster? Because every synchronization technique you’ve ever heard of must express, and every optimization that may ever be performed must respect and uphold, the common fundamental concept of a critical section. …

I hope you enjoy it.
Next month’s article is already in post-production. It follows directly from this one, and will be titled "Apply Critical Sections Consistently." I’ll blog here when it hits the web about a month from now.
Finally, here are links to previous Effective Concurrency columns (based on the dates they hit the web, not the magazine print issue dates):

Plug for the Astoria Seminar

If you enjoy C++, you should also enjoy the Astoria Seminar: Extraordinary C++ to be held on September 23-26, 2007 in Astoria, OR, USA. The event seems to have plenty of seats available, so you haven’t missed out (yet).

Disclaimer: I have no affiliation with the event, and I won’t be speaking or attending. But I feel confident recommending it on the strength of its speakers, if you are interested in any of the topics. Summarizing both:

  • Scott Meyers
    • An Overview of TR1
    • C++ Callbacks for C APIs
  • Andrei Alexandrescu
    • Choose your Poison: Exceptions or Error Codes?
    • Memory Allocation: Either Love It or Hate It. (Or Just Think It’s OK.)
  • Dave Abrahams
    • High Performance Generic Software Design (with Eric Niebler)
    • C++ Metaprogramming Concepts and Frameworks
  • Eric Niebler
    • High Performance Generic Software Design (with Dave Abrahams)
    • Domain-Specific Embedded Language Design with Boost.Proto
  • Walter Bright
    • Building Fast Lexers and Parsers
    • Performance Tuning Your Application

If any of the above topics gave a little tug at your heartstrings, or you want to rub shoulders with (and pick brains of) some really knowledgeable experts, I’m sure you won’t want to miss it. With Dave and Eric there (and Andrei, even though he claims to be speaking about other topics) it’s guaranteed to have a heavy dose of template- and metaprogramming-oriented material.

P.S.: Walter, thanks again for Empire! It was the cause of some happily wasted hours in my undergrad years.

More Visual C++ Q&A: A New Compiler Front-End

A few days ago, I blogged to answer to someone’s question about "where is Visual C++ going" by giving a number of resources and links, primarily about this year’s release now in public beta.

But their real question was about "where is Visual C++ going beyond VC++ 2008," and in particular whether we will continue to invest in the C++ compilers and native libraries, support new native and managed facilities like XAML via C++, and so on.

Now I can point to an answer that’s slightly more complete but also breaks some news: Our VP, Soma, blogged about this very topic this week. Here’s the key paragraph, some emphasis added:

This team will be significantly increasing support for native development tools. Central to this work is investigating ways to make C++ developers far more efficient in understanding, updating and validating the quality of large native code bases. In fact, the team is already working on a front-end rewrite that will allow for a vastly improved IntelliSense experience. This same work should pave the way for future enhancements such as refactoring and advanced source code analysis. In addition, the team intends to update the native libraries to simplify the development of rich-client user interfaces and access to underlying Windows platform innovation. The team will also work to provide “friction-free” interop between native & managed code through enhancements to C++/CLI and IJW.

From the comments section, Bill Dunlap from our VC++ group added some teasers, including (emphasis mine):

MFC – we are working on a huge update to MFC that should knock your socks off.  I can’t tell you too much right now, but this is closer than you might [think] <g>.

The Visual C++ "front-end rewrite" Soma mentions is indeed well under way, and one of the big benefits will be that it will make the compiler much more flexible (dare I say "agile"?) for us to work with and add features, including C++0x features. We’ll be able to say more about the new compiler and report progress in the coming year or two as it turns into real product you can see and touch.

[8:55am: updated to add Bill Dunlap’s comments and edit the last paragraph]