Feeds:
Posts
Comments

On Saturday June 9, the ISO C++ committee completed its summer meeting in beautiful Rapperswil, Switzerland, hosted with thanks by HSR Rapperswil, Zühlke, Netcetera, Bbv, SNV, Crealogix, Meeting C++, and BMW Car IT GmbH. We had some 140 people at the meeting, representing 11 national bodies. As usual, we met for six days Monday through Saturday, this time including all evenings.

Per our C++20 schedule, this was the second-last meeting for merging major language features into C++20. So we gave priority to the major proposals that might make C++20 or otherwise could make solid progress, and we deferred other proposals to be considered at a future meeting — not at all as a comment on the proposals, but just for lack of time. We expect to get to these soon once C++20 is well in hand.

Top news: Contracts adopted for C++20

Contracts (Gabriel Dos Reis, J. Daniel Garcia, John Lakos, Alisdair Meredith, Nathan Myers, Bjarne Stroustrup) was formally adopted for C++20.

Contracts allow preconditions, postconditions, and assertions to be expressed in code using a uniform syntax, with options to have different contract levels, custom violation handlers, and more.

Here are a few quick examples to get the flavor. Let’s start with perhaps the most familiar contract, assert:

void f() {
    int x = g();
    int y = h();
    [[assert: x+y > 0]]
}

“But wait,” someone might say, “C’s assert macro was good enough for my grandpappy, so shouldn’t it be good enough for me?” Never fear, you can still assert(x), but if you respell it as [[assert:x]] you get some benefits. For example:

  • You’re not relying on a macro (unlike C assert). Yes, this matters, because macros are outside the language and routinely cause problems when using language features. For example, this was demonstrated again just a few days ago on Twitter by Nico Josuttis (HT: Alisdair Meredith), who pointed out that assert(c==std::complex<float>{0,0}) does not compile; the reason is because macros don’t understand language commas, but [[assert: c==std::complex<float>{0,0}]] works just fine without any surprises.
  • You get to install your own violation handler and ship a release build with the option of turning on enforcement at run time.
  • You get to express audit to distinguish expensive checks to be run only when explicitly requested.
  • You get to express axiom contracts that are intended to never generate run-time code but are available to static analysis tools.
  • Finally, you will likely get better performance, because contracts should enable compilers to perform more optimizations, more easily, than expressing them using assertions.

But there’s more, because of course contracts are not just about assertions. They also include expects preconditions and ensures postconditions, which are part of the function declaration and so are visible at call sites:

double sqrt(double x) [[expects: x >= 0]];

void sort(vector<emp>& v) [[ensures audit: is_sorted(v)]];
    // could be expensive, check only when audit is requested

In addition to similar benefits as for assert, expects preconditions in particular deliver some enforcement benefits that are very desirable and difficult or impossible to get by hand:

  • Preconditions are usually enforced at the call site, which is what we want most of the time because a precondition violation always means a programming bug in the calling code.
  • But preconditions can also be enforced in the callee, which can sometimes be necessary for pragmatic reasons, such as when the function is invoked through an opaque function pointer.
  • Preconditions and postconditions that are known at the call site also give the optimizer more information to potentially make your code fast.

As a cheeky aside, if you noticed that I mentioned optimization several times, it’s for the usual reason: The simplest way to get C++ programmers to want a feature is to show that it can make their code faster, even if performance isn’t the only motivation or benefit.

Why contracts are a big deal, and related Rapperswil progress

In my opinion, contracts is the most impactful feature of C++20 so far, and arguably the most impactful feature we have added to C++ since C++11. That statement might surprise you, so let me elaborate why I think so.

Having first-class contracts support it is the first major “step 1” of reforming error handling in C++ and applying 30 years’ worth of learnings.

Step 2 is to (gradually) migrate std:: standard library precondition violations in particular from exceptions (or error codes) to contracts. The programming world now broadly recognizes that programming bugs (e.g., out-of-bounds access, null dereference, and in general all pre/post/assert-condition violations) cause a corrupted state that cannot be recovered from programmatically, and so they should never be reported to the calling code as exceptions or error codes that code could somehow handle. Over the past three meetings (Albuquerque through Rapperswil), the Library Evolution Working Group (LEWG) voted unanimously to pursue P0788R2 (Walter Brown) and relatedly in Rapperswil voted unanimously to pursue section 4.2 of P0709 (my paper), which includes pursuing a path of gradually migrating all standard library preconditions from exceptions toward contracts. (Note that in the near term, the idea is for implementations to be allowed, but not required, to use contracts. We are bringing the community forward gently here.)

Why is step 2 so important? Because it’s not just window dressing: Gradually switching precondition violations from exceptions to contracts promises to eventually remove a majority of all exceptions thrown by the standard library(!). This principle applies across programming languages; for examples, in Java and .NET some 90% of all exceptions are thrown for precondition violations (e.g., ArgumentNullException). Being able to eliminate a majority of all exceptions, which eventually enables many more functions to be noexcept, is a huge improvement for both correctness and performance:

  • Correctness: It eliminates a majority of the invisible control flow paths in our code. For example, over 20 years ago I wrote GotW #20 [Sutter 1997] that shows how today a 4-line function has 3 normal execution paths and 20 invisible exceptional execution paths; if we can eliminate a majority of the functions that can throw, we immediately remove a majority of the invisible possible execution paths in functions like this one, in all calling code.
  • Performance: More noexcept enables more optimization and faster code. (You knew that was coming, right?)

Once you change all preconditions (and postconditions and assertions) from exceptions to contracts, eliminating some of the largest categories of exceptions, one specific kind of exception dominates all others: bad_alloc. Which brings us to step 3…

Step 3 is to consider handling heap exhaustion (out-of-memory, OOM) differently from other errors. If in addition to not throwing on precondition violations we also do not throw on OOM, the vast majority of all C++ standard library functions can be noexcept. — Needless to say, this would be a huge change where we need to tread carefully and measure impact and high-fidelity compatibility in major real code bases, and we don’t want people to panic about it or think we’ve lost our minds: We are serious about bringing code forward gently after validating good adoptability and low impact long before this gets near an actual standard.

Nevertheless, we are also serious about improving this, and the fundamental change is simple and already fully supported in C++ today: In Rapperswil, LEWG also voted unanimously to pursue section 4.3 of P0709 (my paper) which proposes pursuing a path of gradually migrating all OOM from bad_alloc to new(nothrow)-like mechanisms. The initial contemplated step, definitely not for C++20, would be to change the default new_handler from throwing bad_alloc to calling terminate. That might sound like a big change, but it’s not, it’s already fully supported in C++ today because you can already change the new_handler to terminate today with a single line of code (std::set_new_handler([]{terminate();});), and this would just be changing the default and existing code that wants to keep the current behavior could still write simply the reverse single line of code (std::set_new_handler([]{throw std::bad_alloc();});) to get exactly the current behavior.

To repeat, this is a feature that will want a clear high-fidelity zero-breakage migration path, and we’re treating that compatibility seriously, even as we are also treating solving this problem seriously to modernize C++ error handling and move toward a mostly-noexcept world.

You can find a more detailed writeup in my new proposal P0709, particularly sections 1.1, 4.2, and 4.3. Again, P0709 is not for C++20, it is to illustrate a direction and potential path. The other parts of P0709 have not yet been reviewed by the full committee, so for now they should not be treated as anything more than a proposal, subject to much discussion and feedback over the coming several years.

Other new features approved for C++20

We adopted several other new features into the draft standard.

Feature test macros (Ville Voutilainen, Jonathan Wakely). This enables code to portably test whether a certain new C++ feature exists. “Why would I do that?” someone might ask. The primary and biggest benefit is they help your team to start to adopt new C++ features even before all your compilers support them; just write

#if /*new feature is present*/ // temporary
    nice clean modern code!    // <-- keep this long-term
#else                          // temporary
    do it the old way          // temporary
#endif                         // temporary

and eventually drop the #if test and the whole #else block as soon as all your compilers are up to date. This is so much better than today, where one of two things happens: (1) Teams often wait until all their compilers support a given new C++ feature before they start to use it, which slows down adopting the new features and getting their benefits at least on the compilers that do support it. Or, (2) teams roll their own nonstandard nonportable compiler-specific “approximate” feature tests (e.g., write their own macro for “I know this feature is available on version ## of MSVC and version ## of GCC” by hand).

We all agree we don’t like macros. However, we don’t yet have replacements for all uses of macros, including this one, and these standard macros are better than rolling your own nonstandard ones or, more likely, just not using new C++ features at all for a longer time.

Some experts still disagree, and we respect their views, but in my view these feature test macros are an important and pragmatic help to improve the speed of adoption of new standard C++ features.

Standard library concepts (Casey Carter, Eric Niebler). This is the first part of the Ranges TS to be merged into C++20 at an upcoming meeting, and contains the core concepts from the Ranges TS. It is also the first appearance of the concepts language feature in the standard library. Expect more to come for C++20 (see Ranges, below).

Class Types in Non-Type Template Parameters (Jeff Snyder, Louis Dionne). Yes, you can now have types other than int and char as non-type template parameters. For example, in addition to template<int Size>, you can now have things like template<fixed_string S> for a suitably defined class type. It turns out that this builds on the <=> spaceship comparison operator; and if you’re wondering why, it’s because we know the semantics of a defaulted <=> comparison, which is essential because the compiler has to perform comparisons to determine whether two template instantiations are the same.

Note: I did not have this benefit in mind at all when I proposed <=>. I think this is a great example where, when you let programmers express intent explicitly as with <=>, and provide useful defaults, you are inherently adding more reliable information to the source code and will reap additional benefits because you can now build on knowledge of that clear programmer intent.

explicit(bool) (Barry Revzin). This is conditional explicit, along the same lines as conditional noexcept. It lets library writers write explicit at a finer granularity, to turn off conversions where possible and feasible, without having to write two functions all the time.

Bit-casting object representations (JF Bastien). Header <bit> now lets you bit_cast. “But wait,” someone may be thinking, “don’t we already have reinterpret_cast?” Yes we do, and this is still a reinterpreting operation, but bit_cast has less unsafety and some additional flexibility: it ensures the sizes of the From and To types match, guarantees that they are both actually trivially copyable, and as a bonus makes the operation constexpr wherever possible.

Speaking of constexpr bit_cast, here are some more items in the “constexpr all the things!” department:

Other progress and decisions

Reflection TS is feature-complete: The Reflection TS was declared feature-complete and is being sent out for its main comment ballot over the summer. Note again that the TS’s current template metaprogramming-based syntax is just a placeholder; the feedback being requested is on the core “guts” of the design, and the committee already knows it intends to replace the surface syntax with a simpler programming model that uses ordinary compile-time code and not <>-style metaprogramming.

Parallelism TS2 is done: The second Parallelism TS is done! We completed ballot comment resolution, and approved the final TS for publication. This TS includes more execution policies, an exception_list type to communicate multiple parallel exceptions, and more parallel algorithms including wavefront, reductions, inductions, parallel for, and more. It also includes task_block support to enable writing custom parallel algorithms.

Graphics (io2d) is deferred: Many thanks to Michael McLaughlin especially, and to Guy Davidson, Michael Kazakov, and David Ludwig for their assistance with the design, specification, and implementation of this cross-platform library. This is a project that has been worked on for several years, and for the past two years has been primarily responding to committee tweak requests; unfortunately, although the committee requested a series of updates to the proposal that have been applied, at this meeting the committee decided that it does not have interest to pursue further work on graphics in any form at this time after all. However, the io2d project will continue, and be available on package managers (Conan, vcpkg), and we expect a renewed proposal in the medium term; in the meantime, watch Guy Davidson’s blog for news and updates.

Also, LEWG adopted P0921r2 as a statement of their direction for future C++ standard library evolution compatibility guarantees.

Updates on other major proposals

Here are other major items in progress. You’ll notice that the first six (6!) of them mention expectations for our next meeting this November in San Diego. Not all of those items will make C++20 in San Diego, but people are going to try. It’s not surprising that San Diego is going to be a busy meeting, though; that was expected, because it’s the last meeting to merge major features into C++20, and deadlines are famously motivational. — Just do not expect all of the following to make C++20, and I’m listing them in rough order starting with the most likely to make it in.

(very likely for C++20) Ranges: In my previous trip report I mentioned that the core concepts from the Ranges TS were expected to make C++20, but the rest of the Ranges TS would be “C++20 or C++23.” Since then we have made faster than expected progress, and it now looks like Ranges is “likely” to make C++20 in the next meeting or two. For those interested in details, in addition to all of the Ranges TS, also paper P0789 on Range Adaptors and Utilities have now progressed to detailed wording review and are targeting C++20. In sum, to quote Eric Niebler: “If you liked the Ranges TS, you’ll love C++20.”

(likely for C++20) Concepts: “convenience” notation for constrained templates: We already added the concepts core feature to C++20, and at this meeting we had further discussions on adding a convenience syntax to write constrained templates without resorting to the low-level “requires” keyword. The two major active proposals that received discussion were from Bjarne Stroustrup and from me. The good news is that the Evolution Working Group (EWG) liked both, which means that for the first time we have a proposal based on the TS syntax (Bjarne’s preference) that could get consensus to be approved!

The key people are continuing to work to come up with a merged proposal that might be adoptable for C++20 in November in San Diego, and I’m pleased to report that as of this post-meeting mailing we for the first time have a unified proposal that lists most of the previous authors of papers in this area as coauthors, you can find it here: P1141R0: “Yet another approach for constrained declarations.” I’m guardedly optimistic that we may have a winner here; we’ll know in San Diego. (I sometimes delay my trip report until the post-meeting mailing is available so that everyone can see the latest papers, and knowing that this new paper was coming was one reason I delayed this report.)

(maybe for C++20) Coroutines: EWG considered an alternative, then decided to go forward with the TS approach. That came up for full committee vote but fell just short and was not adopted for C++20; the proposers will continue to work on improving consensus over the summer by addressing remaining concerns and we expect coroutines to be proposed again for C++20 at our November meeting in San Diego.

Modules: For the first time, the committee saw a merged approach that both major proposers said satisfies their requirements; that announcement was met by applause in the room. The merged proposal aims to combine the “best of” the Modules TS and the Atom alternative proposal, and that direction was approved by EWG. EWG did not approve the poll to incorporate a subset of it into C++20 at this meeting; it is not yet clear whether part of the proposal can make C++20 but we are going to have an extra two-day meeting in September to help make progress and we expect it to be proposed again for C++20 at our November meeting in San Diego.

Executors: This is still not expected to be part of C++20, but key people have not given up and are trying to make it happen, and one never can tell. We are going to hold an extra two-day meeting in September to help make progress on Executors, and expect to have a lively discussion about options to merge all or parts of it into C++20 in November in San Diego.

Networking: This is pretty much ready except that it depends on Executors. Soon after Executors are ready for C++20, Networking is ready to slide in right behind it.

Clearly San Diego is going to be a busy meeting. But before then we have two extra design meetings on modules and executors to help improve their chances of progress; those will be co-located with CppCon in September, to take place near the CppCon site on the days just before the conference begins. On top of that, there will also be an extra library wording issues meeting in the Chicago area in August… all in all, it’ll be a full summer and fall before we even get to San Diego.

Additionally, SG12 had productive discussions about undefined behavior (including with participation from our sister ISO working group WG23, Programming Language Vulnerabilities), and SG15 had a second exploratory evening session focusing on package managers for C++.

What’s next

Here is a cheat-sheet summary of our current expectations for some of the major pieces of work. Note that, as always, this is an estimate only. The bolded parts are the major changes from last time, including that Ranges as a whole is looking very likely for C++20.

wg21-schedule-2018-06

And here is an updated snapshot of where we are on the timeline for C++20 and the TSes that are completed, in flight, or expected to begin:

wg21-timeline-2018-06

Thank you again to the approximately 140 experts who attended this meeting, and the many more who participate in standardization through their national bodies! Have a good spring… we look forward now to our next “extra” meetings in September (Bellevue, WA, USA) and the next regular WG21 meeting in November (San Diego, CA, USA).

[Edited to add C++20 schedule at end]

On Saturday March 17, the ISO C++ committee completed its winter meeting in Jacksonville, Florida, USA, hosted with thanks by the Standard C++ Foundation and Perennial. We had some 140 people at the meeting, representing 8 national bodies. As usual, we met for six days Monday through Saturday, including all evenings.

A special highlight was on Thursday evening (the only non-officially-working evening) when Bjarne Stroustrup personally hosted the entire committee for a celebratory dinner to share the 2018 Charles Stark Draper Prize, the U.S.’s top engineering honor, which this year was awarded for a programming language for only the second time in its history. Although the prize was awarded to Bjarne personally, he made it clear that he considered this an award for the whole C++ community, without whom C++ would never have been successful, and so he hosted the dinner for the committee as a representative proxy for the entire worldwide C++ community. — So to all C++ programmers and contributors who are reading this: Thank you, from Bjarne and from us, for your support, and consider yourselves part of this year’s Draper Prize.

The following are some highlights of what we achieved this week. You can find a brief summary of ISO procedures here. The main things to note are:

  • “IS” means “international standard.” In our case, it’s the core C++ standard itself. Think of this as “trunk.”
  • “TS” means “technical specification,” a document separate from the main standard where we can gain experience with new features before putting them into the IS. We have several of these, summarized on the status page. Think of these as “beta branches.”

Leading up to this meeting

As I reported in my previous trip report for the fall meeting (Albuquerque 2017), last time we almost completed addressing the comments received from national bodies in the Modules comment ballot that ran last summer. The rest were addressed in a series of teleconferences between meetings, and the Modules TS was finalized and shipped to ISO at the end of January.

One of the highlights in the pre-meeting mailing was “Direction for ISO C++” (Beman Dawes, Howard Hinnant, Bjarne Stroustrup, Daveed Vandevoorde, Michael Wong). Although non-binding, it’s the first set of recommendations from our recently created advisory Direction Group, a small subgroup of respected long-time participants that currently consists of those paper authors and is chaired this year by Bjarne Stroustrup.

Features adopted for C++20

We adopted several new features into the draft standard.

[[no_unique_address]] (Richard Smith). You know the empty base optimization (EBO)? If you do, can you remember the (probably many) times you’ve artificially made another class a base of your class, instead of just a data member, just so you could get EBO? And, every time that happened, you wished C++ had the empty member optimization (let’s call it “EMO”)? In C++20, it does, and you opt in via [[no_unique_address]]. Here’s an example from the paper:

template<typename Key, typename Value,
         typename Hash, typename Pred, typename Allocator>
class hash_map {
  [[no_unique_address]] Hash hasher;         // EMOji
  [[no_unique_address]] Pred pred;           // EMOji
  [[no_unique_address]] Allocator alloc;     // EMOji
  Bucket *buckets;
  // ...
public:
  // ...
};

[[likely]] and [[unlikely]] (Clay Trychta). (The link is to R2 of the paper, which contains more description. The R4 version is the one that was adopted.) Many compilers already allow you to “hint” whether a branch is likely or unlikely to be true, which can help optimizations. This standardizes that. Here’s an example from the paper:

if (foo()) [[unlikely]] return false;
if (bar()) [[unlikely]] return false;
baz();

Major disclaimer: This feature comes with the same warning label as the existing compiler extensions, which is “measure, measure, measure!” Compilers already know which branches are likely, usually better than you do (especially with profile-guided optimization, aka PGO). A major reason to use this feature is not actually to optimize (though it can help if you don’t have PGO), but to control which path gets optimized for other reasons. For example, for some code it is essential to make the uncommon path faster so that it is faster when you do hit it — and in such cases you would actually use this attribute in the inverted sense, so please also write a comment nearby to document that intent otherwise some hapless reader (more than likely your future self) will be temporarily confused.

Extending <chrono> to calendars and time zones (Howard Hinnant, Tomasz Kamiński). This is a much-loved (and huger-than-you-think) library addition that will help a lot of users, and really exercises modern C++ features like user-defined literals.

span: Bounds-safe views for sequences of objects (Neil MacIntosh, Stephan T. Lavavej). This one comes directly from the C++ Core Guidelines’ Guideline Support Library (GSL), and is intended to be a replacement especially for unsafe C-style (pointer,length) parameter pairs. We expect to be used pervasively as a vocabulary type for function parameters in particular.

Cleanup adopted for C++20

We also made some improvements to existing features.

“Down with typename!” (Nina Ranns, Daveed Vandevoorde). Are you tired of writing typename redundantly in places where the compiler should know only a type was possible? So were the proposal authors. Now typename is required in fewer places.

Lambda capture initializers can now expand variadic parameter packs (Barry Revzin). An example, taken from the paper:

template<class F, class... Args>
auto delay_invoke(F f, Args... args) {
    return [f=std::move(f), ...args=std::move(args)]() -> decltype(auto) {
        return std::invoke(f, args...);
    };
}

The now-allowed expansion is the one in the third line.

Consistent begin/end for range-for (Ville Voutilainen). The range-based for loop is already customizable, and can handle ranges that have both member rng.begin()/rng.end() functions or ones that have non-member begin(rng)/end(rng) functions. But what if it relies on the non-member functions, but happens to also have one member named either begin or end (such as, say, end in ios_base)? That’s now legal, we ignore the one-off member and use the non-member pair. Here’s an example from the paper that is not legal in C++17 but now works in C++20:

struct X : std::stringstream { /*...*/ };

std::istream_iterator<char> begin(X& x)
  { return std::istream_iterator<char>(x); }

std::istream_iterator<char> end(X& x)
  { return std::istream_iterator<char>(); }

int main() {
    X x;
    for (auto&& i : x) {   // works in C++20
      // ...
    }
}

Interesting tidbit: This is one of those “new functionality” features created by removing wording in the standard, namely removing a restriction. The entire wording change was to change “either (or both) finds” to “both find” in one place.

Structured bindings can access accessible members (Timur Doumler). In C++17, you could use structured bindings to bind to class members as long as they were public. But what if you’re inside a member or friend of the class? Shouldn’t you be able to use structured bindings on members, which are visible (i.e., accessible) to you even if they aren’t public to everyone, just like we can do any other normal thing with those members? In C++17 that didn’t work, but it was an oversight and now we can do that:

class X {
    int i;
    int j;
public:
    friend void f();
};

void f() {
    X x;
    auto [myi, myj] = x;   // now ok
}

We also adopted some other fixes, including:

… and a few more including a couple of small extensions to coroutines and networking. Note that those two TSes were already published, and are not yet merged into the C++ draft standard, but we are still maintaining those experimental TS “branches” with fixes and updates, so that those will be done and ready once we are ready to merge those TS branches into the C++ “trunk” project itself.

Other major full committee approvals

We approved Parallelism TS 2 to be extended with the (huge) extensions in Data-parallel vector types and operations (Matthias Kretz) and declared it feature-complete: It is now being sent out for its main ISO comment ballot.

We also decided to officially open a Reflection TS work item, which means that the committee as a whole is taking ownership of the proposal and intends to progress it as a TS. The initial content is from the paper “Static reflection” (Matúš Chochlík, Axel Naumann, David Sankel) but everyone should understand that the surface syntax will change. The primary point of the TS is in the underlying “engine” and functionality, and the intention is to replace the placeholder template-metaprogramming-like reflexpr syntax with an object-like model that looks like “more constexpr code” — regular C++ code that is able to be run at compile time.

Language/library evolution subgroup approvals

Here is a list of proposals that achieved Evolution or Library Evolution working group (EWG or LEWG) design approval. This means that the subgroup responsible for approving the design has done so (sometimes provisionally, with a few “revision is expected” notes below), and the next step is that they now enter wording review in the Core or Library working group (CWG or LWG), and are slated to be proposed for formal adoption in C++20 at a future meeting. Thanks to Olivier Giroux, Ville Voutilainen, Titus Winters for their notes that contributed to this summary.

For contracts, EWG discussed a clarification to what the result of observable side-effects in contract pre/post-conditions is, and the guidance is that it’s undefined behavior.

For reflection and related facilities, EWG approved some papers that are significant milestones for compile-time programming:

EWG also approved:

We also decided to pursue putting in writing two statements about how we evolve C++:

  • EWG decided to pursue turning “C++ Stability, Velocity, and Deployment Plans” (Titus Winters) into a Standing Document, with the expectation is that the document will be revised and reviewed again. Titus Winters will be the main author, and Gabriel Dos Reis, Bjarne Stroustrup, and Mike Spertus will assist.
  • EWG also supports turning “Standard library compatibility promises” (Titus Winters) into a Standing Document, and to add the promises also to the standard’s own Library Introduction clause. Titus Winters will be the main author, with help from Ashley Hedberg, Nevin Liber, Bjarne Stroustrup, James Dennett, Walter E. Brown, Gor Nishanov, Alisdair Meredith, Mike Spertus, Robert Steagall and Daveed Vandevoorde.

We decided to launch a systematic effort to drive out the remaining uses of macros by providing replacements for those uses. We requested an analysis paper listing all the remaining use cases for macros are, a description of the status of the non-macro solutions for those problems, and possible solutions. This paper will be led by Ville Voutilainen, assisted by Bjarne Stroustrup, Gabriel Dos Reis, James Dennett, and Vittorio Romeo.

Somewhat stunningly (to me), we decided to pursue some cleanup to the C fundamental types that would be a breaking change to certain kinds of C and C++17 code. It came up via the discussion of “Towards consistency between <=> and other comparison operators” (Richard Smith), which observed that when we added <=> to C++20, in <=> only we deliberately decided not to repeat the well-known issues that we did not want to perpetuate with C’s two-way comparisons for fundamental types (e.g., signed-unsigned comparison surprises like -1 < 0u giving the “wrong” answer)… which naturally meant that we now have inconsistencies between the preexisting two-way comparison operators and the shiny new three-way <=> operator. When faced with this, the subgroup discovered that we had a consensus in the room that enough really was enough, and we decided to seriously investigate doing some housecleaning and fix those things even though that would include breaking changes to (mostly ill-behaved) C and C++17 code. For example, we are now on a path to pursue deprecating or outright removing the ability to compare two unrelated enumerations (which is just plain suspicious code), and to require -1 < 0u to give the mathematically correct answer even when in the worst case that means generating two comparison machine instructions instead of just one (any code that does such ill-advised things would change from being a correctness problem into “just” a one-extra-instruction performance problem). — We have made no decisions about actually doing this or the ship vehicle for such changes, which likely would have to be rolled out in stages via deprecation followed by removel, and we expect more data to be gathered before Rapperswil regarding how much code could be affected. But as far as I can recall, this is the most breaking-change cleanup to C’s fundamental types that we have ever been willing to seriously consider.

LEWG approved Standard library concepts (Casey Carter). This is the first part of the Ranges TS to be on track for merging into C++20 at an upcoming meeting, and contains the core concepts from the Ranges TS. It is also the first appearance of the concepts language feature in the standard library.

Other progress

Also for concepts, at this meeting EWG approved pursuing a direction based on my paper “Concepts in-place syntax” (Herb Sutter) to have a shorthand syntax for declaring constrained templates.

At this meeting, we considered further improvements to the modules design, including a renewed proposal focusing on a bridge to help existing header-based code move toward a modules-enabled world. By the end of the meeting, the main participants had hammered out a plan to, over the next few meetings:

  • move a core set of modules functionality into C++20 that is “clean” and uncompromised by legacy concerns; and
  • concurrently update the remaining modules TS with features specific to transitioning header-based code to modules, which might include support for macros.

There’s a lot of work remaining, but we’ll know in the next few meetings how the objectives are progressing.

After several years of incubation, executors are now making strong progress and are on track to become a TS in the C++20 timeframe. (Let me explicitly say “thread pools” for the benefit of those who are Ctrl-F’ing to find out how C++ intends to support modern thread pools such as in Windows 10 and Grand Central Dispatch. You’re now in the right place: Modern thread pool support is coming as part of executors.)

Note that there is a dependency on executors before we can merge the networking TS and the future.then feature in the concurrency TS into the C++ draft standard, which means that all of those features are likely to be merged early in the C++23 cycle rather than in C++20.

We are going to try to ship coroutines in C++20.

We are opening a new work item for Library Fundamentals TS3, the third batch of library additions, even as we will soon be starting to fold in material from the recently-published Library Fundamentals TS2 into C++20.

SG15 (Tooling) (Titus Winters) had its first meeting, and there is a shared belief that we need to take concrete steps toward enabling better support for tools for two things in particular: modules, and C++ library package managers. That coincided very nicely with the 2018-02 isocpp.org survey, where on the open-ended question 10, the #1 write-in answer was to request “dependencies / package manager” (15% of all write-ins mentioned that). Clearly there is interest in this area, and it will be interesting to see how this develops into proposals over the coming meetings.

We also created a new study group SG16 (Unicode) with Tom Honermann as the SG chair.

What’s next

Whew! Here is a cheat-sheet summary of our current expectations for some of the major pieces of work that are not already in draft C++20. Note that this is an estimate only.

cpp11147020 - 201803

And here is an updated snapshot of where we are on the timeline for C++20 and the TSes that are completed, in flight, or expected to begin:

wg21-timeline-2018-03.png

Finally, here is the schedule for the C++20 cycle approved by unanimous consent at this meeting:

wg21-schedule-2018-03

Thank you again to the approximately 140 experts who attended this meeting, and the many more who participate in standardization through their national bodies! Have a good spring… we look forward now to our next meetings in June (Rapperswil, Switzerland) and November (San Diego, CA, USA).

A few minutes ago, the ISO C++ committee completed its fall meeting in Albuquerque, New Mexico, USA, hosted with our thanks by Sandia National Laboratories. We had some 140 people at the meeting, representing 10 national bodies. As usual, we met for six days Monday through Saturday, including several evenings.

The following are some highlights of what we achieved this week. You can find a brief summary of ISO procedures here. The main things to note are:

  • “IS” means “international standard.” In our case, it’s the core C++ standard itself. Think of this as “trunk.”
  • “TS” means “technical specification,” a document separate from the main standard where we can gain experience with new features before putting them into the IS. We have several of these, summarized on the status page. Think of these as “beta branches.”

Modules TS ballot comments: Almost done

A primary goal of the meeting was to address the comments received from national bodies in the Modules TS’s comment ballot that ran this summer. We managed to address them all in one meeting, as well as deal with most of the specification wording issues discovered in the process of responding to the national comments; we discovered one or two areas where the TS wording did not quite match the approved design intent, and so the plan is to finish addressing those and to approve the Modules TS for publication in between meetings via a teleconference, rather than wait for our next face to face meeting in March.

It will be great to get the TS published, and continue getting experience with implementations now in progress, at various stages, in all of Visual C++, Clang, and gcc as we let the ink dry and hammer out some remaining design issues, before starting to consider adopting modules into the C++ draft standard itself. I do not know whether modules will make the feature cutoff for C++20, but a lot of people are working hard to maximize the chances… we’ll know in another 12-18 months when we reach the C++20 feature cutoff.

Second meeting for C++20

This was also the second meeting where we could vote changes into Draft C++20. And we did!

Here are some of the features that were added to C++20 at this meeting. Note: These links currently find the most recent pre-meeting papers and so may not reflect the exact wording adopted at the meeting, but the links will light up to the post-meeting versions of the papers that were actually adopted as soon as those are available in the post-meeting mailing about three weeks from now.

Range-based for statements with initializer (Thomas Köppe). In C++17, we already allowed initialization of if-scoped and switch-scoped variables, just like the ordinary for loop has already had for years. Today, we added the same for the range-based for loop, which gives the same benefit: It enables and encourages locally scoped variables without the programmer having to introduce a scope manually. To take an example from the paper, in C++17 we might write the following to get a variable thing that exists just as long as is needed for the for loop, which avoids a bad pitfall (do you see why the “WRONG” comment is wrong? it might work depending on what f() returns, or it might be undefined behavior):

{
  T thing = f();
  for (auto& x : thing.items()) {
    // Note: “for (auto& x : f().items())” is WRONG
    mutate(&x);
    log(x);
  }
}

and now in draft C++20 we can write the recommended local scoping directly with less ceremony of { } and indenting, and follow the C++ Core Guidelines scoping recommendations now also for range-for, as just:

for (T thing = f(); auto& x : thing.items()) {
  mutate(&x);
  log(x);
}

Bit-casting object representations (JF Bastien). This proposal gives a way to copy the bits of an object in a consistent and simple manner. It adds the new header <bit>, and provides bit_cast for trivially-copyable “bag-o-bits” objects, to easily copy the bits of any such object to another of the same size (the types need not be the same). Note: Yes, we already have memcpy, but bit_cast is safer and also can run at compile time.

Lots of other cleanup. We did various smaller features and cleanup, sometimes to fix bugs, sometimes to improve consistency and generality, and sometimes to make the language a little simpler to use.

  • Example of bug fixes: Draft C++20 sets forth more precisely where constexpr functions are defined (core issue 1581).
  • Examples of consistency and generality: Draft C++20 now supports concepts requires-clauses in more places including lambdas (P0857, Thomas Köppe). Also, stateless (non-capturing) lambdas are now default constructible and assignable, which makes them more convenient to create and use (P0624, Louis Dionne).

Operator <=>, aka “spaceship” (myself). Beyond those, my personal favorite is that the committee adopted my own proposal for the <=> “spaceship” three-way comparison operator (language wording; library wording). Many thanks to all the proposal’s reviewers, including all the authors of previous proposals in this area and especially Jens Maurer and Walter Brown for standardese wording help. This will greatly simplify how to write comparisons.

For example, in C++17 if we want to have a case-insensitive string type CIString that supports comparisons between two CIStrings and between a CIString and a C-style char* string, we would have to write something like the following 18 nonmember friend functions:

class CIString {
  string s;
public:
  // ...

  friend bool operator==(const CIString& a, const CIString& b) { return ci_compare(a.s.c_str(), b.s.c_str()) != 0; }
  friend bool operator< (const CIString& a, const CIString& b) { return ci_compare(a.s.c_str(), b.s.c_str()) <  0; }
  friend bool operator!=(const CIString& a, const CIString& b) { return !(a == b); }
  friend bool operator> (const CIString& a, const CIString& b) { return b < a; }
  friend bool operator>=(const CIString& a, const CIString& b) { return !(a < b); }
  friend bool operator<=(const CIString& a, const CIString& b) { return !(b < a); }

  friend bool operator==(const CIString& a, const char* b) { return ci_compare(a.s.c_str(), b) != 0; }
  friend bool operator< (const CIString& a, const char* b) { return ci_compare(a.s.c_str(), b) <  0; }
  friend bool operator!=(const CIString& a, const char* b) { return !(a == b); }
  friend bool operator> (const CIString& a, const char* b) { return b < a; }
  friend bool operator>=(const CIString& a, const char* b) { return !(a < b); }
  friend bool operator<=(const CIString& a, const char* b) { return !(b < a); }

  friend bool operator==(const char* a, const CIString& b) { return ci_compare(a, b.s.c_str()) != 0; }
  friend bool operator< (const char* a, const CIString& b) { return ci_compare(a, b.s.c_str()) <  0; }
  friend bool operator!=(const char* a, const CIString& b) { return !(a == b); }
  friend bool operator> (const char* a, const CIString& b) { return b < a; }
  friend bool operator>=(const char* a, const CIString& b) { return !(a < b); }
  friend bool operator<=(const char* a, const CIString& b) { return !(b < a); }
};

With this proposal, the class’s comparisons could instead be implemented as just two ordinary member functions (vs. the 18 that had to be nonmember friends above):

class CIString {
   string s;
public:
   // ...

  std::weak_ordering operator<=>(const CIString& b) const
      { return ci_compare(s.c_str(), b.s.c_str()); }
  std::weak_ordering operator<=>(const char* b) const
      { return ci_compare(s.c_str(), b); }
};

and objects of this type can still be used just as flexibly and efficiently as if the class author had written all of the above two-way operators in the first version, because now the compiler will rewrite expressions like s1<s2 to (s1<=>s2 < 0) for you automatically. Additionally, unlike the first attempt, this version also documents in code that the kind of ordering being returned is a weak ordering, not a strong (total) ordering. I’m a fan of writing less code to say more, and to say it more accurately. Please see the paper linked above for more details.

In related news, at this meeting the Library Evolution subgroup also began considering David Stone’s proposal to apply operator<=> to the standard library, and it got a warm reception and is expected to progress over the coming meetings. If it succeeds, we hope it may possibly let us get a small reduction in the size of the standard library specification as well as a result. Additionally, at this meeting we discovered that having <=> opens an unanticipated door for language evolution: Because the default operator<=> is guaranteed to be memberwise, so that we can know those are its semantics at compile time, a brand-new proposal by Jeff Snyder can leverage it to solve the remaining problems that before prevented us from using non-built-in types as non-type template parameters; we’ll see more of his proposal at our next meeting. That’s a good sign of a feature that is generally useful in the language beyond just its intended use cases.

We also approved extensions to the standard library:

atomic<shared_ptr<T>> (myself, Alisdair Meredith): This was originally my proposal and I got it into the Concurrency TS; many thanks to Alisdair Meredith who got it the rest of the way into draft C++20 over the past two meetings. There are changes since it appeared in the Concurrency TS, including to make it use the name I originally proposed (and not “atomic_shared_ptr<T>”).

Here’s more that we got at this meeting on the standard library side. If you notice “constexpr” being mentioned a few times above already, and some more below, that’s no accident; in Library subgroup chair Marshall Clow’s words, “the future of constexpr is bright.” The following other progress also includes more work on enabling features to work at compile time, including most of the rest of the standard algorithms:

(Aside: At this meeting, the Evolution subgroup also provisionally allowed constexpr (compile-time) new, vector, and string. Stop a moment, and think about what that means. — That is not yet in C++20, but it’s on its way and could be approved for draft C++20 in another few meetings… and if this all reminds you of the CppCon “constexpr all the things!” talk title, you’re exactly right.)

And much more. Thanks to all those proposal authors and the issues list proposed wording contributors and all their helpers, without which this team effort would not succeed meeting after meeting. None of the proposers could get it done without all the contributions of many people who work tirelessly all the way from design feedback to detailed wording review, usually for no public glory, and we appreciate their indispensable help. For any of the above papers you happen to have interest to click on, please be sure to look also at the Acknowledgments section, many of which are quite extensive and deservedly so.

We also continued incubating other work. In particular, the Reflection study group had presentations, and gave direction and feedback, on static reflection for functions, as well as design feedback on Section 5 of my metaclasses paper. The Undefined/Unspecified Behavior study group met for two days with our sister committee WG23 (Vulnerabilities) co-located at the same venue to start work on a C++-specific document about programming language vulnerabilities and guidance, in conjunction with (and already providing new feedback for) the C++ Core Guidelines.

What’s next

Here’s an updated snapshot of our status:

wg21-timeline-2017-11

Thank you again to the 140 experts in Albuquerque this week, and the many more who participate in standardization through their national bodies! Have a good winter… we look forward now to our next meetings in March (Jacksonville, Florida, USA) and June (Rapperswil, Switzerland).

I was also interviewed recently by Anastasia Kazakova for the CLion blog, and that interview is now live:

Toward a more powerful and simpler C++ with Herb Sutter

Topics include:

  • Concepts and modules (and coroutines) as the true hot topics right now
  • How my work on metaclasses was motivated and developed
  • Obligatory aside on operator<=> which grew out of the same work
  • Good and bad ways to learn from other languages and their experience
  • What are the next questions to be answered for metaclasses proposal
  • What has been the committee’s feedback so far
  • How can we expect to see reflection, compile-time code, injection, and metaclasses both progress in committee and get built into production compilers
  • How toolable are today’s C++11/14/17 features, and what about toolability for metaclasses

The Qt World Summit videos were just posted, including my talk which was a condensed (40-minute) version of my CppCon 2017 metaclasses talk with some small tweaks for a Qt-specific audience.

Here it is below:

Last week I did an interview by email with InfoQ. It just went live:

C++17 is Here: Interview with Herb Sutter

Topics include:

  • What parts of C++17 should developers get most excited about?
  • Why didn’t concepts make it into C++17?
  • What will be the major focus areas for C++20?
  • What do you find interesting or inspiring about new languages like Rust, Swift, and Go?
  • Any new books coming? What’s your main focus today?

In my household, iOS 7 was sickening — literally. When it came out with its flashy parallax home screen and (IMO too often gratuitous) motion effects, my wife was one of the many people it immediately made motion-sick. After 30 years of loyally loving Apple products, my wife almost had to dump her iPhone. It was so bad that it’s the only time in my life we’ve written an email directly to the CEO of a company; we didn’t expect Tim Cook to reply, but we hope it helped raise awareness, and fortunately (likely not because of us, even slightly, but very happily), Settings > Accessibility > Reduce Motion came long just in time, and iOS was usable again.

Now iOS 11 has done it again. Just unlocking the phone is motion sickness-inducing because the lock screen now flies upward out of the way on every unlock, even if you have Settings > Accessibility > Reduce Motion enabled. (What happened to “No means no”?) And there appears to be more motion again around the lock and home screens and when just opening and switching the built-in apps, so now my wife is feeling ill again in the first 10 seconds of every phone session since she upgraded, and we’re having Android conversations again. And we don’t want Android. Really.

iOS is supposed to be the most usable phone OS, but you can’t use something if you can’t look at it.

 

Open letter to Apple designers:

We love your work because you love usability, and especially in recent years you love accessibility. Please, get back to those roots.

What is it with all the motion lately? You are known for minimalism, and that “design is how it works.” Design is not about “how it looks” eye candy — gratuitous motion is not a feature, yet it seems that in recent releases you have had a temptation to go for “cool” effects that do not improve usability. Please resist. I hope we can all agree that parallax on the home screen has insignificant effect on improving usability; I turned it off as soon as I could even though I’m not motion sickness-prone (seriously, this aspect of iOS reminds me unflatteringly of Clippy bouncing around). And yes, I realize that you likely made the iOS 11 lock screen swerve careen glide up on unlock in order to teach that “hey look! see? it lives up there just off the top of the screen” so that we remember that we can now pull it down anytime to get it back — yes, we know, we learned it once the first time, could we please now not have to live with that animation forever? Please stop with the careening screen elements. You know what Nancy Reagan would say about the animations: Just Say No.

Minimal-change proposed resolution: Please, just make all the new motion effects, including the fly-away lock screen, respect Settings > Accessibility > Reduce Motion. (Translation: “No means no.” We said No already. Please respect it.) Or give us a new way to turn it off. Please.

We want to keep using iOS, but we can’t use it if we can’t look at it. We don’t want to have to switch to Android to get a phone we can use. Don’t let Android win on usability, which is supposed to be your home turf — and don’t let Android win on accessibility, which is so important these days and which I know is important to you.

Thank you for your consideration and help.

 

If you know of a workaround that can disable these awful motion effects, please mention it in the comments. (But please don’t suggest jailbreaking, which isn’t an option for us because that would be license-violating and security-compromising.)