Trip Report: C++ Standards Meeting in Lenexa, May 2015

Summary / TL;DR

 

Project What’s in it? Status
C++14 C++14 Published!
C++17 Various minor features. More substantial features under consideration include default comparisons and operator . On track for 2017
Networking TS Sockets library based on Boost.ASIO In late stages of design review
Filesystems TS Standard filesystem interface Published!
Library Fundamentals TS I optional, any, string_view, and more Voted out for publication!
Library Fundamentals TS II source code information capture, array_view, and more Expected 2016 or 2017
Array Extensions TS Old proposals (arrays of runtime bound (ARBs) and dynarray) abandoned. New direction being explored: a magic type that acts like an ARB and can be used as a local variable only.
Parallelism TS Parallel versions of STL algorithms Voted out for publication!
Concurrency TS improvements to future, latchesand barriers, atomic smart pointers Voted out for balloting by national standards bodies
Transactional Memory TS transaction support Voted out for publication!
Concepts (“Lite”) TS constrained templates In process of addressing comments from national standards bodies. Publication expected late 2015.
Reflection Code introspection and (later) reification mechanisms Still in the design stage, no ETA
Graphics 2D drawing API Standard wording expected to be ready for review at the next meeting.
Modules A component system to supersede the textual header file inclusion model Microsoft and Clang continuing to iterate on their implementations and converge on a design. Ship vehicle (C++17 or a TS) uncertain.

Introduction

Last week I attended a meeting of the ISO C++ Standards Committee in Lenexa, Kansas. This was the first committee meeting in 2015; you can find my reports on 2014’s meetings here (February, Issaquah), here (June 2014, Rapperswil), and here (November, Urbana-Champaign). These reports, particularly the Urbana one, provide useful context for this post.

The focus of this meeting was iterating on the various ambitious proposals in progress, and beginning to form an idea of which of them will be ready for C++17. In addition, several of the Technical Specifications (TS) in flight have reached their final stages in the committee, while work continues on others.

C++14

C++14 was officially published as an Internal Standard by ISO in December 2014. Its timely publication is evidence that the committee’s plan for adopting a three-year publication cycle post-C++11 has, thus far, been successful.

C++17

What Will Make It In?

When the committee originally announced, shortly after C++11 was published, the schedule for the next two standard revisions, C++14 was described as a “minor revision”, and C++17, a “major” one.

A few things have happened since then:

  • C++14 ended up being not so minor, with fairly substantial features like generic lambdas and variable templates making it in.
  • For features not going through the TS process, there’s no intrinsic reason the three years between C++14 and C++17 would be any more or less productive for the committee than the three years between C++11 and C++14.
  • For features going through the TS process, that process has in some cases been taking somewhat longer than initially envisioned, and thus it’s not clear whether they will be published in time – and particularly, if there will be enough time after their publication to get more implementation and use experience with them – to merge them into C++17. I would say the following TS’s stand a chance of being merged into C++17:
    • Filesystems, which has already been published
    • Library Fundamentals I, Parallelism, and Transactional Memory, which were voted for publication at this meeting
    • Concepts, which is expected to be voted for publication in a post-meeting telecon, or at the next meeting (in October in Kona, Hawaii) at the latest

    However, I don’t think any of these mergers is a given. For example, there is some opposition to merging the Filesystems TS into the Standard in its current form on the basis that its design isn’t a good fit for certain less common varieties of filesystems. Concepts also has some pending design issues that may be revisited prior to a merger. In all cases, feedback from implementors and users will be key and will likely decide the TS’s fate.

As a result, I think it’s likely that C++17 will end up being approximately as “major” or “minor” of a revision as C++14 was.

Modules making it into C++17 is less likely. Due to the significance of the change that they bring to the language, there have been calls – including by the authors of one of the two current modules implementations – to pursue the feature initially as a Technical Specification, giving the design the opportunity to be hardened via implementation and use experience. If this avenue is pursued, the timing effectively rules out such a TS being published and merged into the IS by C++17. That said, from a user’s perspective, I don’t think this is any reason to despair: the feature is still likely to become available to users in the 2017 timeframe, even if it’s in the form of a TS.

Reflection is still very much in the design stage, and SG 7 indicated a preference for a TS as the initial ship vehicle. C++17 is practically out of the question.

(I talk about modules and reflection in more detail below, for those interested.)

That said, there are features not going through the TS process which are expected to be in C++17.

What Has Made It In?

My Urbana report lists the language and library features that have made it into C++17 as of the last meeting.

No new language features were voted into C++17 this meeting, in the sense of standard wording for them being merged into the C++17 working draft (a small, language lawyer-ish change, making exception specifications part of the type system came close, but was deferred to Kona due to some concerns brought up during the closing plenary session). However, there are numerous language features in the design or wording review stages that are expected to be voted into C++17 in upcoming meetings; I talk about these in the “Evolution Working Group” section below.

There were some small library features voted into C++17 at this meeting:

Technical Specifications

Procedural changes

There has been a change to ISO’s procedure for publishing a Techincal Specification since the last meeting. The process used to involve two rounds of balloting by national standards bodies, called PDTS (Preliminary Draft TS) and DTS (Draft TS). Recently, the DTS round has been dropped, leaving just the PDTS round, and making for a more agile TS publication process.

Crossed the finish line!

As a result of this procedural change, some TS’s which had successfully finished their PDTS ballots became eligible to be voted out for publication at this meeting, and after addressing PDTS ballot comments, vote them out we did! Library Fundamentals I, Transactional Memory, and Parallelism I have all been sent to ISO for official publication, which should happen within a few months.

A couple of other TS’s haven’t quite crossed the finish line yet, but are very close.

Concepts

The Concepts TS garnered a rich and opinionated collection of PDTS ballot comments. Among them were your usual editorial and wording-level technical comments, but also some design-level comments which were brought before the Evolution Working Group (EWG) for consideration.

It’s rare for the committee to make design changes to a TS or Standard at such a late stage in the publication cycle, and indeed most design-level comments were deferred (meaning, they will not be addressed in this version of the TS, but they could be revisited in a future version, or if the TS comes up for merging into the Standard). One comment, however, which was essentially a request for a (small) feature, was approved. The feature will allow using a concept name as type name in a variable declaration:

ConceptName var = expression;

The semantics is that the type of var is deduced from the type of expression (much like with auto), but the code is ill-formed if the deduced type does not satisfy the concept.

I was mildly surprised that EWG was willing to approve this addition at this late stage, but pleasantly so: I think this feature is very useful. To top off the good news, Andrew Sutton (the primary author of the Concepts TS), who couldn’t make it to the meeting itself, reported only two days later that he added support this feature in his GCC-based Concepts TS implementation! (Implementation experience is immensely valuable for guiding the committee’s decisions, because issues with a proposal feature often come up during implementation.)

As a result of this new addition, and a multitude of wording-level comments, the Core Working Group (CWG) didn’t have time to prepare final wording for the Concepts TS by the end of the meeting, so it couldn’t be voted out for publication just yet. Rather, CWG plans to hold a post-meeting teleconference to (hopefully) complete the final wording, after which the options are to hold a committee-wide teleconference to vote it out for publication, or to wait until Kona to vote on it.

Either way, the Concepts TS is practically at the brink of completion! Very exciting.

There’s also good news on the implementation side: GCC front-end developer Jason Merrill says Andrew’s Concepts implementation is expected to merge into mainline GCC within a month or so. Meanwhile, IBM, who have switched to using clang as the front-end for their newer products, announced their intention to kick off a clang-based implementation.

Concurrency I

Good progress here, too: the first Concurrency TS was sent out for its PDTS ballot! Assuming a successful ballot, it should be ready to be voted for publication in Kona.

Evolution Working Group

As usual, I spent most of the meeting in the Evolution Working Group, which does design review for proposed language features. EWG once again had a full plate of proposals to look at.

Recapping from previous posts, the outcome of an EWG design review is one of the following:

  • Approved. The proposal is approved without design changes. They are sent on to the Core Working Group (CWG), which revises them at the wording level, and then puts them in front of the committee at large to be voted into whatever IS or TS they are targeting.
  • Further Work. The proposal’s direction is promising, but it is either not fleshed out well enough, or there are specific concerns with one or more design points. The author is encouraged to come back with a modified proposal that is more fleshed out and/or addresses the stated concerns.
  • Rejected. The proposal is unlikely to be accepted even with design changes.

Here’s how this meeting’s proposals fared:

Accepted:

  • A proposal to make emplace_back() and similar play nice with aggregate types. Note that this is a library proposal for which EWG input was solicited, so it was sent to the Library Working Group (LWG) rather than CWG.
  • Microsoft’s resumable functions (a.k.a. coroutines) proposal. More about this in the “Coroutines” section below.
  • A proposal to make exception specifications part of the type system. This resolves a long-standing issue where exception specifications sort-of contribute to a function’s type but not quite, and as such their handling in various contexts (passing template arguments, conversions between function pointer types, and others) requires special rules.
  • A minor change to the semantics of inheriting constructors, which makes the semantics more intuitive and consistent with inheritance of other members.
  • A proposal for inline variables, which are basically static storage duration variables (either at namespace scope, or static data members) whose definition can appear inline, and can be defined in a header. This can already be accomplished using a static variable defined locally in an inline function, this proposal just exposes that semantics under a more straightforward syntax. The proposal had some minority opposition (on the basis that it reuses the keyword inline for a purpose somewhat unrelated to its existing use, and that it encourages the use of static storage duration variables to begin with), but otherwise had fairly strong support and was accepted.
  • A proposal to remove the keyword register, but reserve it for future use.

Further work:

  • A tweak to the folding expressions feature added last meeting, which would restrict the set of operators for which a unary fold with an empty parameter pack is valid. Support for this hinges on defining an identity element for the affected operators, but it’s not clear that such a notion is sensible in the presence of operator overloading. For example, consider the following function:
        template <typename... Strings>
        auto concatenate(Strings... strings)
        {
          return strings + ...;
        }
    

    With the current rules, when this function is called with 1 or more strings, it returns the concatenation of its arguments (because strings overload operator + to do concatenation), but when called with no arguments, it returns the integer 0, because that’s defined as the identity element for the addition operator.

    The proposal in question would make it ill-formed to call this function with no arguments; if the author wants that to work, their recourse is to change the unary fold to the binary fold strings + ... + "".

    There was consensus that addition, multiplication, and bitwise operators should be treated this way, but others were more contentious. For example, it was argued that for the logical operators && and ||, you shouldn’t be overloading them to return things that aren’t bool anyways, so the identities true and false remain appropriate.

    A particularly interesting case is the comma operator, for which the specified identity is void(). Comma folds are expected to be common as a technique to emulate statement folding, as in the following example:

        template <typename... Functions>
        auto call_all_functions(Functions... functions)
        {
          functions() , ...;  // expands to function1() , function2() , functionN();
        }
    

    On the one hand, it would be a shame to make people write functions , ... , void() every time they want to do this, and the comma operator generally shouldn’t be overloaded anyways, so keeping the void() identity should be reasonable. On the other hand, if people want to do statement folding, perhaps the language should allow them to do that directly, rather than relying on the comma operator to emulate it with expression folding.

    As there was no consensus on the precise course of action, the matter was referred for further work.

  • The latest modules proposal from the Microsoft folks. More about this in the “Modules” section below.
  • The alternative coroutines proposal that I presented (the author being absent). More about this in the “Coroutines” section below.
  • Contract programming. Two main proposals were discussed, with different flavours. One of them provided an assert-like facility, to be used inside function bodies, primarily for the purpose of runtime checking. The other (there was also a third very similar to it) proposed a syntax for declaring preconditions, postconditions, and invariants for a function in its interface (i.e. in its declaration), primarily for the purpose of static analysis and enabling compiler optimizations. There was consensus that both sets of goals, and both places for writing contracts (interfaces and implementations) are desirable, but there was some debate about whether the proposals should be considered as orthogonal and allowed to proceed independently, or whether the authors should collaborate and come up with a unified proposal that satisfies both use cases. In the end, the direction was to strive for a unified proposal.
  • Default comparisons. Bjarne presented the latest version of his proposal for automatically generating comparison operators for class types. The main features of the proposal are (1) that it’s opt-out, meaning you get the operators by default but you can declare them as = delete if you don’t want them; and (2) it’s carefully designed to avoid breaking existing code as follows: for any comparison operator call site, if name lookup under current rules finds a user-declared operator, it will continue finding that operator under the new rules, rather than using any auto-generated one. The proposal had strong concensus, which was a (welcome) surprise after the lack of consensus on earlier versions (and other proposals in the area) at the previous two meetings. It came close to being approved and sent to CWG, but some details of the semantics remained to be hashed out, so Bjarne was asked to return with an updated proposal in Kona.
    There was another proposal related to comparisons, which pointed out that we are currently waving our hands about matters such as different types of equality and different types of order (total, weak, partial, etc.). To rectify this, it proposed using named functions (e.g. one for each kind for order) instead of operators for comparisons. The feedback was that such machinery is useful to have, but we also want reasonable defaults which are spelt == and <, and as such, the proposed set of named functions can be developed independently of Bjarne’s proposal.
  • A proposal to extend aggregate initialization to be allowed for types with base classes in cases where the base classes are default-constructible. EWG’s feedback was to revise the proposal to also address the use case of providing values to initialize the base classes with in cases where they are not default-constructible.
  • Unified call syntax. This proposal, by Bjarne, seeks to unify the member (x.f(y)) and non-member (f(x, y)) call syntaxes by allowing functions of either kind to be invoked by syntax of either kind. The approach is to have the x.f(y) syntax look for member functions first, and fall back to looking for non-member functions only if the member lookup yields no results; conversely, f(x, y) would look for non-member functions first, and fall back to a member lookup. The resulting semantics are asymmetric (they don’t make x.f(y) and f(x, y) completely interchangeable), but fully backwards compatible. (This design was one of several alternatives Bjarne presented at the previous meeting, and it seemed to have the greatest chance for gaining consensus, primarily due to its backwards compatibility.)

    Beyond aesthetics (“I prefer my function calls to look this way”) and tooling reasons (“member call syntax gives me IntelliSense”), the primary motivation for this feature is facilitating generic proramming, which is expected to become more popular than ever with Concepts. When defining requirements on a template parameter type, either informally in today’s C++ or explicitly with Concepts, you currently have to choose whether the operations on the type are expressed as member of non-member functions. Either choice constrains users of your template: if you choose member functions, they can’t adapt third-party types that they can’t modify to model your concept; if you choose non-member functions, they will likely have to provide a lot of non-member adapters for types that would otherwise automatically model your concept. You could choose to allow either one (this is what C++11 does with the “range” concept used in the range-based for loop: the required operation of getting an iterator to the first element of the range can be spelt either begin(range) or range.begin()), but then your call sites become very unreadable because you need a lot of template/SFINAE magic to express “call X if it exists, otherwise call Y”. A unified call syntax would allow template implementers to use whichever call syntax they like, while users of the template can use either member functions or non-member functions to model the concepts, as they desire / are able to. (C++0x Concepts had a feature called “concept maps” which solved this problem by acting as a bridge between the operations in a concept definition (which is what generic code would use) and the actual operations on a type modelling the concept. However, concept maps were removed from later Concepts designs because they proved very tricky to specify and implement.)

    Unfortunately, this is a very risky change to make to the language. While the proposal itself doesn’t break any existing code, new code that takes advantage of the proposal (that is, code that invokes a non-member function via a member call syntax, or vice versa) is considerably more prone to breakage. For example, adding a new member function to a class can easily break user code which was calling a non-member function of that name via the member function syntax; this breakage can manifest as a compiler error, or as a silent behaviour change, depending on the situation.

    A lot of the finer points of the proposed semantics remain to be nailed down as well. How does the fallback mechanism work – is it activated only if the initial lookup doesn’t find any results, or also if it finds results but they’re all, say, SFINAE’d out? What is the interaction with two-phase name lookup? What happens when the member call syntax is used on an incomplete type?

    EWG was very divided on this proposal; consensus seemed fairly far off. Some people suggested changes to the proposal that would allay some of their concerns with it; one of them was to have classes opt-in to unified call syntax, another to restrict the set of non-member functions that can be found via a member call syntax to those found by ADL. Bjarne said that he intends to continue iterating on the idea.

  • A proposal for overloading operator dot. This would allow creating “smart references”, much as the ability to overload operator -> gives us smart pointers, as well enable many other patterns that take advantage of interface composition. The proposal was generally very well-received; one feature that was somewhat controversial was the ability to declare multiple “overloads” of operator dot that return different types, with the effect of bringing the interfaces of both types into the scope of the declaring type (much how multiple inheritance from the two types would). The author (also Bjarne) was asked to come back with standard wording.
  • A proposal to allow template argument deduction for constructors. The idea here is to avoid having to define factory functions for templated types, such as make_pair(), for the sole purpose of not having to explicitly write out the template argument types in a constructor call of the form pair<T, U>(t, u); the proposal would allow simply pair(t, u).This proposal has been on the table for a while, but it’s been plagued by the problem that for a lot of classes, deduction based on existing constructors wouldn’t work. For example, if a class container<T> has a constructor that takes arguments of type container<T>::iterator, that type is a non-deduced context, so T could not be deduced from a constructor call of the form container(begin, end). The latest version addresses this by allowing class authors to optionally define “canonical factory functions” that define how the class’ template parameters are deduced from constructor arguments. Here’s how one might look like (the syntax is hypothetical):
    template <typename Iter>
    container(Iter a, Iter b) 
        -> container<typename iterator_traits<Iter>::value_type>;

    This basically says “if container is constructed from two iterators, the class’ template parameter is the value type of those iterators”. The question of where to place such a declaration came up; EWG favoured placing it at namespace scope, so as to allow third parties to provide them if desired.

    Another point that was brought up was that a constructor call of the form classname(arguments) where classname is a template class, already has a meaning inside the scope of classname: there, classname without any template arguments means “the current instantiation” (this is called injected class names in standard terminology). The proposal needs to specify whether such a constructor would change meaning (i.e. deduction would be performed instead) or not. The consensus was to try to perform deduction, and fall back to the current instantiation if that fails; this would technically be a breaking change, but the hope is that the scope of any breakage would be minor.

    Overall, the proposal had strong support and is expected to move forward.

  • A proposal to allow a template to have a non-type template parameter whose type is deduced. EWG expressed preference to the syntax template <auto x> and encouraged the author to continue iterating on the idea.
  • A restricted form of static_if; the restrictions are that (1) it can only be used at local scope, (2) each branch of it forms a scope of its own, and (3) non-dependent constructs need to be well-formed in both branches. The proposal was well-received, and the author will continue working on it. It was noted that the Concepts TS doesn’t currently allow evaluating a concept outside a requires-expression, so something like static_if (ConceptName<T>) wouldn’t necessarily work, but hopefully that restriction will be lifted in the near future.
  • Extending static_assert to allow taking for the error message not just a string literal, but any constant expression that can be converted to a string literal. The idea is to allow performing compile-time string formatting to obtain the error message.
  • noexcept(auto), which basically means “deduce the noexcept-ness of this function from the noexcept-ness of the functions it calls. Like return type deduction, this requires the body of the function being available in each translation unit that uses the function. It was brought up that, together with the proposal for making exception specifications part of the type system, this would mean that modifying the function’s body could change the function’s type (again similarly to return type deduction), but people weren’t overly concerned about that.

Rejected:

  • A proposal for allowing return type deduction for explicitly-defaulted and -deleted special member functions. This was rejected because the group realized that it would introduce a footgun: a copy or move assignment operator with an auto return type would return by value!
  • No-op constructors and destructors, which are basically a language hack that would allow certain library optimizations; a previous attempt at enabling said optimizations, destructive move, was presented at the previous meeting. EWG’s feedback was much the same as last time: though it’s dressed differently, the proposal is still an attempt to mess with the language’s lifetime rules, which people are extremely wary of doing. The proposal as written will not move forward, but Chandler Carruth (Google’s lead clang developer) had some ideas about how to allow the desired optimizations by other means, and will discuss them with the author.
  • A proposal for relaxing the rules for forming an array type declarator to allow omitting a dimension anywhere; this would allow forming types such as int[][3][][7], though not instantiating them. The author was seeking to write a multi-dimensional array class where each dimension could be determined statically or dynamically, and use a type of this form as a template parameter and interpret it as a description for which dimensions were static. EWG didn’t find this motivation compelling (the information can be conveyed by other means, such as Array<int, Dimensions<0, 3, 0, 7>>) and was generally wary of adding to the set of types that can be formed but not instantiated (an existing example of such a type is a function type whose return type is a function type).
  • A proposal for generalized dynamic assumptions. EWG liked the use cases, but felt it would make more sense as part of a unified contracts proposal than a stand-alone feature, as contracts also need a syntax to express assumptions.
  • Allowing goto in constexpr functions. The intent here was to plug gratuitous holes between what can be done in a constant expression, and what can be done in regular code. EWG liked the motivation, but preferred to see it together with proposals that plug other holes, such as using lambdas and virtual functions in constant expressions. At least one of those (lambdas) is expected to be proposed in Kona. (Bjarne jokingly wondered whether some day people would be proposing launching threads in a constexpr function.)
  • Delayed evaluation parameters, which is a proposal for evaluating function arguments in a lazy rather than eager fashion (i.e. only evaluating them when their value is needed inside the function, not before calling the function). EWG was intrigued by the idea, but the proposal wasn’t nearly fleshed out enough to be considered as a conrete proposal. Interested people are encouraged to continue exploring the design space.
  • A revised proposal to allow arrays of runtime bound as data members wasn’t looked at specifically, but its presence on the agenda prompted a broader discussion about the Arrays TS, which I talk about in the “Arrays TS” section below.

Modules

There are two groups currently working on modules: Microsoft, in their compiler, and Google, in clang (extending Apple’s clang modules implementation for C and Objective-C, to C++). Microsoft has a draft proposal based on their design; Google hasn’t submitted a proposal based on their design yet.

The two designs differ slightly in philosophy. Microsoft’s design feels like what modules might have looked like if they were part of C++ from the beginning. It’s clean, and promises to be a good fit for new code written in a modular fashion. Google’s design, on the other hand, is geared towards making it possible to incrementally modularize large existing codebases without requiring a significant refactoring or other major changes (at least in the absence of egregiously non-modular design patterns). In other words, Microsoft’s design is more idealistic and pure, and Google’s is more practical.

Most notably, Microsoft’s design essentially requires modularizing a codebase from the bottom-up. For example, if a component of your program uses the C++ standard library, then modularizing that component requires first modularizing the C++ standard library; if the C++ standard library in turn uses the C standard library, then that too must be modularized (which is particularly unfortunate, for two reasons: (1) C standard library headers tend to be notoriously difficult to modularize due to their use of the preprocessor, and (2) they need to remain consumable by non-C++ code). Google’s design, on the other hand, specifically allows modular code to include non-modular code, so you could modularize your program component without having to modularize the C++ standard library.

To be sure, this feature of Google’s design introduces significant implementation complexity. (In my Rapperswil report, I reported that Google claimed their modules implementation was complete. I now understand what they meant was their implementation of a subset of the design that did not include this feature was complete.) I don’t have a deep understanding of the technical issues involved, but from what I’ve gathered, the difficulty is taking multiple copies of entities defined by the same non-modular code included in different modules and “merging” them to view them as a single entity.

There are other differences between the two designs, too. For example, Google’s allows exporting macros from a module, while Microsoft’s does not. Google’s design also supports cyclic dependencies between module interfaces, resolved by forward-declaring an entity from one module in the interface of the other; Microsoft’s proposal has no such support.

EWG spent half a day (and folks from the two groups additional time offline) discussing and trying to reconcile these design differences. The outcome was relatively hopeful about reaching convergence. The Microsoft folks conceded that some abilities, such as forward declaring entities from another module, are necessary. The Google folks conceded that some abilities geared towards making modules work with existing codebases, such as allowing the export of macros, don’t have to be supported directly by the language (they could be handled by compiler flags and such). The two groups agreed to produce a combined design paper for Kona.

In terms of a ship vehicle, the Google folks characterized modules as “the feature with the single greatest implementation impact so far”, and expressed a strong preference for going through a Technical Specification; this route would effectively rule out modules being in C++17, though as a TS the feature would still likely be available to users in the 2017 timeframe. That said, no official decision has been made yet regarding a ship vehicle.

Coroutines

You may recall from my Urbana report that the outcome of the coroutines discussion there was that two flavours of coroutines, stackful and stackless (see the report for an explanation of the distinction) were sufficiently different and both sufficiently motivated by use cases that they deserved to be developed as independent proposals, with a small minority favouring trying to unify them.

Since Urbana there has been progress in all of these directions, with four papers coming back for consideration at this meeting: an iteration on the stackless proposal, an iteration on the stackful proposal, and two different attempts to unify the two approaches. EWG looked at two of these.

The stackless proposal, called “resumable functions” and championed by Microsoft, is the most mature one. It has already gone through numerous rounds of review in SG 1 (the Concurency Study Group), and is close to the stage where standard wording for it can be written. Its discussion in EWG mostly concerned details such as what to call the traits and functions involved in the proposal (there was no consensus to change from the current coroutine_ prefix), whether deducing that a function is resumable by the presence of await expressions in its body without annotating the declaration with a keyword like resumable is implementable (implementers agreed that it was as long as return statements in such a function were spelt differently), and whether yield is a reasonable keyword to standardize (consensus was that it was not, and so we’re going to get keywords prefixed with co- such as coyield and coreturn instead). Ultimately, the proposal author was given the go-ahead to write standard wording and go to CWG.

The other proposal EWG looked at was one of the attempts to unify stackful and stackless coroutines, called resumable expressions. I presented this paper because the author, Chris Kohlhoff, couldn’t make it to the meeting and I was somewhat familiar with the topic as a result of corresponding with him. Unlike resumable functions, this proposal was in the early design stage. The premise was that you could “have your cake and eat it too” by leveraging the compiler’s ability to analyze your code to avoid annotating calls to resumable functions at every level the way you have to do with await (the weakness of stackless coroutines compared to stackful), while still only requiring the allocation of as much memory as you need (the advantage of stackless over stackful). The problem was that the compiler analysis can’t see past translation unit boundaries, thus still requiring annotations there. There were also concerns about the performance cross-translation unit calls compared to resumable functions; Chris was convinced that it was no slower than resumable functions, but unfortunately I didn’t have a sufficiently good comparative understanding of the implementation models to successfully argue this point. The final opinion on the proposal was divided: some people saw imagination in it, and wanted to see it developed further; others didn’t appreciate the fact that a competing proposal to resumable functions was brought up at such a late stage, risking the standardization of the latter.

You might ask how it even makes sense for resumable functions to be sent to CWG without resumable expressions being categorically rejected. The answer is twofold; first, it’s looking like resumable functions will target a Technical Specification rather than C++17, which means there’s room for competing proposals to be developed in parallel. Second, even if it were targeting the standard, it’s conceivable that multiple kinds of coroutines can co-exist in the language (certainly in Urbana the consensus was the stackful and stackless coroutines should coexist). In any case, Chris plans to attend the Kona meeting and presumably present and updated version of the resumable expressions proposal.

The other two papers (the stackful one and a different unification attempt) were only looked at briefly by SG 1, as the author (same person for both) wasn’t present.

Arrays TS

The Array TS, which contains a language feature called “arrays of runtime bound” (ARBs) that’s essentially a toned-down version of C’s variable-length arrays (VLAs), and a library class dynarray for wrapping such a thing into a container interface, has been in limbo for the past year, as attempts to implement dynarray ran into difficulties, and proposals trying to replace it with something implementable got shot down one after the other.

At this meeting, EWG reviewed the status quo and addressed the question of what will happen to the Arrays TS going forward.

The status quo is this:

  • Many people want simple stack arrays. Emphasis on simple (no “making it a member of a class”) and stack (no “it might be on the stack or it might be on the heap” business.)
  • Some people want to be able to wrap such things into a class interface, so it knows its size, and doesn’t automatically decay to a pointer.
  • Some people additionally want to be able to copy this class and make it a member of other classes.
    • Implementation attempts have essentially demonstrated that this latter thing is impossible.

Given this state of affairs, the features currently in the Arrays TS are not going to be accepted in their current form; EWG recommended stripping the TS of its current contents, and waiting for a workable proposal to come along.

A promising direction for such a workable proposal is to have a “magic type” that acts like an ARB but knows its size and does not decay to a pointer (the implementable features that people wanted from a class wrapper). The type in question could only used for a local variable, and the underlying ARB itself wouldn’t be exposed. Several people expressed an interest in collaborating on a proposal in this direction.

Libary / Library Evolution Working Groups

With all the exciting action in EWG, I didn’t have much of a chance to follow progress on the library side in any detail, but here’s what I’ve gathered during the plenary sessions.

Note that I listed the library features accepted into C++17 at this meeting in the “C++17” section above.

The following proposals were accepted into the second Library Fundamentals TS:

The following proposals failed to gain consensus:

  • A proposal to include certain special math functions which have been standardized independently, into C++17. The primary objection was the cost to implementors for what was perceived by some as a relatively niche user base.
  • Multidimensional bounds, offset and array_view was proposed for acceptance into Library Fundamentals II, but was voted down over issues that still remain to be addressed.

The list of proposals still under review is very long, but here are some highlights:

  • Eric Niebler’s suggested design for customization points was reviewed favourably; Eric was encouraged to experiment more with the idea and come back.
  • A proposal for nothrow-swappable traits was reviewed favourably, and the author was given guidance to put forward all of the traits mentioned in the paper.
  • A lot of time was spent reviewing a proposal for a variant class; as one of the few “vocabulary types” still missing from the standard library, this is considered very important. A lot of the discussion centred around whether variant should have an empty state, and if not, how to deal with the scenario where during assignment, the copy constructor of the right-hand side object throws. boost::variant deals with this by incurring heap allocation, which is widely considered undesirable. I believe the prevailing consensus was to have an empty state, but only allow it to arise in this exceptional situation (pun intended), and make accessing the variant in its empty state (other than assigning a new value to it) undefined behaviour; this way, ordinary code isn’t burdened with having to worry about or check for the empty state.
  • LEWG is continuing to review the Networking TS based on Boost.ASIO.

Ranges

I split out ranges into its own section because I believe it deserves special mention.

As I described in my Urbana report, Eric Niebler came to that meeting with a detailed and well fleshed-out design for ranges in the standard library. It was reviewed very favourably, and Eric was asked to “conceptify” it – meaning express the concepts defined by the proposal using the features of the Concepts TS – and develop the result into a TS. This TS would form part of an “STLv2” refresh of the standard library which wouldn’t be subject to strict backwards-compatibility constraints with the current standard library.

Eric did not delay in doing so: he came back in Lenexa with a conceptified proposal written up as a draft TS. LEWG began a design review of this proposal, and made good progress on it; they hope to complete the review during a post-meeting teleconference and then forward the proposal to LWG.

Study Groups

Note that some Study Groups whose proposals have progressed to the main working groups and which don’t plan on looking at new proposals, are no longer considered active – for example, SG 2 (Modules) is in this category, as the modules proposal is now in front of EWG. I talk a bit about the ones still active below.

SG 1 (Concurrency)

With the Parallelism TS published and the Concurrency TS sent out for its PDTS ballot, SG 1 has been working on the second iterations of both TS’s.

Here are some of the proposals being considered for Parallelism II:

And for Concurrency II:

There are numerous other proposals in front of the SG as well which don’t have a target ship vehicle yet.

SG 5 (Transactional Memory)

SG 5 has accomplished commendable work by publishing the Transactional Memory TS, but they aren’t quite calling it quits! They plan to meet again in Kona to discuss proposals for possible future standardization in the area.

SG 6 (Numerics)

SG 6 met and looked at three specific proposals:

The first, as I described in the “Library” section above, was unsuccessfully proposed for acceptance into C++17.

The other two are being considered for a Numerics TS, along with a number of other proposals not specifically discussed at this meeting, such as unbounded-precision integer types, rational numbers, fixed-point arithmetic, decimal floating-point support, various utility functions (GCD/LCM, constexpr bitwise operations), random numbers (a couple of different proposals), and other topics for which there aren’t concrete proposals yet. (Obviously, not everything in this list will be in a single Numerics TS.)

Said Numerics TS is still in a relatively early stage; a working draft is not yet expected in Kona.

SG 7 (Reflection)

SG 7 had a busy evening session where they looked at a number of reflection-related proposals:

  • A language feature for argument stringization (misleadingly titled “parameter stringization”), attempting to obsolete one of the few remaining uses for the preprocessor. The proposal was well-received; of the various syntactic options presented, SG 7 preferred the approach of adding an annotation to a function declaration that makes the stringized arguments corresponding to all parameters available in the function body under a syntax such as function_name.param<N>()
  • Potential improvements to source-code information capture. Two specific improvements were discussed: the ability to query the offset relative to the start of the file (in addition to a line number + offset relative to the source of the line), which meet with approval, and fine-grained intrinsics (e.g. querying the line number and the function name separately), for which SG 7 recommended waiting until the original proposal has implementation experience.
  • A proposal for language features to facilitate writing test code; consensus was that this topic is not sufficiently relevant to reflection, and should be pursued elsewhere (such as in EWG).
  • An updated version of a detailed, comprehensive proposal for static reflection (see also a slightly shorter paper outlining use cases). When the original version was presented in Urbana, it was given very short shrift, mostly because it had no presenter, and no one had had time to study it in any amount of detail. This time around, participants seemed to be more informed about it, and ended up being rather favourable to the overall approach. Most notably, the use of a “magic operator” (spelled mirrored(entity) in the proposal) rather than templates (such as reflect<entity> as the previously-discussed type property queries proposal did) opens the doors to reflecting more kinds of entities, such as typedefs (as distinct from their underlying types), uninstantiated templates, and namespaces, which SG 7 viewed as valuable. Interest in further development of the proposal was expressed.
  • Another reflection proposal, type reflection via variadic template expansion. Due to time constraints, this could only be presented very briefly. SG 7 expressed interest in a comparative analysis of the expressive power of this proposal compared to the “type property queries” and “static reflection” proposals.

Notably absent from the agenda was the latest version of the “type property queries” proposal, which had appeared to be the leading comprehensive reflection proposal in the past few meetings. The main reason it wasn’t presented was that the author couldn’t make it to the meeting, though one could also argue that SG 7 was already familiar with the overall design (the changes since the last version having been only minor), so time was better spent looking at proposals with alternative designs that still needed analysis.

SG 10 (Feature Test)

SG 10 is continuing to maintain the list of feature testing macros and keep it up to date with new things like C++17 features.

They also have a proposal for some new preprocessor features to aid feature detection: a __has_include() predicate for testing for the presence of an include, and a __has_cpp_attribute() predicate for testing for support for a particular attribute.

SG 12 (Undefined Behaviour)

SG 12 is still active, but did not meet this week as its members were busy advancing other proposals.

SG 13 (I/O)

SG 13 did not meet this week; the author of the 2D graphics proposal plans to complete standard wording for it for Kona.

*NEW* SG 14 (Game Development & Low-Latency Applications)

C++ aims to be a “zero-overhead abstraction” language, where you don’t pay for what you don’t use. It does a formidable job at this, but for some communities of C++ users, it could do an even better job.

The big sticking points are exceptions and RTTI, two language features for which you pay a bit even if you don’t use them. Projects concerned about this overhead commonly use compiler flags like -fno-exceptions and -fno-rtti, but the committee views these as nonconforming and doesn’t give them a lot of consideration. As a result, for example, a lot of standard library features require exceptions, and are therefore unusable in these projects.

There is also desire for more guarantees from the standard library, such as “empty containers never allocate” or “strings employ the small-string optimization”.

EWG looked at a a wishlist containing the above and more, and recommended creating a new Study Group to explore the area further.

The new Study Group, SG 14, will tentatively be called “Game Development & Low-Latency Applications”, because these are the most impacted communities, and the communities from which the committee hopes to get significant input.

There is a tentative plan for SG 14 to meet independently of the committee at CppCon and GDC, the idea being that members of the game development community are more likely to be able to make it to those events than to committee meetings.

Next Meeting

The next meeting of the Committee will be in Kona, Hawaii, the week of October 19th, 2015.

Conclusion

On the whole, this was a very exciting meeting! My highlights:

  • The Concepts TS being very close to publication. Concepts has been the feature I’ve been waiting for the most; I think it will revolutionize generic programming and allow C++ users to unleash the power of templates in unprecedented ways.
  • C++17 starting to take shape. While it’s uncertain whether some larger pieces like modules and coroutines will make it in, I think it will still have a good complement of features. Among other things, the success of the most recent default comparisons proposal, after the lack of consensus that plagued the ones that came before, is very encouraging – a good success story for the standards process.
  • Modules being on track to be available in the 2017 timeframe, even if it’s uncertain whether it will be part of C++17 itself or in the form of a Technical Specification.

Things are only going to get more interesting as C++17 starts to take more concrete shape, and more Technical Specifications cross the finish line. Stay tuned!

Author’s Note (2015-06-10): In the original version of this post, I made a claim about Modules not making it into C++17 that sounded authoritative, when in fact it was largely speculation. I have edited the post to clarify that no official decision has yet been made about the ship vehicle for Modules. My apologies for this mischaracterization, and my thanks to Gabriel Dos Reis for pointing it out.

Advertisements

About botondballo

I am a recent graduate of the University of Toronto, with a degree in Computer Science. I currently work for Mozilla as a software engineer.
This entry was posted in c++, programming and tagged , . Bookmark the permalink.

20 Responses to Trip Report: C++ Standards Meeting in Lenexa, May 2015

  1. antoine says:

    Awesome report, thanks.

  2. dr.module says:

    Little correction in your article.
    Modules in Clang was designed by Apple for C and Objective-C.
    Google is extending that to c++.

    Apple has been using Modules for c and obj-c in Mac OS X since last year.

  3. Sander van Rossen says:

    So modules & reflection didn’t made it, even though they’re the most useful features (that should’ve been added to C++ decades ago, especially modules). Everything else .. meh :-/

  4. Here’s what “Hitler” thinks about C++17: https://youtu.be/ND-TuW0KIgg

  5. Pingback: C++ Concepts TS could be voted for publication on July 20 | There's Waldo!

  6. Pingback: steveklabnik comments on “Things Rust shipped without” | Exploding Ads

  7. Dorin says:

    I would rather have a C++19 with Modules in instead of a C++17 without Modules. This is sad indeed.

    • botondballo says:

      The committee is on a 3-year release cadence. If Modules don’t make C++17, they will very likely make C++20. Would that be so much worse than having them in C++19? By sticking to the “release train” model, features that are ready in 2017 will become available to be used in 2017.

      Finally, keep in mind that even if we don’t get Modules in the official standard in C++17, we will likely get them in a TS in the same timeframe.

  8. Pingback: Trip Report: C++ Standards Meeting in Kona, October 2015 | There's Waldo!

  9. shoes says:

    Howdy! I could have sworn I’ve been to this site before but after looking at many of
    the articles I realized it’s new to me. Anyhow, I’m certainly pleased
    I found it and I’ll be book-marking it and checking back regularly!

  10. Anonymoose says:

    That was an interesting and informative read.

    I’m a bit surprised by the unsigned over/underflow issues they were looking at, honestly. I thought it would be standard practice to write simple underflow checks for unsigned variables using their properties instead of signed variables’ properties, assuming you checked during calculation/loop indexing/etc. For example:

    for(size_t sz = someContainer.size(), i = sz – 1; i = 0″ magically treat unsigned ints as if they were signed, so it may be wrong of me to assume people would actually write code that requires unsigned variables with unsigned variable properties in mind.
    [Alternatively, one could use static_cast(i >= 0), but that’s just awkward and inelegant, and requires knowing how the compiler implements size_t for the destination system.]

    Let’s see… assuming variables named uintN\_t\_old\_val, uintN\_t\_var, and increase\_value:
    * If you’re increasing a uint by another uint, use something like this:
    uintN\_t\_old_val = uintN\_t\_var;
    uintN\_t\_var += increase\_value;
    uintN\_t\_var = (uintN\_t\_var >= uintN\_t\_old\_val ? uintN\_t\_var : UINTn\_MAX);
    * If decreasing a uint by another uint, use the above, but with -= and =.
    * If increasing or decreasing a uint by a signed int, check the signed int’s sign first, and apply the appropriate bounds check afterwards depending on it.
    * If doing bounds checking on a loop, just check if the loop index went past the initial value. If decreasing the index, use something like this:
    loop\_index (initial\_value – 1)
    [Note that this limits us to only being able to use exactly one less than the full range of values available to our uintN\_t.]
    * If we need to use the full range of values available in your chosen uint\_t, from 0 to UINTn\_MAX, the only thing I can think of that works properly is something like this:
    for (uint16\_t i = 0, bool firstIteration = true; i > 0 || firstIteration; i++) {
    doSomething();
    if (i == 0) { firstIteration = false; }
    }
    Since we can’t be sure that when `i == 0`, it’s because the loop is just starting instead of because of overflow, we can use a `bool` to indicate whether or not this is the first iteration, so we can break the loop the second time we encounter 0.
    If we need to loop down from UINTn\_MAX, only a few simple changes are necessary:
    for (uint16\_t i = UINT16\_MAX, bool firstIteration = true; i < UINT16\_MAX || firstIteration; i++) {
    doSomething();
    if (i == UINT16\_MAX) { firstIteration = false; }
    }
    [Note sure if it would be more efficient to use an "if" in the loop body or to just put "firstIteration = false" as a second loop increment, or whether loop unrolling would change which is most efficient.]

    [Substitute ++i for i++ or –i for i– if you'd prefer, modern compilers should optimise both to the prefix version anyways.]

    If we use simple rules like that, is there any need to change the way over/underflow works for them? (Serious question, I'd like to know, assuming someone replies and I remember to check this page again later. I'd also be interested in knowing if there are any better low-overhead ways for checking & mitigating unsigned over/underflow.)

    • botondballo says:

      Assuming you’re talking about the overflow-handling functions proposed in N4448, I think the main value they provide is convenience, allowing you to avoid performing manual checks like the ones you described everywhere.

      • Anonymoose says:

        Ah, okay. I must’ve misread it, then, I kinda thought they were going to change the way unsigned over-/underflow handling was performed, in a way that could potentially damage existing manual checks, because it appears that the majority of programmers still treat unsigned ints as if they were signed when writing conditions.

        Also, it seems comments here don’t use Markdown, and I can’t edit mine to fix the formatting issues caused by my assumption that they do. Lovely. >.>

  11. Pingback: Trip Report: C++ Standards Meeting in Jacksonville, February 2016 | There's Waldo!

  12. Pingback: C++模块-为什么他们从C++ 0x?他们稍后会回来吗? – CodingBlog

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s