A response to “Net Neutrality. No big deal.”

I recently watched this video titled “Net Neturality. No big deal.” by Bryan Lunduke.

I watched this video because, while I am in favour of Net Neutrality, and concerned about the impending repeal of Net Neutrality regulations in the United States, I consciously try to avoid being stuck in an echo chamber of similar views, and try to expose myself to opposing viewpoints as well; particularly when such opposing viewpoints are held by a figure in a community that I respect and identify with (in Bryan’s case, the Linux and free software community).

I found the video interesting and well-presented, but I didn’t find Bryan’s arguments convincing. I decided to write this post to respond to two of the arguments Bryan makes in particular.

The first argument I wanted to address was about the fact that some of the largest companies that are lobbying to keep Net Neutrality rules in place – Google, Netflix, and Microsoft – are also supporters of DRM. Bryan argues, that since these companies support DRM, which is a threat to a free and open internet, we should not take their support for Net Neutrality (which they claim to also be motivated by a desire for a free and open internet) at face value; rather, they only support Net Neutrality regulations because they have a financial incentive for doing so (namely, they run high-bandwidth streaming and similar services that are likely to be first in line to be throttled in a world without Net Neutrality protections).

I don’t dispute that companies like Google, Netflix, and Microsoft support Net Neutrality for selfish reasons. Yes, the regulations affect their bottom line, at least in the short term. But that doesn’t mean there aren’t also good reasons for supporting Net Neutrality. Many organizations – like the Electronic Frontier Foundation, whom I have no reason to suspect to be beholden to the pocketbooks of large tech companies – have argued that Net Neutrality is, in fact, important for a free and open internet. That Netflix supports it for a different reason, doesn’t make that any less the case.

I also think that comparing DRM and the lack of Net Neutrality in this way confuses the issue. Yes, both are threats to a free and open internet, but I think they are qualitatively very different.

To explain why, let’s model an instance of communication over the internet as being between two parties: a sender or producer of the communication, and its receiver or consumer. DRM exists to give the producer control over how the communication is consumed. There are many problems with DRM, but at least it is not intended to interfere with communication in cases where the producer and consumer agree on the terms (e.g. the price, or lack thereof) of the exchange1.

By contrast, in a world without Net Neutrality rules, an intermediary (such as an ISP) can interfere with (such as by throttling) communication between two parties even when the two parties agree on the terms of the communication. This potentially opens the door to all manner of censorship, such as interfering with the communications of political activists. I see this as being a much greater threat to free communication than DRM.

(I also find it curious that Bryan seems to focus particularly on the standardization of DRM on the Web as being objectionable, rather than DRM itself. Given that DRM exists regardless of whether or not it’s standardized on the Web, the fact that it is standardized on the Web is a good thing, because it enables the proprietary software that implements the DRM to be confined to a low-privilege sandbox in the user’s browser, rather than having “full run of the system” as pre-standardization implementations of DRM like Adobe Flash did. See this article for more on that topic.)

The second argument Bryan makes that I wanted to address was that Net Neutrality rules mean the U.S. government being more involved in internet communications, such as by monitoring communications to enforce the rules.

I don’t buy this argument for two reasons. First, having Net Neutrality rules in place does not mean that internet communications need to be proactively monitored to enforce the rules. The role of the government could very well be limited to investigating and corrections violations identified and reported by users (or organizations acting on behalf of users).

But even we assume there will be active monitoring of internet communications to enforce the rules, I don’t see that as concerning. Let’s not kid ourselves: the U.S. government already monitors all internet communications it can get its hands on; axing Net Neutrality rules won’t cause them to stop. Moreover, users already have a way to protect the content of their communications (and, if desired, even the metadata, using tools like Tor) from being monitored: encryption. Net Neutrality rules don’t change that in any way.

In sum, I enjoyed watching Bryan’s video and I always appreciate opposing viewpoints, but I didn’t find the arguments that Net Neutrality is not a big deal convincing. For the time being, I continue to believe that the impending rollback of U.S. Net Neutrality rules is a big deal.

Footnotes

1. I am thinking here of cases where the content being communicated is original content, that is, content originated by the producer. I am, of course, aware, that DRM can and does interfere with the ability of two parties to communicate content owned by a third party, such as sending a movie to a friend. To be pedantic, DRM can even interfere with communication of original content in cases where such content is mistakenly identified as belonging to a third party. I’m not saying DRM is a good thing – I’m just saying it doesn’t rise to being the same level of threat to free communication as not having Net Neutrality protections does.

Advertisements
Posted in activism | Tagged , | 1 Comment

Trip Report: C++ Standards Meeting in Albuquerque, November 2017

Summary / TL;DR

Project What’s in it? Status
C++17 See below Publication imminent
Library Fundamentals TS v2 source code information capture and various utilities Published!
Concepts TS Constrained templates Merged into C++20 with some modifications
Parallelism TS v2 Task blocks, library vector types and algorithms and more Nearing feature-completion; expect PDTS ballot at next meeting
Transactional Memory TS Transaction support Published! Not headed towards C++20
Concurrency TS v1 future.then(), latches and barriers, atomic smart pointers Published! Parts of it headed for C++20
Concurrency TS v2 See below Under active development
Networking TS Sockets library based on Boost.ASIO Publication imminent
Ranges TS Range-based algorithms and views Publication imminent
Coroutines TS Resumable functions, based on Microsoft’s await design Publication imminent
Modules TS A component system to supersede the textual header file inclusion model Resolution of comments on Proposed Draft in progress
Numerics TS Various numerical facilities Under active development; no new progress
Graphics TS 2D drawing API Under active design review; no new progress
Reflection Code introspection and (later) reification mechanisms Introspection proposal awaiting wording review. Targeting a Reflection TS.
Contracts Preconditions, postconditions, and assertions Proposal under wording review

Some of the links in this blog post may not resolve until the committee’s post-meeting mailing is published (expected within a few days of November 27, 2017). If you encounter such a link, please check back in a few days.

Introduction

A couple of weeks ago I attended a meeting of the ISO C++ Standards Committee (also known as WG21) in Albuquerque, New Mexico. This was the third committee meeting in 2017; you can find my reports on previous meetings here (February 2017, Kona) and here (July 2017, Toronto). These reports, particularly the Toronto one, provide useful context for this post.

With the final C++17 International Standard (IS) having been voted for publication, this meeting was focused on C++20, and the various Technical Specifications (TS) we have in flight, most notably Modules.

What’s the status of C++17?

The final C++17 International Standard (IS) has been sent off for publication in September. The final document is based on the Draft International Standard (DIS), with only minor editorial changes (nothing normative) to address comments on the DIS ballot; it is now in ISO’s hands, and official publication is imminent.

In terms of implementation status, the latest versions of GCC and Clang both have complete support for C++17, modulo bugs. MSVC is said to be on track to be C++17 feature-complete by March 2018; if that ends up being the case, C++17 will be quickest standard version to date to be supported by these three major compilers.

C++20

This is the second meeting that the C++20 Working Draft has been open for changes. (To use a development analogy, think of the current Working Draft as “trunk”; it was opened for changes as soon as C++17 “branched” earlier this year). Here, I list the changes that have been voted into the Working Draft at this meeting. For a list of changes voted in at the previous meeting, see my Toronto report.

Technical Specifications

In addition to the C++ International Standard, the committee publishes Technical Specifications (TS) which can be thought of “feature branches” (to continue the development analogy from above), where provisional specifications for new language or library features are published and the C++ community is invited to try them out and provide feedback before final standardization.

At the last meeting, we published three TSes: Coroutines, Ranges, and Networking. The next steps for these features is to wait for a while (usually at least a year) to give users and implementers a chance to try them out and provide feedback. Once we’re confident the features are ripe for final standardization, they will be merged into a future version of the International Standard (possibly C++20).

Modules TS

The Modules TS made significant progress at the last meeting: its Proposed Draft (PDTS) was published and circulated for balloting, a process where national standards bodies evaluate, vote on, and submit comments on a proposed document. The ballot passed, but numerous technical comments were submitted that the committee intends to address before final publication.

A lot of time at this meeting was spent working through those comments. Significant progress was made, but not enough to vote out the final published TS at the end of the meeting. The Core Working Group (CWG) intends to hold a teleconference in the coming months to continue reviewing comment resolutions. If they get through them all, a publication vote may happen shortly thereafter (also by teleconference); otherwise, the work will be finished, and the publication vote held, at the next meeting in Jacksonville.

I summarize some of the technical discussion about Modules that took place at this meeting below.

The state of Modules implementation is also progressing: in addition to Clang and MSVC, Facebook has been contributing to a GCC implementation.

Parallelism TS v2

The Parallelism TS v2 is feature-complete, with one final feature, a template library for parallel for loops voted in at this meeting. A vote to send it out for its PDTS ballot is expected at the next meeting.

Concurrency TS v2

The Concurrency TS v2 (no working draft yet) continues to be under active development. Three new features targeting it have received design approval at this meeting: std::cell, a facility for deferred reclamation; apply() for synchronized_value; and atomic_ref. An initial working draft that consolidates the various features slated for the TS into a single document is expected at the next meeting.

Executors, slated for a separate TS, are making progress: the Concurrency Study Group approved the design of the unified executors proposal, thereby breaking the lockdown that has been holding the feature up for a number of years.

Stackful coroutines continue to be a unique beast of their own. I’ve previously reported them to be slated for the Concurrency TS v2; I’m not sure whether that’s still the case. They change the semantics of code in ways that impacts the core language, and thus need to be reviewed by the Evolution Working Group; one potential concern is that the proposal may not be implementable on all platforms (iOS came up as a concrete example during informal discussion). For the time being, the proposal is still being looked at by the Concurrency Working Group, where there continues to be strong interest in standardizing them in some form, but the details remain to be nailed down; I believe the latest development is that an older API proposal may end up being preferred over the latest call/cc one.

Future Technical Specifications

There are some planned future Technical Specifications that don’t have an official project or working draft yet:

Reflection

The static introspection / “reflexpr” proposal (see its summary, design, and specification for details), headed for a Reflection TS, has been approved by the Evolution and Library Evolution Working Groups, and is awaiting wording review. The Reflection Study Group (recently renamed to “Compile-Time Programming Study Group”) approved an extension to it, concerning reflection over functions, at this meeting.

There are more reflection features to come beyond what will be in the static introspection TS. One proposal that has been drawing a lot of attention is metaclasses, an updated version of which was reviewed at this meeting (details below).

Graphics

I’m not aware of much new progress on the planned Graphics TS (containing 2D graphics primitives inspired by cairo) since the last meeting. The latest draft spec can be found here, and is still on the Library Evolution Working Group’s plate.

Numerics

Nothing particularly new to report here either; the Numerics Study Group did not meet this week. The high-level plan for the TS remains as outlined previously. There are concrete proposals for several of the listed topics, but not working draft for the TS yet.

Other major features

Concepts

As I related in my previous report, Concepts was merged into C++20, minus abbreviated function templates (AFTs) and related features which remain controversial.

I also mentioned that there will likely be future proposals to get back AFTs in some modified form, that address the main objection to them (that knowing whether a function is a template or not requires knowing whether the identifiers in its signature name types or concepts). Two such proposals were submitted in advance of this paper; interestingly, both of them proposed a very similar design: an adjective syntax where in an AFT, a concept name would act as an adjective tacked onto the thing it’s constraining – most commonly, for a type concept, typename or auto. So instead of void sort(Sortable& s);, you’d have void sort(Sortable& auto s);, and that makes it clear that a template is being defined.

These proposals were not discussed at this meeting, because some of the authors of the original Concepts design could not make it to the meeting. I expect a lively discussion in Jacksonville.

Now that Concepts are in the language, the question of whether new library proposals should make use of them naturally arose. The Library Evolution Working Group’s initial guidance is “not yet”. The reason is that most libraries require some foundational concepts to build their more specific concepts on top of, and we don’t want different library proposals to duplicate each other / reinvent the wheel in that respect. Rather, we should start by adding a well-designed set of foundational concepts, and libraries can then start building on top of those. The Ranges TS is considered a leading candidate for providing that initial set of foundational concepts.

Operator Dot

I last talked about overloading operator dot a year ago, when I mentioned that there are two proposals for this: the original one, and an alternative approach that achieves a similar effect via inheritance-like semantics.

There hasn’t been much activity on those proposals since then. I think that’s for two reasons. First, the relevant people have been occupied with Concepts. Second, as the reflection proposals develop, people are increasingly starting to see them as a more general mechanism to satisfy operator dot’s use cases. The downside, of course, is that reflection will take longer to arrive in C++, while one of the above two proposals could plausibly have been in C++20.

Evolution Working Group

I’ll now write in a bit more detail about the technical discussions that took place in the Evolution Working Group, the subgroup that I sat in for the duration of the week.

All proposals discussed in EWG at this meeting were targeting C++20 (except for Modules, where we discussed some changes targeting the Modules TS). I’ve categorized them into the usual “accepted”, “further work encouraged”, and “rejected” categories:

Accepted proposals:

  • Standardizing feature test macros (and another paper effectively asking for the same thing). Feature test macros are macros like __cpp_lambdas that tell you whether your compiler or standard library supports a particular feature without having to resort to the more indirect approach of having a version check for each of your supported compilers. The committee maintains a list of them, but they’re not an official part of the standard, and this has led some implementations to refuse to support them, thus significantly undermining their usefulness. To rectify this, it was proposed that they are made part of the official standard. This was first proposed at the last meeting, but failed to gain consensus at that time. It appears that people have since been convinced (possibly by the arguments laid out in the linked papers), as this time around EWG approved the proposal.
  • Bit-casting object representations. This is a library proposal, but EWG was asked for guidance regarding making this function constexpr, which requires compiler support. EWG decided that it could be made constexpr for all types except a few categories – unions, pointers, pointers-to-members, and references – for which that would have been tricky to implement.
    • As a humorous side-note about this proposal, since it could only apply to “plain old data” types (more precisely, trivially copyable types; as mentioned above, “plain old data” was deprecated as a term of art), one of the potential names the authors proposed for the library function was pod_cast. Sadly, this was voted down in favour of bit_cast.
  • Language support for empty objects. This addresses some of the limitations of the empty base optimization (such as not being able to employ it with types that are final or otherwise cannot be derived from) by allowing data members to opt out of the rule that requires them to occupy at least 1 byte using an attribute, [[no_unique_address]]. The resulting technique is called the “empty member optimization”.
  • Efficient sized delete for variable-sized classes. I gave some background on this in my previous post. The authors returned with sign-off from all relevant implementers, and a clearer syntax (the “destroying delete” operator is now identified by a tag type, as in operator delete(Type*, std::destroying_delete_t), and the proposal was approved.
  • Attributes for likely and unlikely statements. This proposal has been updated as per previous EWG feedback to allow placing the attribute on all statements. It was approved with one modification: placing the attribute on a declaration statement was forbidden, because other attributes on declaration statements consistently apply to the entity being declared, not the statement itself.
  • Deprecate implicit capture of *this. Only the implicit capture of *this via [=] was deprecated; EWG felt that disallowing implicit capture via [&] would break too much idiomatic code.
  • Allow pack expansions in lambda init-capture. There was no compelling reason to disallow this, and the workaround of constructing a tuple to store the arguments and then unpacking it is inefficient.
  • String literals as template parameters. This fixes a longstanding limitation in C++ where there was previously no way to do compile-time processing of strings in such a way that the value of the string could affect the type of the result (as an example, think of a compile-time regex parsing library where the resulting type defines an efficient matcher (DFA) for the regex). The syntax is very simple: template <auto& String>; the auto then gets deduced as const char[N] (or const char16_t[N] etc. depending on the type of the string literal passed as argument) where N is the length of the string. (You can also write template <const char (&String)[N]> if you know N, but you can’t write template <size_t N, const char (&String)[N]> and have both N and String deduced from a single string literal template argument, because EWG did not want to create a precedent for a single template argument matching two template parameters. That’s not a big deal, though: using the auto form, you can easily recover N via traits, and even constrain the length or the character type using a requires-clause.)
  • A tweak to the Contracts proposal. An issue came up during CWG review of the proposal regarding inline functions with assertion checks inside them: what should happen if the function is called from two translation units, one of which is compiled with assertion checks enabled and one of them not? EWG’s answer was that, as with NDEBUG today, this is technically an ODR (one definition rule) violation. The behaviour in practice is fairly well understood: the linker will pick one version or the other, and that version will be used by both translation units. (There are some potential issues with this: what if, while compiling a caller in one of the translation units, the optimizer assumed that the assertion was checked, but the linker picks the version where the assertion isn’t checked? That can result in miscompilation. The topic remains under discussion.)

There were also a few that, after being accepted by EWG, were reviewed by CWG and merged into the C++20 working draft the same week, and thus I already mentioned them in the C++20 section above:

  • Fixing small-ish functionality gaps in concepts. This consisted of three parts, two of which were accepted:
    • requires-clauses in lambdas. This was accepted.
    • requires-clauses in template template parameters. Also accepted.
    • auto as a parameter type in regular (non-lambda) functions. This was mildly controversial due to the similarity to AFTs, whose design is still under discussion, so it was deferred to be dealt with together with AFTs.
  • Access specifiers and specializations.
  • Deprecating “plain old data” (POD).
  • Default constructible and assignable stateless lambdas.

  • Proposals for which further work is encouraged:

    • Standard containers and constexpr. This is the latest version of an ongoing effort by compiler implementers and others to get dynamic memory allocation working in a constexpr context. The current proposal allows most forms of dynamic allocation and related constructs during constant evaluation: non-trivial destructors, new and delete expressions, placement new, and use of std::allocator; this allows reusing a lot of regular code, including code that uses std::vector, in a constexpr context. Direct use of operator new is not allowed, because that returns void*, and constant evaluation needs to track the type of dynamically allocated objects. There is also a provision to allow memory that is dynamically allocated during constant evaluation to survive to runtime, at which point it’s treated as static storage. EWG liked the direction (and particularly the fact that compiler writers were on the same page regarding its implementability) and encouraged development of a more concrete proposal along these lines.
    • Supporting offsetof for stable-layout classes. “Stable-layout” is a new proposed category of types, broader than “standard-layout”, for which offsetof could be implemented. EWG observed that the definition of “standard-layout” itself could be broadened a bit to include most of the desired use cases, and expressed a preference for doing that instead of introducing a new category. There was also talk of potentially supporting offsetof for all types, which may be proposed separately as a follow-up.
    • short float. This proposal for a 16-bit floating-point type was approved by EWG earlier this year, but came back for some reason. There was some re-hashing of previous discussions about whether the standard should mandate the size (16 bits) and IEEE behaviour.
    • Adding alias declarations to concepts. This paper proposed three potential enhancements to concept declarations to make writing concepts easier. EWG was not particularly convinced about the need for this, but believed at least the first proposal could be entertained given stronger motivation.
    • [[uninitialized]] attribute. This attribute is intended to suppress compiler warnings about variables that are declared but not initialized in cases where this is done intentionally, thus facilitating the use of such warnings in a codebase to catch unintentional cases. EWG pointed out that most compiler these days warn not about uninitialized declarations, but uninitialized uses. There was also a desire to address the broader use case of allocating dynamic memory that is purposely uninitialized (e.g. std::vector<char> buffer(N) currently zero-initializes the allocated memory).
    • Relaxed incomplete multidimensional array type declaration. This is a companion proposal to the std::mdspan library proposal, which is a multi-dimensional array view. It would allow writing things like std::mdspan<double[][][]> to denote a three-dimensional array where the size in each dimension is determined at runtime. Note that you still would not be able to create an object of type double[][][]; you could only use it in contexts that do not require creating an object, like a template argument. Basically, mdspan is trying to (ab)use array types as a mini-DSL to describe its dimensions, similar to how std::function uses function types as a mini-DSL to describe its signature. This proposal was presented before, when mdspan was earlier in its design stage, and EWG did not find it sufficiently motivating. Now that the mdspan is going forward, the authors tried again. EWG was open to entertaining the idea, but only if technical issues such as the interaction with template argument deduction are ironed out.
    • Class types in non-type template parameters. This has been proposed before, but EWG was stuck on the question of how to determine equivalence (something you need to be able to do for template arguments) for values of class types. Now, operator<=> has given us a way to move forward on this question, basically by requiring that class types used in non-type template parameters have a defaulted operator<=>. It was observed that there is some overlap with the proposal to allow string literals as template parameters (since one way to pass a character array as a template parameter would be to wrap it in a struct), but it seemed like they also each have their own use cases and there may be room for both in the language.
    • Dynamic library loading. The C++ standard does not talk about dynamic libraries, but some people would find it useful to have a standardized library interface for dealing with them anyways. EWG was asked for input on whether it would be acceptable to standardize a library interface without saying too much about its semantics (since specifying the semantics would require that the C++ standard start talking about dynamic libraries, and specifying their behaviour in relation to exceptions, thread-local storage, the One Definition Rule, and so on). EWG was open to this direction, but suggested that the library interface be made much more general, as in its current incarnation it seemed to be geared towards certain platforms and unimplementable on others.
    • Various proposed extensions to the Modules TS, which I talk about below.

    There was also a proposal for recursive lambdas that wasn’t discussed because its author realized it needed some more work first.

    Rejected proposals:

    • A proposed trait has_padding_bits, the need for which came up during review of an atomics-related proposal by the Concurrency Study Group. EWG expressed a preference for an alternative approach that removed the need for the trait by putting the burden on compiler implementers to make things work correctly.
    • Attributes for structured bindings. This was proposed previously and rejected on the basis of insufficient motivation. The author came back with additional motivation: thread-safety attributes such as [[guarded_by]] or [[locks_held]]. However, it was pointed out that the individual bindings are just aliases to fields of an (unnamed) object, so it doesn’t make sense to apply attributes to them; attributes can be applied to the deconstructed object as a whole, or to one of its fields at the point of the field’s declaration.
    • Keeping the alias syntax extendable. This proposed reverting the part of the down with typename! proposal, approved at the last meeting, that allowed omitting the typename in using alias = typename T::type; where T was a dependent type. The rationale was that even though today only a type is allowed in that position (thus making the typename disambiguator redundant), this prevents us from reusing the same syntax for expression aliases in the future. EWG already considered this, and didn’t find it compelling: the preference was to make the “land grab” for a syntax that is widely used today, instead of keeping it in reserve for a hypothetical future feature.
    • Forward without forward.The idea here is to abbreviate the std::forward<decltype(x)>(x) boilerplate that often occurs in generic code, to >>x (i.e. a unary >> operator applied to x). EWG sympathized with the desire to eliminate this boilerplate, but felt that >>, or indeed any other unary operator, would be too confusing of a syntax, especially when occuring after an = in a lambda init-capture (e.g. [foo=>>foo](...){ ... }). EWG was willing to entertain a keyword instead, but the best people could come up with was fwdexpr and that didn’t have consensus; as a result, the future of this proposal is uncertain.
    • Relaxing the rules about invoking an explicit constructor with a braced-init-list. This would have allowed , among a few other changes, writing return {...}; instead of return T{...}; in a function whose declared return type is T, even if the invoked constructor was explicit. This has been proposed before, but rejected on the basis that it makes it easy to introduce bugs (see e.g. this response). The author proposed addressing those concerns by introducing some new rules to limit the cases in which this was allowed, but EWG did not find the motivation sufficiently compelling to further complicate C++’s already complex initialization rules.
    • Another attempt at standardizing arrays of runtime bound (ARBs, a pared-down version of C’s variable-length arrays), and a C++ wrapper class for them, stack_array. ARBs and a wrapper class called dynarray were previously headed for standardization in the form of an Array Extensions TS, before the project was scrapped because dynarray was found to be unimplementable. This proposal would solve the implementability concerns by restricting the usage of stack_array (e.g. it couldn’t be used as a class member). EWG was concerned that the restrictions would result in a type that’s not very usable. (It was pointed out that a design to make such a type more composable was proposed previously, but the author didn’t have time to pursue it further.) Ultimately, EWG didn’t feel that this proposal had a better chance of succeeding than the last time standardization of ARBs was attempted. However, a future direction that might be more promising was outlined: introducing a core language “allocation expression” that allocates a unnamed (and runtime-sized) stack array and returns a non-owning wrapper, such as a std::span, to access it.
    • A modern C++ signature for main(). This would have introduced a new signature for main() (alongside the existing allowed signatures) that exposed the command-line arguments using an iterable modern C++ type rather than raw pointers (the specific proposal was int main(std::initializer_list<std::string_view>). EWG was not convinced that such a thing would be easier to use and learn than int main(int argc, char*[] argv);. It was suggested that instead, a trivial library facility that took argc and argv as inputs and exposed an iterable interface could be provided; alternatively (or in addition), a way to access command-line arguments from anywhere in the program (similar to Rust’s std::env::args()) could be explored.
    • Abbreviated lambdas for fun and profit. This proposal would introduce a new abbreviated syntax for single-expression lambdas; a previous version of it was presented and largely rejected in Kona. Not much has changed to sway EWG’s opinion since then; if anything, additional technical issues were discovered.

      For example, one of the features of the abbreviated syntax is “automatic SFINAE”. That is, [x] => expr would mean [x] -> decltype(expr) { return expr; }; the appearance of expr in the return type rather than just the body would mean that a substitution failure in expr wouldn’t be a hard error, it would just remove the function overload being considered from the overload set (see the paper for an example). However, it was pointed out that in e.g. [x] -> decltype(x) { return x; }, the x in the decltype and the x in the body refer to two different entities: the first refers to the variable in the enclosing scope that is captured, and the second to the captured copy. If we try to make [x] => x “expand to” that, then we get into a situation where the x in the abbreviated form refers to two different entities for two different purposes, which would be rather confusing. Alternatively, we could say in the abbreviated form, x refers to the captured copy for both purposes, but then we are applying SFINAE in new scenarios, and some implementers are strongly opposed to that.

      It was also pointed out that the abbreviated form’s proposed return semantics were “return by reference”, while regular lambdas are “return by value” by default. EWG felt it would be confusing to have two different defaults like this.
    • Making the lambda capture syntax more liberal in what it accepts. C++ currently requires that in a lambda capture list, the capture-default, if present, come before any explicit captures. This proposal would have allowed them to be written in any order; in addition, it would have allowed repeating variables that are covered by the capture-default as explicit captures for emphasis. EWG didn’t find the motivation for either of these changes compelling.
    • Lifting overload sets into objects. This is a resurrection of an earlier proposal to allow passing around overload sets as objects. It addressed previous concerns with that proposal by making the syntax more explicit: you’d pass []f rather than just f, where f was the name of the overloaded function. There were also provisions for passing around operators, and functions that performed member access. EWG’s feedback was that this proposal seems to be confused between two possible sets of desired semantics:
      1. a way to build super-terse lambdas, which essentially amounts to packaging up a name; the overload set itself isn’t formed at the time you create the lambda, only later when you instantiate it
      2. a way to package and pass around overload sets themselves, which would be formed at the time you package them

      EWG didn’t have much of an appetite for #1 (possibly because it had just rejected another terse-lambda proposal), and argued that #2 could be achieved using reflection.

    Discussion papers

    There were also a few papers submitted to EWG that weren’t proposals per se, just discussion papers.

    These included a paper arguing that Concepts does not significantly improve upon C++17, and a response paper arguing that it in fact does. The main issue was whether Concepts delivers on its promise of making template error messages better; EWG’s consensus was that they do when compared to unconstrainted templates, but perhaps not as much as one would hope when compared to C++17 techniques for constraining templates, like enable_if. There may be room for implementations (to date there is just the one in GCC) to do a better job here. (Of course, Concepts are also preferable over enable_if in other ways, such as being much easier to read.)

    There was also a paper describing the experiences of the author teaching Concepts online. One of the takeaways here is that students don’t tend to find the variety of concept declaration syntaxes confusing; they tend to mix them freely, and they tend to like the abbreviated function template (AFT) syntax.

    Modules

    I mentioned above that a significant focus of the meeting was to address the national body comments on the Modules PDTS, and hopefully get to a publication vote on the final Modules TS.

    EWG looked at Modules on two occasions: first to deal with PDTS comments that had language design implications, and second to look at new proposals concerning Modules. The latter were all categorized as “post-TS”: they would not target the Modules TS, but rather “Modules v2”, the next iteration of Modules (for which the ship vehicle has not yet been decided).

    Modules TS

    The first task, dealing with PDTS comments in EWG, was a short affair. Any comment that proposed a non-trivial design change, or even remotely had the potential to delay the publication of the Modules TS, was summarily rejected (with the intention that the concern could be addressed in Modules v2 instead). It was clear that the committee leadership was intent on shipping the Modules TS by the end of the meeting, and would not let it get derailed for any reason.

    “That’s a good thing, right?” you ask. After all, the sooner we ship the Modules TS, the sooner people can start trying it out and providing feedback, and thus the sooner we can get a refined proposal into the official standard, right? I think the reality is a bit more nuanced than that. As always, it’s a tradeoff: if we ship too soon, we can risk shipping a TS that’s not sufficiently polished for people to reasonably implement and use it; then we don’t get much feedback and we effectively waste a TS cycle. In this case, I personally feel like EWG could have erred a bit more on the side of shipping a slightly more polished TS, even if that meant delaying the publication by a meeting (it ended up being delayed by at least a couple of months anyways). That said, I can also sympathize with the viewpoint that Modules has been in the making for a very long time and we need to ship something already.

    Anyways, for this reason, most PDTS comments that were routed to EWG were rejected. (Again, I should emphasize that this means “rejected for the TS“, not “rejected forever”.) The only non-rejection response that EWG gave was to comment US 041, where EWG confirmed that the intent was that argument-dependent lookup could find some non-exported entities in some situations.

    Of course, there were other PDTS comments that weren’t routed to EWG because they weren’t design issues; these were routed to CWG, and CWG spent much of the week looking at them. At one point towards the end of the week, CWG did consult EWG about a design issue that came up. The question concerned whether a translation unit that imports a module sees a class type declared in that module as complete or incomplete in various situations. Some of the possibilities that have to be considered here are whether the module exports the class’s forward declaration, its definition, or both; whether the module interface unit contains a definition of the class (exported or not) at all; and whether the class appears in the signature of an exported entity (such as a function) without itself being exported.

    There are various use cases that need to be considered when deciding the behaviour here. For example, a module may want to export functions that return or take as parameters pointers or references to a type that’s “opaque” to the module’s consumer, i.e. the module’s consumer can’t create an instance of such a class or access its fields; that’s a use case for exporting a type as incomplete. At the same time, the module author may want to avoid splitting her module into separate interface and implementation units at all, and thus wants to define the type in the interface unit while still exporting it as incomplete.

    The issue that CWG got held up on was that the rules as currently specified seemed to imply that in a consumer translation unit, an imported type could be complete and incomplete at the same time, depending on how it was named (e.g. directly vs. via decltype(f()) where it was the return type of a function f). Some implementers indicated that this would be a significant challenge to implement, as it would require a more sophisticated implementation model for types (where completeness was a property of “views of types” rather than of types themselves) that no existing language feature currently requires.

    Several alternatives were proposed which avoided these implementation challenges. While EWG was favourable to some of them, there was also opposition to making what some saw as a design change to the Modules TS at this late stage, so it was decided that the TS would go ahead with the current design, possibly annotated as “we know there’s a potential problem here”, and it would be fixed up in v2.

    I find the implications of this choice a bit unfortunate. It sounded like the implementers that described this model as being a significant challenge to implement, are not planning to implement it (after all, it’s going to be fixed in v2; why redesign your compiler’s type system if ultimately you won’t need it). Other implementers may or may not implement this model. Either way, we’ll either have implementation divergence, or all implementations will agree on a de facto model that’s different from what the spec says. This is one of those cases where I feel like waiting to polish the spec a bit more, so that it’s not shipped in a known-to-be-broken state, may have been advised.

    I mentioned in my previous report that I thought the various Modules implementers didn’t talk to each other enough about their respective implementation strategies. I still feel like that’s very much the case. I feel like discussing each other’s implementation approaches in more depth would have unearthed this issue, and allowed it to be dealt with, sooner.

    Modules v2

    Now moving on to the proposals targeting Modules v2 that EWG reviewed:

    • Two of them (module interface imports and namespace pervasiveness and modules) it turned out were already addressed in the Modules TS by changes made in response to PDTS comments.
    • Placement of module declarations. Currently, if a module unit contains declarations in the global module, the module declaration (which effectively “starts” the module) needs to go after those global declarations. However, this makes it more difficult for both humans and tools to find the module declaration. This paper proposes a syntax that allows having the module declaration be the first declaration in the file, while still having a way to place declarations in the global module. It was observed that this proposal would make it easier to make module a context-sensitive keyword, which has also been requested. EWG encouraged continued exploration in this direction.
    • Module partitions. This iterates on the previous module partitions proposal (found in this paper), with a new syntax: module basename : partition; (unlike in the previous version, partition here is not a keyword, it’s the partition’s name). EWG liked this approach as well. Module partitions also make proclaimed-ownership-declarations unnecessary, so those can be axed.
    • Making module names strings. Currently, module names are identifier sequences separated by dots (e.g. foo.bar.baz), with the dots not necessarily implying a hierarchical relationship; they are mapped onto files in an implementation-defined manner. Making them strings instead would allow mapping onto the filesystem more explicitly. There was no consensus for this change in EWG.
    • Making module a context-sensitive keyword. As always, making a common word like module a hard keyword breaks someone. In this case, it shows up as an identifier in many mature APIs like Vulkan, CUDA, Direct X 9, and others, and in some of these cases (like Vulkan) the name is enshrined into a published specification. In some cases, the problem can be solved by making the keyword context-sensitive, and that’s the case for module (especially if the proposal about the placement of module declarations is accepted). EWG agreed to make the keyword context-sensitive. The authors of this paper asked if this could be done for the TS rather than for Modules v2; that request was rejected, but implementers indicated that they would implement it as context-sensitive ASAP, thus avoiding problems in practice.
    • Modules TS does not support intended use case. The bulk of the concerns here were addressed in the Modules TS while addressing PDTS comments, except for a proposed extension to allow using-declarations with an unqualified name. EWG indicated it was open to such an extension for v2.
    • Two papers about support for exporting macros, which remains one of the most controversial questions about Modules. The first was a “rumination” paper, which was mostly arguing that we need a published TS and deployment experience before we can settle the question; the second argued that having deployed modules (clang’s pre-TS implementation) in a large codebase (Apple’s), it’s clear that macro support is necessary. A number of options for preserving hygiene, such as only exporting and importing individual macros, were discussed. EWG expressed a lukewarm preference to continuing to explore macro support, particularly with such fine-grained control for hygiene.

    Other Working Groups

    The Library Evolution Working Group, as usual, reviewed a decent amount of proposed new library features. While I can’t give a complete listing of the proposals discussed and their outcomes (having been in EWG all week), I’ll mention a few highlights of accepted proposals:

    Targeting C++20:

    std::span (formerly called array_view) is also targeting C++20, but has not quite gotten final approval from LEWG yet.

    Targeting the Library Fundamentals TS v3:

    • mdspan, a multi-dimensional array view. (How can a multi-dimensional array view be approved sooner than a single-dimensional one, you ask? It’s because mdspan is targeting a TS, but span is targeting the standard directly, so span needs to meet a higher bar for approval.)
    • std::expected<T>, a “value or error” variant type very similar to Rust’s Result

    Targeting the Ranges TS:

    • Range adaptors (“views”) and utilities. Range views are ranges that lazily consume elements from an underlying range, while performing an additional operation like transforming the elements or filtering them. This finally gives C++ a standard facility that’s comparable to C#’s LINQ (sans the SQL syntax), Java 8’s streams, or Rust’s iterators. C++11 versions of the facilities proposed here are available today in the range-v3 library (which was in turn inspired by Boost.Range).

    There was an evening session to discuss the future of text handling in C++. There was general agreement that it’s desirable to have a text handling library that has notions of code units, code points, and grapheme clusters; for many everyday text processing algorithms (like toupper), operating at the level of grapheme clusters makes the most sense. Regarding error handling, different people have different needs (safety vs. performance), and a policy-based approach to control error handling may be advisable. Some of the challenges include standard library implementations having to ship a database of Unicode character classifications, or hook into the OS’s database. The notion of whether we should have a separate character type to represent UTF-8 encoded text, or just use char for that purpose, remains contentious.

    SG 7 (Compile-Time Programming)

    SG 7, the Compile-Time Programming (previously Reflection) Study Group met for an evening session.

    An updated version of a proposed extension to the static reflection proposal to allow reflecting over functions was briefly reviewed and sent onwards for review in EWG and LEWG at future meetings.

    The rest of the evening was spent discussing an updated version of the metaclasses proposal. To recap, a metaclass defines a compile-time transformation on a class, and can be applied to a class to produce a transformed class (possibly among other things, like helper classes / functions). The discussion focused on one particular dimension of the design space here: how the transformation should be defined. Three options were given:

    1. The metaclass operates on a mutable input class, and makes changes to it to produce the transformed class. This is how it worked in the original proposal.
    2. Like #1, but the metaclass operates on an immutable input class, and builds the transformed class from the ground up as its output.
    3. Like #2, but the metaclass code operates on the “meta level”, where the representation of the input and output types is an ordinary object of type meta::type. This dispenses with most of the special syntax of the first two approaches, making the metaclass look a lot like a normal constexpr function.

    SG 7 liked the third approach the best, noting that it not only dispenses with the need for the $ syntax (which couldn’t have been the final syntax anyways, it would have needed to be something uglier), but makes the proposal more general (opening up more avenues for how and where you can invoke/apply the metaclass), and more in line with the preference the group previously expressed to have reflection facilities operate on a homogeneous value representation of the program’s entities.

    Discussion of other dimensions of the design space, such as what the invocation syntax for metaclasses should look like (i.e. how you apply them to a class) was deferred to future meetings.

    SG 12 (Undefined Behaviour and Vulnerabilities)

    SG 12, the Undefined Behaviour Study Group, recently had its scope expanded to also cover documenting vulnerabilities in the C++ language, and ways to avoid them.

    This latter task is a joint effort between SG 12 and WG 23, a sister committee of the C++ Standards Committee that deals with vulnerabilities in programming languages in general. WG 23 produces a language-agnostic document that catalogues vulnerabilities without being specific to a language, and then language-specific annexes for a number of programming languages. For the last couple of meetings, WG 23 has been collaborating with our SG 12 to produce a C++ annex; the two groups met for that purpose for two days during this meeting. The C++ annex is at a pretty early stage, but over time it has the potential to grow to be a comprehensive document outlining many interesting types of vulnerabilities that C++ programmers can run into, and how to avoid them.

    SG 12 also had a meeting of its own, where it looked at a proposal to make certain low-level code patterns that are widely used but technically have undefined behaviour, have defined behaviour instead. This proposal was reviewed favourably.

    C++ Stability and Velocity

    On Friday evening, there was a session to discuss the stability and velocity of C++.

    One of the focuses of the session was reviewing the committee’s policy on deprecating and removing old features that are known to be broken or that have been superseded by better alternatives. Several language features (e.g. dynamic exception specifications) and library facilities (e.g. std::auto_ptr) have been deprecated and removed in this way.

    One of the library facilities that were removed in C++17 was the deprecated “binders” (std::bind1st and std::bind2nd). These have been superseded by the C++11 std::bind, but, unlike say auto_ptr, they aren’t problematic or dangerous in any way. It was argued that the committee should not deprecate features like that, because it causes unnecessary code churn and maintenance cost for codebases whose lifetime and update cycle is very long (on the order of decades); embedded software such as an elevator control system was brought up as a specific example.

    While some sympathized with this viewpoint, the general consensus was that, to be able to evolve at the speed it needs to to satisfy the needs of the majority of its users, C++ does need to be able to shed old “cruft” like this over time. Implementations often do a good job of maintaining conformance modes with older standard versions (and even “escape hatches” to allow old features that have been removed to be used together with new features that have since been added), thus allowing users to continue using removed features for quite a while in practice. (Putting bind1st and bind2nd specifically back into C++20 was polled, but didn’t have consensus.)

    The other focus of the session was the more general tension between the two pressures of stability and velocity that C++ faces as it evolves. It was argued that there is a sense in which the two are at odds with each other, and the committee needs to take a clearer stance on which is the more important goal. Two examples of cases where backwards compatibility constraints have been a drag on the language that were brought up were the keywords used for coroutines (co_await, co_yield, etc. – wouldn’t it have been nice to just be able to claim await and yield instead?), and the const-correctness issue with std::function which still remains to be fixed. A poll on which of stability or velocity is more important for the future direction of C++ revealed a wide array of positions, with somewhat of a preference for velocity.

    Conclusion

    This was a productive meeting, whose highlights included the Modules TS making good progress towards its publication; C++20 continuing to take shape as the draft standard gained the consistent comparisons feature among many other smaller ones; and range views/adaptors being standardized for the Ranges TS.

    The next meeting of the Committee will be in Jacksonville, Florida, the week of March 12th, 2018. It, too, should be an exciting meeting, as design discussion of Concepts resumes (with the future of AFTs possibly being settled), and the Modules TS is hopefully finalized (if that doesn’t already happen between meetings). Stay tuned for my report!

    Other Trip Reports

    Others have written reports about this meeting as well. Some that I’ve come across include Herb Sutter’s and Bryce Lelbach’s. I encourage you to check them out!

    Posted in c++, programming | Tagged , , | 10 Comments

    Featured Song: Elysium

    Recently, I’ve been flirting with progressive metal – or at least, symphonic / power metal with significant progressive influences. The more recent albums of Stratovarius (who I’ve featured several times before) – particularly the ones after guitarist Timo Tolkki’s 2008 departure from the band – fall into that category.

    Today’s selection is the title track of the 2011 album Elysium. At 18 minutes, I believe it’s the longest song I’ve featured to date – but then such is progressive rock/metal 🙂

    I listened to this album not long after its release, but it’s only after re-listening to it recently that I feel like I’ve come to truly appreciate it for the masterpiece that it is.

    The song has a bit of everything, from multiple intricate guitar and keyboard solos that typify progressive metal, through calm and contemplative sections that help build tension, to Stratovarius’ signature dramatic orchestral passages.

    In all honesty, I do find it a bit long – I think the first 11 minutes could have been condensed to ~5 without the song losing much value. Past the 11-minute mark though, the song really picks up stylistically, delivering a very emotional series of passages culminating in a climactic ending. So, if you give it a listen and start to get bored, I recommend skipping forward rather than giving up, lest you miss the best part!



    Lyrics can be found in the video description.

    Enjoy!

    Posted in featured song, music | Tagged | Leave a comment

    Trip Report: C++ Standards Meeting in Toronto, July 2017

    Summary / TL;DR

    Project What’s in it? Status
    C++17 See below Draft International Standard published; on track for final publication by end of 2017
    Filesystems TS Standard filesystem interface Part of C++17
    Library Fundamentals TS v1 optional, any, string_view and more Part of C++17
    Library Fundamentals TS v2 source code information capture and various utilities Published!
    Concepts TS Constrained templates Merged into C++20 with some modifications
    Parallelism TS v1 Parallel versions of STL algorithms Part of C++17
    Parallelism TS v2 Task blocks, library vector types and algorithms and more Under active development
    Transactional Memory TS Transaction support Published! Uncertain whether this is headed towards C++20
    Concurrency TS v1 future.then(), latches and barriers, atomic smart pointers Published! Parts of it headed for C++20
    Concurrency TS v2 See below Under active development
    Networking TS Sockets library based on Boost.ASIO Voted for publication!
    Ranges TS Range-based algorithms and views Voted for publication!
    Coroutines TS Resumable functions, based on Microsoft’s await design Voted for publication!
    Modules TS A component system to supersede the textual header file inclusion model Proposed Draft voted out for balloting by national standards bodies
    Numerics TS Various numerical facilities Under active development
    Graphics TS 2D drawing API Under active design review
    Reflection Code introspection and (later) reification mechanisms Introspection proposal passed core language and library design review; next stop is wording review. Targeting a Reflection TS.
    Contracts Preconditions, postconditions, and assertions Proposal passed core language and library design review; next stop is wording review.

    Some of the links in this blog post may not resolve until the committee’s post-meeting mailing is published. If you encounter such a link, please check back in a few days.

    Introduction

    A couple of weeks ago I attended a meeting of the ISO C++ Standards Committee (also known as WG21) in Toronto, Canada (which, incidentally, is where I’m based). This was the second committee meeting in 2017; you can find my reports on previous meetings here (November 2016, Issaquah) and here (February 2017, Kona). These reports, particularly the Kona one, provide useful context for this post.

    With the C++17 Draft International Standard (DIS) being published (and its balloting by national standards bodies currently in progress), this meeting was focused on C++20, and the various Technical Specifications (TS) we have in flight.

    What’s the status of C++17?

    From a technical point of view, C++17 is effectively done.

    Procedurally, the DIS ballot is still in progress, and will close in August. Assuming it’s successful (which is widely expected), we will be in a position to vote to publish the final standard, whose content would be the same as the DIS with possible editorial changes, at the next meeting in November. (In the unlikely event that the DIS ballot is unsuccessful, we would instead publish a revised document labelled “FDIS” (Final Draft International Standard) at the November meeting, which would need to go through one final round of balloting prior to publication. In this case the final publication would likely happen in calendar year 2018, but I think the term “C++17” is sufficiently entrenched by now that it would remain the colloquial name for the standard nonetheless.)

    C++20

    With C++17 at the DIS stage, C++20 now has a working draft and is “open for business”; to use a development analogy, C++17 has “branched”, and the standard’s “trunk” is open for new development. Indeed, several changes have been voted into the C++20 working draft at this meeting.

    Technical Specifications

    This meeting was a particularly productive one for in-progress Technical Specifications. In addition to Concepts (which had already been published previously) being merged into C++20, three TSes – Coroutines, Ranges, and Networking – passed a publication vote this week, and a fourth, Modules, was sent out for its PDTS ballot (a ballot process that allows national standards bodies to vote and comment on the proposed TS, allowing the committee to incorporate their feedback prior to sending out a revised document for publication).

    Coroutines TS

    The Coroutines TS – which contains a stackless coroutine design, sometimes called co_await after one of the keywords it uses – had just been sent out for its PDTS ballot at the previous meeting. The results were in before this meeting began – the ballot had passed, with some comments. The committee made it a priority to get through all the comments at this meeting and draft any resulting revisions, so that the revised TS could be voted for final publication, which happened (successfully) during the closing plenary session.

    Meanwhile, an independent proposal for stackful coroutines with a library-only interface is making its way through the Library groups. Attempts to unify the two varieties of coroutines into a single design seem to have been abandoned for now; the respective proposal authors maintain that the two kinds of coroutines are useful for different purposes, and could reasonably co-exist (no pun intended) in the language.

    Ranges TS

    The Ranges TS was sent out for its PDTS ballot two meetings ago, but due to the focus on C++17, the committee didn’t get through all of the resulting comments at the last meeting. That work was finished at this meeting, and this revised TS also successfully passed a publication vote.

    Networking TS

    Like the Ranges TS, the Networking TS was also sent out for its PDTS ballot two meetings ago, and resolving the ballot comments was completed at this meeting, leading to another successful publication vote.

    Modules TS

    Modules had come close to being sent out for its PDTS ballot at the previous meeting, but didn’t quite make it due to some procedural mis-communication (detailed in my previous report if you’re interested).

    Modules is kind of in an interesting state. There are two relatively mature implementations (in MSVC and Clang), whose development either preceded or was concurrent with the development of the specification. Given this state of affairs, I’ve seen the following dynamic play out several times over the past few meetings:

    • a prospective user, or someone working on a new implementation (such as the one in GCC), comes to the committee seeking clarification about what happens in a particular scenario (like this one)
    • the two existing implementers consult their respective implementations, and give different answers
    • the implementers trace the difference in outcome back to a difference in the conceptual model of Modules that they have in their mind
    • the difference in the conceptual model, once identified, is discussed and reconciled by the committee, typically in the Evolution Working Group (EWG)
    • the implementers work with the Core Working Group (CWG) to ensure the specification wording reflects the new shared understanding

    Of course, this is a desirable outcome – identifying and reconciling differences like this, and arriving at a specification that’s precise enough that someone can write a new implementation based purely on the spec, is precisely what we want out of a standards process. However, I can’t help but wonder if there isn’t a more efficient way to identify these differences – for example, by the two implementers actually studying each other’s implementations (I realize that’s complicated by the fact that one is proprietary…), or at least discussing their respective implementation strategies in depth.

    That said, Modules did make good progress at this meeting. EWG looked at several proposal changes to the spec (I summarize the technical discussion below), CWG worked diligently to polish the spec wording further, and in the end, we achieved consensus to – finally – send out Modules for its PDTS ballot!

    Parallelism TS v2

    The Parallelism TS v2 (working draft here) picked up a new feature, vector and wavefront policies. Other proposals targeting it, like vector types and algorithms, are continuing to work their way through the library groups.

    Concurrency TS v2

    SG 1, the Study Group that deals with concurrency and parallelism, reviewed several proposals targeting the Concurrency TS v2 (which still does not yet have a working draft) at this meeting, including a variant of joining_thread with cooperative cancellation, lock-free programming techniques for reclamation, and stackful coroutines (which I’ve mentioned above in connection with the Coroutines TS).

    Executors are still likely slated for a separate TS. The unified proposal presented at the last meeting has been simplified as requested, to narrow its scope to something manageable for initial standardization.

    Merging Technical Specifications Into C++20

    We have some technical specifications that are already published and haven’t been merged into C++17, and are thus candidates for merging into C++20. I already mentioned that Concepts was merged with some modifications (details below).

    Parts of the Concurrency TS are slated to be merged into C++20: latches, with barriers to hopefully follow after some design issues are ironed out, and an improved version of atomic shared pointers. future.then() is going to require some more iteration before final standardization.

    The Transactional Memory TS currently has only one implementation; the Study Group that worked on it hopes for some more implementation and usage experience prior to standardization.

    The Library Fundamentals TS v2 seems to be in good shape to be merged into C++20, though I’m not sure of the exact status / concrete plans.

    In addition to the TSes that are already published, many people are eager to see the TSes that were just published (Coroutines, Ranges, and Networking), as well as Modules, make it into C++20 too. I think it’s too early to try and predict whether they will make it. From a procedural point of view, there is enough time for all of these to complete their publication process and be merged in the C++20 timeframe. However, it will really depend on how much implementation and use experience these features get between now and the C++20 feature-complete date (sometime in 2019), and what the feedback from that experience is.

    Future Technical Specifications

    Finally, I’ll give some mention to some planned future Technical Specifications that don’t have an official project or working draft yet:

    Reflection

    A proposal for static introspection (sometimes called “reflexpr” after the keyword it uses; see its summary, design, and specification for details) continues to head towards a Reflection TS. It has been approved by SG 7 (the Reflection and Metaprogramming Study Group) and the Evolution Working Group at previous meetings. This week, it was successfully reviewed by the Library Evolution Working Group, allowing it to move on to the Core and Library groups going forward.

    Meanwhile, SG 7 is continuing to look at more forward-looking reflection and metaprogramming topics, such as a longer-term vision for metaprogramming, and a proposal for metaclasses (I talk more about these below).

    Graphics

    The Graphics TS, which proposes to standardize a set of 2D graphics primitives inspired by cairo, continues to be under active review by the Library Evolution Working Group; the latest draft spec can be found here. The proposal is close to being forwarded to the Library Working Group, but isn’t quite there yet.

    While I wasn’t present for its discussion in LEWG, I’m told that one of the changes that have been requested is to give the library a stateless interface. This matches the feedback I’ve heard from Mozilla engineers knowledgeable about graphics (and which I’ve tried to relay, albeit unsuccessfully, at a previous meeting).

    Evolution Working Group

    I’ll now write in a bit more detail about the technical discussions that took place in the Evolution Working Group, the subgroup that I sat in for the duration of the week.

    All proposals discussed in EWG at this meeting were targeting C++20 (except for Modules, where we discussed changes targeting the Modules TS). I’ve categorized them into the usual “accepted”, “further work encouraged”, and “rejected” categories:

    Accepted proposals:

    • Default member initializers for bitfields. Previously, bit-fields couldn’t have default member initializers; now they can, with the “natural” syntax, int x : 5 = 42; (brace initialization is also allowed). A disambiguation rule was added to deal with parsing ambiguities (since e.g. an = could conceivably be part of the bitfield width expression).
    • Tweaking the rules for constructor template argument deduction. At the last meeting, EWG decided that for wrapper types like tuple, copying should be preferable to wrapping; that is, something like tuple t{tuple{1, 2}}; should deduce the type of t as tuple<int, int> rather than tuple<tuple<int, int>>. However, it had been unclear whether this guidance applied to types like vector that had std::initializer_list constructors. EWG clarified that copying should indeed be preferred to wrapping for those types, too. (The paper also proposed several other tweaks to the rules, which did not gain consensus to be approved just yet; the author will come back with a revised paper for those.)
    • Resolving a language defect related to defaulted copy constructors. This was actually a proposal that I co-authored, and it was prompted by me running into this language defect in Mozilla code (it prevented the storing of an nsAutoPtr inside a std::tuple). It’s also, to date, my first proposal to be approved by EWG!
    • A simpler solution to the problem that allowing the template keyword in unqualified-ids aimed to solve. While reviewing that proposal, the Core Working Group found that the relevant lookup rules could be tweaked so as to avoid having to use the template keyword at all. The proposed rules technically change the meaning of certain existing code patterns, but only ones that are very obscure and unlikely to occur in the wild. EWG was, naturally, delighted with this simplification.
    • An attribute to mark unreachable code. This proposal aims to standardize existing practice where a point in the code that the author expects cannot be reached is marked with __builtin_unreachable() or __assume(false). The initial proposal was to make the standardized version an [[unreachable]] attribute, but based on EWG’s feedback, this was revised to be a std::unreachable() library function instead. The semantics is that if such a call is reached during execution, the behaviour is undefined. (EWG discussed at length whether this facility should be tied to the Contracts proposal. The outcome was that it should not be; since “undefined behaviour” encompasses everything, we can later change the specified behaviour to be something like “call the contract violation handler” without that being a breaking change.) The proposal was sent to LEWG, which will design the library interface more precisely, and consider the possibility of passing in a compile-time string argument for diagnostic purposes.
    • Down with typename! This paper argued that in some contexts where typename is currently required to disambiguate a name nested in a dependent scope as being a type, the compiler can actually disambiguate based on the context, and proposed removing the requirement of writing typename in such contexts. The proposal passed with flying colours. (It was, however, pointed out that the proposal prevents certain hypothetical future extensions. For example, one of the contexts in question is y in using x = y;: that can currently only be a type. However, suppose we later want to add expression aliases to C++; this proposal rules out re-using the using x = y; syntax for them.)
    • Removing throw(). Dynamic exception specifications have been deprecated since C++11 (superseded by noexcept), and removed altogether in C++17, with the exception of throw() as an alias for noexcept(true). This paper proposed removing that last vestige, too, and EWG approved it. (The paper also proposed removing some other things that were deprecated in C++17, which were rejected; I mention those in the list of rejected proposals below.)
    • Ranged-based for statement with initializer. This introduces a new form of range-for: for (T var = init; U elem : <range-expression>); here, var is a variable that lives for the duration of the loop, and can be referenced by <range-expression> (whereas elem is the usual loop variable that takes on a new value on every iteration). This is useful for both scope hygiene (it avoids polluting the enclosing scope with var) and resolving a category of lifetime issues with range-for. EWG expressed concerns about parseability (parsers will now need to perform more lookahead to determine which form of loop they are parsing) and readability (the “semicolon colon” punctuation in a loop header of this form can look deceptively like the “semicolon semicolon” punctuation in a traditional for loop), but passed the proposal anyways.
    • Some changes to the Modules TS (other proposed changes were deferred to Modules v2) – I talk about these below
    • Changes to Concepts – see below

    Proposals for which further work is encouraged:

    • Non-throwing container operations. This paper acknowledges the reality that many C++ projects are unable to or choose not to use exceptions, and proposes that standard library container types which currently rely on exceptions to report memory allocation failure, provide an alternative API that doesn’t use exceptions. Several concrete alternatives are mentioned. EWG sent this proposal to the Library Evolution Working Group to design a concrete alternative API, with the understanding that the resulting proposal will come back to EWG for review as well.
    • Efficient sized deletion for variable-sized classes. This proposal builds on the sized deletion feature added to C++14 to enable this optimization for “variable-sized classes” (that is, classes that take control of their own allocation and allocate a variable amount of extra space before or after the object itself to store extra information). EWG found the use cases motivating, but encouraged the development of a syntax that less prone to accidental misuse, as well as additional consultation with implementers to ensure that ABI is not broken.
    • Return type deduction and SFINAE. This paper proposes a special syntax for single-expression lambdas, which would also come with the semantic change that the return expression be subject to SFINAE (this is a desirable property that often leads authors to repeat the return expression, wrapped in decltype, in an explicit return type declaration (and then to devise macros to avoid the repetition)). EWG liked the goal but had parsing-related concerns about the syntax; the author was encouraged to continue exploring the syntax space to find something that’s both parseable and readable. Continued exploration of terser lambdas, whether as part of the same proposal or a separate proposal, was also encouraged. It’s worth noting that there was another proposal in the mailing (which wasn’t discussed since the author wasn’t present) that had significant overlap with this proposal; EWG observed that it might make sense to collaborate on a revised proposal in this space.
    • Default-constructible stateless lambdas. Lambdas are currently not default-constructible, but for stateless lambdas (that is, lambdas that do not capture any variables) there is no justification for this restriction, so this paper proposed removing it. EWG agreed, but suggested that they should also be made assignable. (An example of a situation where one currently runs into these restrictions is transform iterators: such iterators often aggregate the transformation function, and algorithms often default-construct or assign iterators.)
    • Product type access. Recall that structured bindings work with both tuple-like types, and structures with public members. The former expose get<>() functions to access the tuple elements by index; for the latter, structured bindings achieve such index-based access by “language magic”. This paper proposed exposing such language magic via a new syntax or library interface, so that things other than structured bindings (for example, code that wants to iterate over the public members of a structure) can take advantage of it. EWG agreed this was desirable, expressed a preference for a library interface, and sent the proposal onward to LEWG to design said interface. (Compilers will likely end up exposing intrinsics to allow library implementers to implement such an interface. I personally don’t see the advantage of doing things this way over just introducing standard language syntax, but I’m happy to get the functionality one way or the other.)
    • Changing the attack vector of constexpr_vector. At the previous meeting, implementers reported that supporting full-blown dynamic memory allocation in a constexpr context was not feasible to implement efficiently, and suggested a more limited facility, such as a special constexpr_vector container. This proposal argues that such a container would be too limiting, and suggests supporting a constexpr allocator (which can then be used with regular containers) instead. Discussion at this meeting suggested that (a) on the one hand, a constexpr allocator is no less general (and thus no easier to support) than new itself; but (b) on the other hand, more recent implementer experiments suggest that supporting new itself, with some limitations, might be feasible after all. Continued exploration of this topic was warmly encouraged.
    • Implicit evaluation of auto variables. This is a resurrection of an earlier proposal to allow a class to opt into having a conversion function of some sort called when an instance of it is assigned to an auto-typed variable. The canonical use case is an intermediate type is an expression template system, for which it’s generally desirable to trigger evaluation when initializing an auto-typed variable. EWG wasn’t fond of widening the gap between the deduction rules for auto and the deduction rules for template parameters (which is what auto is modelled on), and suggested approaching the problem form a different angle; one idea that was thrown around was the possibility of extending the notion of deduction guides (currently used for class template argument deduction) to apply to situations like this.
    • Allowing class template specializations in unrelated namespaces. The motivation here is to avoid having to reopen the namespace in which a class template was defined, to provide a specialization of that template. EWG liked the idea, but suggested that it might be prudent to still restrict such specializations to occur within associated namespaces of the specialization (e.g. the namespaces of the specialization’s template arguments) – kind of like how Rust doesn’t allow you to implement a trait unless you’re either the author of the trait, or the author of the type you’re implementing the trait for.
    • Precise semantics for contract assertions. This paper explores the design space of contract assertions, enumerating the various (sometimes contradictory) objectives we may want to achieve by using them, and proposes a set of primitive operations that facilitate implementing assertions in ways that meet useful subsets of these objectives. EWG expressed an interest in standardizing some of the proposed primitives, specifically a mechanism to deliberately introduce unspecified (nondeterministic) behaviour into a program, and a “prevent continuation handler” that an assertion check can invoke if an assertion fails and execution should not continue as a result. (A third primitive, for deliberately invoking undefined behaviour, is already handled by the independently proposed std::unreachable() function that EWG approved at this meeting.)

    Rejected proposals:

    • Attributes for structured bindings. This proposal would have allowed applying attributes to individual bindings, such as auto [a, b [[maybe_unused]], c] = f();. EWG found this change insufficiently motivated; some people also thought it was inappropriate to give individual bindings attributes when we can’t even give them types.
    • Making pointers-to-members callable. This would have allowed p(s) to be valid and equivalent to s.*p when p is a pointer to a member of a type S, and s is an object of that type. It had been proposed before, and was rejected for largely the same reason: some people argued that it was a half-baked unified call syntax proposal. (I personally thought this was a very sensible proposal – not at all like unified call syntax, which was controversial for changing name lookup rules, which this proposal didn’t do.)
    • Explicit structs. The proposal here was to allow marking a struct as explicit, which meant that all its fields had to be initialized, either by a default member initializer, by a constructor intializer, or explicitly by the caller (not relying on the fallback to default initialization) during aggregate initialization. EWG didn’t find this well enough motivated, observing that either your structure has an invariant, in which case it’s likely to be more involved than “not the default values”, or it doesn’t, in which case the default values should be fine. (Uninitialized values, which can arise for primitive types, are another matter, and can be addressed by different means, such as via the [[uninitialized]] attribute proposal.)
    • Changing the way feature-test macros are standardized. Feature test macros (like __cpp_constexpr, intended to be defined by an implementation if it supports constexpr) are currently standardized in the form of a standing document published by the committee, which is not quite a standard (for example, it does not undergo balloting by national bodies). As they have become rather popular, Microsoft proposed that they be standardized more formally; they claimed that it’s something they’d like to support, but can’t unless it’s a formal standard, because they’re trying to distance themselves from their previous habit of supporting non-standard extensions. (I didn’t quite follow the logic behind this, but I guess large companies sometimes operate in strange ways.) However, there was no consensus to change how feature test macros are standardized; some on the committee dislike them, in part because of their potential for fragmentation, and because they don’t completely remove the need for compiler version checks and such (due to bugs etc.)
    • Removing other language features deprecated in C++17. In addition to throw() (whose removal passed, as mentioned above), two other removals were proposed.
      • Out-of-line declarations of static constexpr data members. By making static constexpr data members implicitly inline, C++17 made it so that the in-line declaration which provides the value is also a definition, making an out-of-line declaration superfluous. Accordingly, the ability to write such an out-of-line declaration at all was deprecated, and was now proposed for removal in C++20.
      • Implicit generation of a copy constructor or copy assignment operator in a class with a user-defined copy assignment operator, copy constructor, or destructor. This has long been known to be a potential footgun (since generally, if you need to user-define one of these functions, you probably need to user-define all three), and C++11 already broke with this pattern by having a user-defined move operation disable implicit generation of the copy operations. The committee has long been eyeing the possibility extending this treatment to user-defined copy operations, and the paper suggested that perhaps C++20 would be the time to do so. However, the reality is that there still is a lot of code out there that relies on this implicit generation, and much of it isn’t actually buggy (though much of it is).

      Neither removal gained consensus. In each case, undeprecating them was also proposed, but that was rejected too, suggesting that the hope that these features can be removed in a future standard remains alive.

    • Capturing *this with initializer. C++17 added the ability to have a lambda capture the entire *this object by value. However, it’s still not possible to capture it by move (which may be reasonable if e.g. constructing the lambda is the last thing you do with the current object). To rectify this, this paper proposed allowing the capture of *this with the init-capture syntax. Unfortunately, this effectively allows rebinding this to refer to a completely unrelated object inside the lambda, which EWG believed would be far too confusing, and there didn’t appear to be a way to restrict the feature to only work for the intended use case of moving the current object.
    • bit_sizeof and bit_offsetof. These are similar to sizeof and offsetof, but count the number of bits, and work on bitfield members. EWG preferred to hold off on these until they are implementable with a library interface on top of reflection.
    • Parametric functions. This oddly-named proposal is really a fresh approach to named arguments. In contrast with the named arguments proposal that I co-authored a few years back, which proposed to allow using named arguments with existing functions and existing parameter names (and garnered significant opposition over concerns that it would make parameter names part of a function’s interface when the function hadn’t been written with that in mind), this paper proposed introducing a new kind of function, which can have named arguments, declared with a new syntax, and for which the parameter names are effectively part of the function’s type. While this approach does address the concerns with my proposal, EWG felt the new syntax and new language machinery it would require was disproportionate to the value of the feature. In spite of the idea’s repeated rejection, no one was under any illusion that this would be the last named arguments proposal to come in front of EWG.

    There were a handful of proposals that were not discussed due to their authors not being present. They included the other terse lambdas proposal and its offshoot idea of making forwarding less verbose, and a proposal for an [[uninitialized]] attribute.

    Concepts

    A major focus of this meeting was to achieve consensus to get Concepts into C++20. To this end, EWG spent half a day plus an evening session discussing several papers on the topic.

    Two of the proposals – a unified concept definition syntax and semantic constraint matching – were write-ups of design directions that had already been discussed and approved in Kona; their discussion at this meeting was more of a rubber-stamp. (The second paper contained a provision to require that re-declarations of a constrained template use the same syntax (e.g. you can’t have one using requires-clauses and the other using a shorthand form); this provision had some objections, just as it did in Kona, but was passed anyways.)

    EWG next looked at a small proposal to address certain syntax ambiguities; the affected scenarios involve constrained function templates with a requires-clause, where it can be ambiguous where the require-clause after the template parameter list ends, and where the function declaration itself begins. The proposed solution was to restrict the grammar for the expression allowed in a top-level requires-clause so as to remove the ambiguity; expressions that don’t fit in the restricted grammar can still be used if they are parenthesized (as in requires (expr)). This allows common forms of constraints (like trait<T>::value or trait_v<T>) to be used without parentheses, while allowing any expression with parentheses. This was also approved.

    That brings us to the controversial part of the discussion: abbreviated function templates (henceforth, “AFTs”), also called “terse templates”. To recap, AFTs are function templates declared without a template parameter list, where the parameter types use concept names (or auto), which the compiler turns into invented template parameters. A canonical example is void sort(Sortable& s);, which is a shorthand for template <Sortable S> void sort(S& s); (which is itself a shorthand for template <typename S> requires Sortable<S> void sort(S& s);).

    AFTs have been controversial since their introduction, due to their ability to make template code look like non-template code. Many have argued that this is a bad idea, beacuse template code is fundamentally different from non-template code (e.g. consider different name lookup rules, the need for syntactic disambiguators like typename, and the ability to define a function out of line). Others have argued that making generic programming (programming with templates) look more like regular programming is a good thing.

    (A related feature that shared some of the controversy around AFTs was concept introductions, which were yet another shorthand, making Mergeable{In1, In2, Out} void merge(In1, In1, In2, Out); short for template <typename In1, typename In2, typename Out> requires Mergeable<In1, In2, Out> void merge(In1, In1, In2, Out);. Concept introductions don’t make a template look like a non-template the way AFTs do, but were still controversial as many felt they were an odd syntax and offered yet another way of defining constrained function templates with relatively little gain in brevity.)

    The controversy around AFTs and concept introductions was one of the reasons the proposed merger of the Concepts TS into C++17 failed to gain consensus. Eager not to repeat this turn of events for C++20, AFTs and concept introductions were proposed for removal from Concepts, at least for the time being, with the hope that this would allow the merger of Concepts into C++20 to gain consensus. After a long and at times heated discussion, EWG approved this removal, and approved the merger of Concepts, as modified by this removal (and by the other proposals mentioned above), into C++20. As mentioned above, this merger was subsequently passed by the full committee at the end of the week, resulting in Concepts now being in the C++20 working draft!

    It’s important to note that the removal of AFTs was not a rejection of having a terse syntax for defining constrained function templates in general. There is general agreement that such a terse syntax is desirable; people just want such a syntax to come with some kind of syntactic marker that makes it clear that a function template (as opposed to a non-template function) is being declared. I fully expect that proposals for an alternative terse syntax that comes with such a syntactic marker will forthcome (in fact, I’ve already been asked for feedback on one such draft proposal), and may even be approved in the C++20 timeframe; after all, we’re still relatively early in the C++20 cycle.

    There was one snag about the removal of AFTs that happened at this meeting. In the Concepts wording, AFTs are specified using a piece of underlying language machinery called constrained type specifiers. Besides AFTs, this machinery powers some other features of Concepts, such as the ability to write ConceptName var = expr;, or even vector<auto> var = expr;. While these other features weren’t nearly as controversial as AFTs were, from a specification point of view, removing AFTs while keeping these in would have required a significant refactor of the wording that would have been difficult to accomplish by the end of the week. Since the committee wanted to “strike the iron while it’s hot” (meaning, get Concepts into C++20 while there is consensus for doing so), it was decided that for the time being, constrained type specifiers would be removed altogether. As a result, in the current C++20 working draft, things like vector<auto> var = expr; are ill-formed. However, it’s widely expected that this feature will make it back into C++20 Concepts at future meetings.

    Lastly, I’ll note that there were two proposals (one I co-authored, and a second one that didn’t make the pre-meeting mailing) concerning the semantics of constrained type specifiers. The removal of constrained type specifiers made these proposals moot, at least for the time being, so they were not discussed at this meeting. However, as people propose re-adding some of the uses of constrained type specifiers, and/or terse templates in some form, these papers will become relevant again, and I expect they will be discussed at that time.

    Modules

    Another major goal of the meeting was to send out the Modules TS for its PDTS ballot. I gave an overview of the current state of Modules above. Here, I’ll mention the Modules-related proposals that came before EWG this week:

    • Distinguishing the declaration of a module interface unit from the declaration of a module implementation unit. The current syntax is module M; for both. In Kona, a desire was expressed for interface units to have a separate syntax, and accordingly, one was proposed: export module M;. (The re-use of the export keyword here is due to the committee’s reluctance to introduce new keywords, even context-sensitive ones. module interface M; would probably have worked with interface being a keyword in this context only.) This was approved for the Modules TS.
    • Module partitions (first part of the paper only). These are module units that form part of a module interface, rather than being a complete module interface; the proposed syntax in this paper is module M [[partition]];. This proposal failed to gain consensus, not over syntax concerns, but over semantic concerns: unlike the previous module partitions proposal (which was not presented at this meeting, ostensibly for lack of time), this proposal did not provide for a way for partitions to declare dependencies on each other; rather, each partition was allowed to depend on entities declared in all other partitions, but only on their forward-declarations, which many felt was too limiting. (The corresponding implementation model was to do a quick “heuristic parse” of all partitions to gather such forward-declarations, and then do full processing of the partitions in parallel; this itself resulted in some raised eyebrows, as past experience doing “heuristic parsing” of C++ hasn’t been very promising.) Due to the controversy surrounding this topic, and not wanting to hold up the Modules TS, EWG decided to defer module partitions to Modules v2.
    • Exporting using-declarations. This wasn’t so much a proposal, as a request for clarification of the semantics. The affected scenario was discussed, and the requested clarification given; no changes to the Modules TS were deemed necessary.
    • Name clashes between private (non-exported) entities declared in different modules. Such a name clash is ill-formed (an ODR violation) according to the current spec; several people found that surprising, since one of the supposed advantages of Modules is to shield non-exported entities like private helpers from the outside world. This matter was discussed briefly, but a resolution was postponed to after the PDTS ballot (note: that’s not the same as being postponed to Modules v2; changes can be made to the Modules TS between the PDTS ballot and final publication).
    • A paper describing some requirements that a Modules proposal would need to have to be useful in evolving a particular large codebase (Bloomberg’s). Discussion revealed that the current spec meets some but not all of these requirements; the gaps mainly concern the ability to take a legacy (non-modular) code component, and non-intrusively (“additively”) provide a modular “view” of that component. No changes were proposed at this time, but some changes to fill these gaps are likely to appear as comments on the PDTS ballot.
    • Identifying module source code. Currently, the module M; or export module M; declaration that introduces a module unit is not required to be the first declaration in the file. Preceding declarations are interpreted as being part of the global module (and this is often used to e.g. include legacy headers). The author of this proposal would nonetheless like something that’s required to be the first declaration in the file, that announces “this file is a module unit”, and proposed module ; as being such a marker. EWG was favourable to the idea, but postponed discussion of a concrete syntax until after the PDTS.

    With these discussions having taken place, the committee was successful in getting Modules sent out for its PDTS ballot. This is very exciting – it’s a major milestone for Modules! At the same time, I think it’s clear from the nature of the some of the proposals being submitted on the topic (including the feedback from implementation and deployment experience at Google, some of which is yet to be fully discussed by EWG) that this is a feature where there’s still a fair amount of room for implementation convergence and user feedback to gain confidence that the feature as specified will be useful and achieve its intended objectives for a broad spectrum of C++ users. The PDTS ballot formally begins the process of collecting that feedback, which is great! I am very curious about the kinds of comments it will garner.

    If you’re interested in Modules, I encourage you to give the prototype implementations in Clang and MSVC a try, play around with them, and share your thoughts and experiences. (Formal PDTS comments can be submitted via your national standards body, but you can also provide informal feedback on the committee’s public mailing lists.)

    Other Working Groups

    The Library Working Group had a busy week, completing its wording review of the Ranges TS, Networking TS, and library components of the Coroutines TS, and allowing all three of these to be published at the end of the week. They are also in the process of reviewing papers targeting C++20 (including span, which provides an often-requested “array view” facility), Parallelism TS v2, and Library Fundamentals TS v3.

    The Library Evolution Working Group was, as usual, working through its large backlog of proposed new library features. As much as I’d love to follow this group in as much detail as I follow EWG, I can’t be in two places at once, so I can’t give a complete listing of the proposals discussed and their outcomes, but I’ll mention a few highlights:

    SG 7 (Reflection and Metaprogramming)

    SG 7 met for an evening session and discussed three topics.

    The first was an extension to the existing static reflection proposal (which is headed towards publication as the initial Reflection TS) to allow reflection of functions. Most of the discussion concerned a particular detail: whether you should be allowed to reflect over the names of a function’s parameters. It was decided that you should, but that in the case of a function with multiple declarations, the implementation is free to choose any one of them as the source of the reflected parameter names.

    The second topic was what we want metaprogramming to look like in the longer term. There was a paper exploring the design space that identified three major paradigms: type-based metaprogramming (examples: Boost.MPL, the current static reflection proposal), heterogenerous value-based (example: Boost.Hana), and homogeneous value-based (this would be based on constexpr metaprogramming, and would require some language extensions). Another paper then argued that the third one, homogeneous value-based metaprogramming, is the best choice, both from a compile-time performance perspective (the other two involve a lot of template instantiations which are compile-time expensive), and because it makes metaprogramming look more like regular programming, making it more accessible. SG 7 agreed that this is the long-term direction we should aim for. Note that this implies that, while the Reflection TS will likely be published in its current form (with its type-based interface), prior to merger into the C++ IS it would likely be revised to have a homogenerous value-based interface.

    The third topic was a proposal for a more advanced reflection/metaprogramming feature, metaclasses. Metaclasses combine reflection facilities with proposed code injection facilities to allow class definitions to undergo arbitrary user-defined compile-time transformations. A metaclass can be thought of as a “kind” or category of class; a class definition can be annotated (exact syntax TBD) to declare the class as belonging to that metaclass, and such a class definition will undergo the transformations specified in the metaclass definition. Examples of metaclasses might be “interfaces”, where the transformation includes making every method pure virtual, and “value types”, where the transformation includes generating memberwise comparison operators; widely used metaclasses could eventually become part of the standard library. Obviously, this is a very powerful feature, and the proposal is at a very early stage; many aspects, including the proposed code injection primitives (which are likely to be pursued as a separate proposal), need further development. Early feedback was generally positive, with some concerns raised about the feature allowing codebases to grow their own “dialects” of C++.

    The Velocity of C++ Evolution

    C++ standardization has accelerated since the release of C++11, with the adoption of a three-year standardization cycle, the use of Technical Specifications to gather early feedback on major new features, and an increase in overall participation and the breadth of domain areas and user communities represented in the committee.

    All the same, sometimes it feels like the C++ language is still slow to evolve, and a big part of that is the significant constraint of needing to remain backwards-compatible, as much as possible, with older versions of the language. (Minor breakages have occurred, of course, like C++11 user-defined literals changing the meaning of "literal"MACRO. But by and large, the committee has held backwards-compatibility as one of its cornerstone principles.)

    A paper, discussed at an evening session this week, explores the question of whether, in today’s age of modern tools, the committee still needs to observe this constraint as strictly as it has in the past. The paper observes that it’s already the case that upgrading to a newer compiler version typically entails making some changes / fixes to a codebase. Moreover, in cases where a language change does break or change the meaning of code, compilers have gotten pretty good at warning users about it so they can fix their code accordingly (e.g. consider clang’s -Wc++11-compat warnings). The paper argues that, perhaps, the tooling landscape has matured to the point where we should feel free to make larger breaking changes, as long as they’re of the sort that compilers can detect and warn about statically, and rely on (or even require) compilers to warn users about affected code, allowing them to make safe upgrades (tooling could potentially help with the upgrades, too, in the form of automated refactorings). This would involve more work for compiler implementers, and more work for maintainers of code when upgrading compilers, but the reward of allowing the language to shed some of its cumbersome legacy features may be worth it.

    The committee found this idea intriguing. No change in policy was made at this time, but further exploration of the topic was very much encouraged.

    If the committee does end up going down this path, one particularly interesting implication would be about the future of the standard library. The Concepts-enabled algorithms in the Ranges TS are not fully backwards-compatible with the algorithms in the current standard library. As a result, when the topic of how to merge the Ranges TS into the C++ standard came up, the best idea people had was to start an “STLv2”, a new version of the standard library that makes a clean break from the current version, while being standardized alongside it. However, in a world where we are not bound to strict backwards-compatibility, that may not be necessary – we may just be able to merge the Ranges TS into the current standard library, and live with the resulting (relatively small) amount of breakage to existing code.

    Conclusion

    With C++17 effectively done, the committee had a productive meeting working on C++20 and advancing Technical Specifications like Modules and Coroutines.

    The merger of Concepts into C++20 was a definite highlight of this meeting – this feature has been long in the making, having almost made C++11, and its final arrival is worth celebrating. Sending out Modules for its PDTS ballot was a close second, as it allows us to start collecting formal feedback on this very important C++ feature. And there are many other goodies in the pipeline: Ranges, Networking, Coroutines, contracts, reflection, graphics, and many more.

    The next meeting of the Committee will be in Albuquerque, New Mexico, the week of November 6th, 2017. Stay tuned for my report!

    Other Trip Reports

    Others have written reports about this meeting as well. Some that I’ve come across include Herb Sutter’s and Guy Davidson’s. Michael Wong also has a report written just before the meeting, that covers concurrency-related topics in more depth than my reports. I encourage you to check them out!

    Posted in c++, programming | Tagged , , | 16 Comments

    Featured Song: Misery Is a Butterfly

    It’s been a while since I wrote a Featured Song post. Today, I’m going to share a song from a band I’ve discovered in recent months, Blonde Redhead.

    A small band with just three members (none of whom, incidentally, is blonde or a redhead 🙂 ), their music has a unique sound and a contemplative atmosphere that I’ve taken to.

    I particularly enjoy lead singer Kazu Makino‘s thin, clear high voice which gives the band’s sound an almost ethereal twist. She also has really good stage presence (check out some live recordings of the band).

    The song I’m featuring today – my favourite of the Blonde Redhead songs I’ve heard so far – is the title track of their 2004 album Misery Is a Butterfly:



    Featured lyrics:

    Remember when we found misery
    We watched her, watched her spread her wings
    And slowly fly around our room
    And she asked for your gentle mind

    Full lyrics and discussion can be found here.

    I’d also like to share a beautiful instrumental (piano and cello) cover of this song that I’ve come across:



    Hope you’ve enjoyed them!

    Posted in featured song, music | Leave a comment

    Trip Report: C++ Standards Meeting in Kona, February 2017

    Summary / TL;DR

    Project What’s in it? Status
    C++17 See below Draft International Standard published; on track for final publication by end of 2017
    Filesystems TS Standard filesystem interface Part of C++17
    Library Fundamentals TS v1 optional, any, string_view and more Part of C++17
    Library Fundamentals TS v2 source code information capture and various utilities Published!
    Concepts (“Lite”) TS Constrained templates Published! Not part of C++17
    Parallelism TS v1 Parallel versions of STL algorithms Part of C++17
    Parallelism TS v2 Task blocks, library vector types and algorithms and more Under active development
    Transactional Memory TS Transaction support Published! Not part of C++17
    Concurrency TS v1 future.then(), latches and barriers, atomic smart pointers Published! Not part of C++17
    Concurrency TS v2 See below Under active development
    Networking TS Sockets library based on Boost.ASIO Resolution of comments on Preliminary Draft in progress
    Ranges TS Range-based algorithms and views Resolution of comments on Preliminary Draft in progress
    Numerics TS Various numerical facilities Under active development
    Modules TS A component system to supersede the textual header file inclusion model First version based largely on Microsoft’s design; hope to vote out Preliminary Draft at next meeting
    Graphics TS 2D drawing API Under active design review
    Coroutines TS Resumable functions, based on Microsoft’s await design Preliminary Draft voted out for balloting by national standards bodies
    Reflection Code introspection and (later) reification mechanisms Introspection proposal passed core language design review; next stop is design review of the library components. Targeting a Reflection TS.
    Contracts Preconditions, postconditions, and assertions Proposal passed core language design review; next stop is design review of the library components. Targeting C++20.

    Introduction

    A few weeks ago I attended a meeting of the ISO C++ Standards Committee (also known as WG21) in Kona, Hawaii. This was the first committee meeting in 2017; you can find my reports on 2016’s meetings here (February 2016, Jacksonville), here (June 2016, Oulu), and here (November 2016, Issaquah). These reports, particularly the Issaquah one, provide useful context for this post.

    This meeting was focused on wrapping up C++17, iterating on the various in-progress Technical Specifications (TS), and picking up steam on C++20.

    As I described in my previous report, at the end of the Oulu meeting, the C++17 Committee Draft (CD) – a first feature-complete draft of the C++17 spec – was sent out for comment from national standards bodies, and the comment period concluded prior to the Issaquah meeting, which was then heavily focused on addressing the resulting comments.

    The aim for this meeting was to resolve the remaining comments, and – thanks to a lot of hard work, particularly from the Library groups which were swamped with a large number of comments to address – we were successful in doing so. At the end of the meeting, a revised draft of the C++17 standard, with the comments addressed – now labelled Draft International Standard (DIS) – was sent out for a second round of voting and comments.

    As per ISO procedure, if the DIS vote is successful, the committee can proceed to final publication of C++17 (possibly with further modifications to address DIS comments) without a further round of voting and comments; this was the case for C++14, and it is hoped to be the case again for C++17.

    C++17

    Since at the CD stage, C++17 is supposed to be feature-complete, no new features were voted into C++17 at this meeting (see this for a list of features in C++17). The only things that were voted in were minor changes to resolve CD comments. I call out some of the notable ones below:

    Changes voted into C++17 at this meeting

    C++20

    With C++17 being wrapped up with final comment resolutions, sights are increasingly set on the next release of the language’s International Standard (IS), C++20.

    C++20 doesn’t have a working draft yet (it can’t per ISO procedure until C++17 is published), but a number of features targeted for it have already passed design review (see my previous posts for details), and many more are in the queue.

    Notably, at this meeting, in addition to discussing individual proposals targeted for C++20, a plan for an overall direction / set of primary goals for C++20 was also discussed. The discussion was prompted by a paper in the pre-meeting mailing outlining such a proposed vision, which was discussed during an evening session on Thursday.

    This paper suggests that we aim to get the following major features into C++20:

    • Concepts
    • Modules
    • Ranges
    • Networking

    It does not suggest focusing on these features to the exclusion of others, but does propose prioritizing these over others. The reasoning for why these features merit special attention is well-argued in the paper; read it for details.

    It’s worth noting that each of these features is first being standardized in the form of a Technical Specification, and these are at various stages of publication (Concepts is published; Ranges and Networking have had Preliminary Drafts published and comments on them are in the process of being addressed; for Modules, we hope to publish a Preliminary Draft at the next meeting). Getting these features into C++20 will require promptly completing the TS publication in cases where it’s not there yet, and then merging the TS’s into C++20.

    The proposal for focusing on these four was received favourably by the committee. It is very important to note that this should not be construed as a promise to get these features into C++20; the committee isn’t in a position to make such a promise ahead of time, nor is anyone on it. As always, a feature only goes into the IS wen it’s ready – that is, when the committee has a high confidence in the design, its specification, its implementability, the interaction of the feature with other language and library features, and the appropriateness of the feature for standardization in the context of the language as a whole. We will work hard to get these features into C++20, but there are no promises.

    Technical Specifications

    The committee has a number of Technical Specifications in flight, and others in the planning stage. I’ll mention the status of each.

    Recapping the procedure for publishing a Technical Specification:

    • Once it has completed design and wording review and is considered to be in good enough shape, a Preliminary Draft Technical Specification (PDTS) is published, and sent out for comment by national standards bodies.
    • The comments are reviewed and addressed
    • The revised Technical Specification is sent out for final publication. (Optionally, if the committee believes the TS is not ready for publication and needs a second round of comments, it can publish a Draft Technical Specification (DTS) and send it out for comment, and only subsequently publish the final TS. However, this generally hasn’t been necessary.)

    At this meeting, the Coroutines TS was sent out for its PDTS ballot. The Modules TS came close, but didn’t quite make it.

    Ranges TS

    The Ranges TS was sent out for its PDTS ballot at the end of the last meeting. The ballot comments have since come back, and the library groups have been busy addressing them, resulting in a few changes to the working draft being approved. With the focus being on the C++17 CD comments, however, not all comments have been addressed yet, and the TS is not yet ready for final publication.

    Networking TS

    The Networking TS was also sent out for its PDTS ballot at the end of the last meeting and, as with the Ranges TS, the ballot comments have come back. The library groups did not have much time to spend on addressing the comments (due to the C++17 focus), so that work will continue at the next meeting.

    Coroutines TS

    The Coroutines TS – which contains the “stackless coroutines” / co_await proposal based on Microsoft’s design – was approved to be sent out for its PDTS ballot at this meeting. (This was attempted at the last meeting, but it was voted down on the basis that there had not been time for a sufficiently thorough review of the core language wording. Such review has since taken place, so it sailed through this time.)

    As mentioned in my previous posts, there are also efforts underway to standardize a different, stackful flavour of coroutines (the latest iteration of that proposal suggests a library interface similar to the call/cc facility found in some functional languages), and a proposal to unify the two flavours (this latter seems to be stalled after a discussion of it at the last meeting convinced some people that unification is not worth it).

    These alternative proposals are progressing (or not) independently of the Coroutines TS for the time being. Depending on how they progress, they may still have an impact on the form(s) in which coroutines are ultimately standardized in the C++ IS.

    Concepts TS

    The Concepts TS was published in late 2015, and is now being eyed for merger into C++20.

    Recall that the purpose of standardizing a feature as a Technical Specification first, is to give implementers and users the ability to gain experience with the feature, and provide feedback that may motivate changes to the feature, before standardizing it in its final form.

    Now that the Concepts TS has been published for a while, and a compiler that supports it (GCC 6) released almost a year ago, user and implementer feedback (the latter primarily from developers working on an implementation in Clang) has started trickling in.

    (There was previously an attempt to merge the Concepts TS into C++17, which failed because at that point, the amount of user and implementer feedback had been small, and the committee felt people should have more time to try the feature out.)

    The feedback so far has generated a few proposals for changes to the Concepts TS (P0342, P0464, and P0587). Some of these were looked at this week; I summarize the technical discussion below, but the high-level summary is that, while people agree on the general direction of some changes, other proposed changes remain rather controversial.

    One thing that’s not controversial, is that everyone wants Concepts to make it into C++20. Procedurally, the question arose whether we should (1) merge the TS into the IS now, and treat remaining points of contention as “issues” to be tracked and resolved before the publication of C++20; or (2) resolve the issues in the Concepts TS working draft, and only then merge the result into C++20. A proposal to take route #1 (merge now) failed to gain consensus in the Evolution Working Group (EWG), so for now, the plan is to take approach #2 (resolve issues first, merge after).

    Modules TS

    Modules currently has two implementations – one in MSVC, and one in Clang – which diverge in some aspects of their conceptual and implementation models. Most notably, the Clang implementation includes macros in the set of entitites that can be exported by one module and imported by another, while the MSVC one does not.

    At the October 2015 meeting (which, as it happens, was also in Kona), it was decided that, since supporting macros is both contentious and comes with significant implementation complexity, Modules will initially be pursued in the form of a Technical Specification that does not support macros, and macro support can be considered for a second iteration of the feature (which I’ll henceforth refer to as “Modules v2”; the ship vehicle for that is still to be determined – it might be a second Modules TS, or it might be C++20).

    Accordingly, the current Modules TS working draft largely reflects Microsoft’s design.

    Meanwhile, the Clang implementers have submitted a proposal for design changes that includes adding support for macros among other, smaller changes. EWG looked at parts of this proposal at the February 2016 meeting in Jacksonville, and some of the smaller changes gained the group’s consensus at that time.

    However, it appears that there was some confusion as to whether those changes were intended for Modules v1, or v2. Since one of the proposals in the paper was adding macro support, a feature previously earmarked for v2, some people assumed the entire paper was v2 material. Other people had understood that the smaller changes that were approved, were approved for v1.

    This misunderstanding came to light when the Modules TS (v1) working draft (which does not contain the mentioned changes) came up for a vote in full committee to be sent out for its PDTS ballot. The vote failed, and the matter referred back to EWG to clarify whether the changes in question are in fact approved for v1 or not.

    EWG ended up effectively re-discussing the proposed changes (since during the first discussion, it wasn’t clear whether people were considering the changes for v1 or v2), with the outcome being that some but not all of them had consensus to go into v1 (I summarize the technical discussion below).

    The hope is that Modules v1, as amended with these approved changes, can be sent out for its PDTS ballot at the next meeting (this July, in Toronto).

    Parallelism TS v2

    Not too much new to report for Parallelism TS v2. Task blocks are already in the working draft, while vector types and algorithms are still working their way through the library groups.

    Concurrency TS v2

    The Concurrency TS v2 does not have a working draft yet. New proposals being considered for it include an RAII interface for deferreed reclamation, hazard pointers, an RCU API, and padding bits for compare-and-excahnge. The concurrent queues proposal has been approved by SG1 (the Study Group that deals with concurrency) and forwarded to the library groups for review.

    Executors, probably slated for a separate TS at this point, have a unified proposal, an updated version of which was discussed in SG1. One of the reasons executors are taking so long to standardize is that different communities want them for different use cases, and accommodating all of them adds significant complexity to any proposal. It is likely that the initial version to be standardized will be restricted to a smaller feature set.

    Future Technical Specifications

    Several future Technical Specifications are planned as well.

    Reflection

    The Reflection Study Group (SG 7) approved a proposal for static introspection (summary, design, specification) at the last meeting. This week, the Evolution Working Group looked at it and approved it as well; they also agreed with the decision to start by standardizing the proposal as a TS. The next stop for the proposal is the Library Evolution Working Group.

    There were some proposals in the latest mailing that aimed to change aspects of the introspection proposal – not core aspects like “what can be reflected”, but more like “how does the reflection facility integrate into the language”, such as the proposal to reflect through values instead of types. These proposals will be given due consideration (and SG 7 started looking at them this meeting; I summarize the discussion below), but in the meantime, the introspection TS will go forward as-is, so that valuable implementer and user feedback can be collected on the core aspects of the proposal as soon as possible. Changes such as reflecting through values can then be made post-TS.

    Numerics

    As previously outlined, the Numerics Study Group (SG 6) plans to put out a Numerics TS containing various facilities (summarized here). SG 6 met for two days this week, primarily to work on the TS; the group’s chair hopes that an initial working draft for the TS, to be edited collaboratively over Github, will be ready for the next meeting.

    SG 6 also approved some library features related to bitwise operations (P0237, P0553, P0556) that are not slated for the Numerics TS, but will go directly into C++20 (or the latest version of the Library Fundamentals TS, at LEWG’s choosing).

    Graphics

    The Graphics TS, which proposes to standardize a set of 2D graphics primitives inspired by cairo, has updated wording that addresses issues raised during a previous round of design review. The Library Evolution Working Group looked at the updated proposal this week, and suggested one more round of changes; the hope is to forward the proposal to the Library Working Group (which will then review it at the wording level) at the next meeting.

    Evolution Working Group

    I sat in the Evolution Working Group (EWG) for the duration of the meeting, so in addition to the general overview I gave above, I can go in more details about the technical discussion that took place in that group.

    To recap, EWG spends its time evaluating and reviewing the design of proposed language features. This week, it briefly addressed some remaining C++17 issues, and then spent rest of the week on post-C++17 material (such as C++20, and Technical Specifications like the Modules TS).

    C++17 Topics

    • National body comments on the C++17 CD remaining to be addressed. (Note that the comments can be found in two documents: official comments, and late comments)
      • constexpr static members of enclosing class type (US 24). EWG looked at this at the last meeting, and said this extension would be considered for C++17 if the details were worked out in a paper. As no such paper appeared at this meeting, the extension was now rejected for C++17. It could come back in a later standard.
      • When are get<>() functions called in decomposition declarations? (Late 3). The current wording says that they are called “eagerly”, at the point of decomposition. At the last meeting, EWG was in favour of changing that to “lazily”, that is, being called at the point of use of the decomposed bindings, but this change too required a paper. Again no such paper appeared, and moreover the comment author said that, upon contemplation, it seems like a tricky change to make, and probably not worth it, so the “lazy” idea was abandoned.
      • Should library implementers have the freedom to add constexpr to library functions where the standard doesn’t specify it? (GB 38). This was proposed for previous standards but rejected, mainly because of portability concerns (library functions that the standard didn’t specify to be constexpr still couldn’t be portably used in contexts that require constant expressions, such as array bounds). It was now requested again for C++17; however, the idea still didn’t have EWG’s consensus. There is some hope it may yet in C++20.
    • Terminology: “structured bindings” vs. “decomposition declarations”. The ability to decompose a tuple-like object into its constituent parts, as in auto [a, b, c] = foo(); , was called “structured bindings” during design discussions, but the wording in the standard refers to declarations of this form as “decomposition declarations”. To avoid confusion stemming from having two names for the same thing, “decomposition declarations” were renamed to “structured binding declarations”.
    • Class template argument deduction
      • There was some discussion of whether implicit deduction guides should be kept. The consensus was that most of the time they do the right thing (the exceptions typically being classes whose constructors involve a lot of metaprogramming, like std::tuple) and they should be kept.
      • Copying vs. wrapping behaviour. Suppose a is a variable of type tuple<int, int>, and we write tuple b{a};. Should the type of b be tuple<int, int> (the “copying” behaviour), or tuple<tuple<int, int>> (the “wrapping” behaviour)? This question arises for any wrapper-like type (such as pair, tuple, or optional) which has both a copy constructor and a constructor that takes an object of the type being wrapped. EWG felt copying was the best default. There was some talk of making the behaviour dependent on the syntax of the initialization (e.g. the { } syntax should always wrap) but EWG felt introducing new inconsistencies between the behaviours of different initialization syntaxes would do more harm than good.
      • Whether you should be able to define explicit deduction guides as deleted. EWG agreed that this is useful, but for practical reasons (being so late in the C++17 cycle), the relevant wording will be placed into a Defect Report applicable to C++17 rather than into the C++17 draft itself.
    • std::launder() is a library function with special behaviour that was added to C++17 to allow certain patterns of code (which arise, for example, in typical implementations of std::variant), to have well-defined behaviour without excessively constraining compiler optimizations such as devirtualization. At this meeting, a proposal to achieve the same goal via different means (no library function, just changes to core language wording) was put forward. However, during discussion it came to light that the proposed alternative would not handle all affected scenarios (particularly scenarios where vtable pointers are in play), and it did not gain consensus.

    Post-C++17 Proposals

    Here are the post-C++17 features that EWG looked at, categorized into the usual “accepted”, “further work encouraged”, and “rejected” categories:

    Accepted proposals:

    • Allowing attributes on template instantiations. C++ allows many entities in the program (such as variables, types, and functions) to be annotated with attributes, but explicit template instantiations are not one of them. Annotating explicit instantiations turns out to be useful, particular for visibility attributes, so this ability was added. Since this is more an oversight in the initial specification of attributes than a new feature, in addition to being in C++20, it will be published as a Defect Report potentially applying as far back as C++11.
    • Simplifying implicit lambda capture. This proposal simplifies the specified procedure for determining whether a variable referenced inside the body of a lambda with a capture-default, is captured by the lambda. The main motivation is that the current procedure trips up in some scenarios involving if constexpr. The user impact should be limited to allowing those previously-problematic cases. (In theory, the change could result in lambdas notionally capturing some variables that they don’t strictly need to and didn’t capture before, but optimizers should be pretty effective in optimizing such captures out.)
    • Consistent comparisons. EWG looked at various proposals for default comparisons at the last meeting, and the consensus that emerged was that (1) we want a three-way comparison operator; (2) two-way comparison operators should be “desugared” to the three-way comparison operator; (3) most classes should only need to define the three-way comparison operator, and the language could provide some help in doing that.

      This paper formalizes that consensus into a proposal. The three-way comparison operator is spelt <=> (the “spaceship operator”), and the compiler can generate a default implementation if one is declared as = default. In addition, the proposal supports the notion of different strengths of ordering by making the return type of the spaceship operator be one of std::strong_ordering, std::weak_ordering, or std::partial_ordering, which are enumeration-like types (though not actual enumerations) with appropriate conversions between them; it also supports the notion of types that can be compared for equality but are not ordered, for which the spaceship operator would return std::strong_equality or std::weak_equality.

      EWG passed the above parts of the paper; they will now go to LEWG for library review, and CWG for core language wording review. The paper also contained an optional extension, where some user-defined types would get the spaceship operator auto-generated for them without even a defaulted declaration (similar to the previous default comparison proposal that almost made it into C++17). This extension did not gain EWG’s consensus at this time, although it may come back in revised form.

      (The paper also contained an extension to support chaining comparisons, that is, to let things like a == b == c have the meaning of (a == b) && (b == c) that was likely intended. This also didn’t gain consensus, though it could also come back after some compatibility analysis is performed to determine how much existing code it would break.)
    • Static reflection. This is the proposal that the Reflection Study Group approved at the last meeting. EWG approved this without asking for any design changes; it concurred with the Study Group’s opinion that the ship vehicle should be a Reflection TS (as opposed to, say, C++20), and that standardization of the proposal as written should proceed in parallel with alternative syntaxes being contemplated. The next stop for this proposal is the Library Evolution Working Group; bikeshedding of the reflection operator’s spelling (the latest draft of the paper contains $reflect, while previous ones contained reflexpr) will take place there.
    • Implicit moving from rvalue references in return statements. This proposal argues that in a function return statement, you practically always want to move from an rvalue reference rather than copying from it, and therefore the language should just implicitly move for you instead of requiring you to write std::move. Code that would break as a result of this change is almost certainly wrong to begin with.
    • Contracts. This is a refinement of the proposal for contract checking that was approved at previous meeting.

      There was one point of controversy, concerning the use of an attribute-like syntax. Some people found this objectionable on the basis that attributes are not supposed to have semantic effects. Others pointed out that, in a correct program, the contract attributes do not, in fact, have a semantic effect. Of particular concern was the “always” checking level specified in the proposal, which allows marking specific contract checks as being always performed, even if the program-wide contract checking level is set of “off“; it was argued that this means a conforming implementation cannot ignore contract attributes the way it can ignore other attributes.

      To resolve this concern, options such as using a different (non-attribute) syntax, or removing the “always” checking level, were considered. However, neither of these had stronger consensus than the proposal as written, so the proposal was sent onwards to the Library Evolution Working Group without changes.
    • short float. This is what it sounds like: a shorter floating-point type, expected to be 16 bits long on most platforms, to complement the typically 32-bit float and 64-bit double.

    Proposals for which further work is encouraged:

    • Proposed changes to the Concepts TS. I talk about this below.
    • Abbreviated lambdas for fun and profit. This is really five separable proposals to abbreviate the syntax of lambdas further. All but the first one were rejected.
      • A terser syntax for single-expression lambdas (that is, lambdas whose body consists of a single return statement). This has been desired for a long time; the general idea is to eliminate the braces and the return keyword in this case. The problem is that just putting the expression after the lambda-introducer and optional parameter list leads to ambiguities. This paper proposes writing => expr; EWG encouraged thinking about more options.
      • Allow introducing parameters without a type specifier (that is, not even auto or auto&&). The problem with the naive approach here is that it’s ambiguous with the case where a parameter has a type specifier but no name. The paper proposes several possible solutions; EWG found them inelegant, and more generally felt that this problem space has already been explored without much fruit.
      • A way to request that SFINAE apply to a lambda’s deduced return type. The motivation for this is similar to that of a similar proposal along these lines. This idea had some support, but not consensus.
      • A way to request a deduced noexcept-specification. As with the earlier noexcept(auto) proposal, EWG did not find this sufficiently motivated.
      • A way to request that arguments to the lambda be automatically forwarded (in the std::forward<Type>(value) sense) in the body expression. EWG agreed that having to litter generic code with calls to std::forward is unfortunate, but felt that a solution to this problem should not be specific to lambdas.
    • std::call_cc() stackful context switching. This is an updated version of the earlier stackful coroutines proposal, with the library interface changed from std::execution_context (whose name clashed with a different type of “execution contexts” in the unified executors proposal) to std::continuation and std::call_cc(), names that some might recognize from Scheme and other functional languages. EWG looked at this in joint session with the Concurrency Study Group. The main purpose of the discussion was to determine whether the proposed interface is at the right level of abstraction for standardization. There wasn’t much consensus on this topic, with some liking the interface as written, others arguing for a lower-level interface (think ucontext), and yet others for a higher-level interface (think fibres). Interested parties will continue iterating on this proposal in a smaller group.
    • Attributes for likely and unlikely branches. When this proposal was first looked at (at the last meeting), the feedback was that instead of trying to place the attributes onto the conditions of branches themselves, they should be placed on the statement(s) that are being described as likely/unlikely to be reached. In this revision, the proposal author did that, but attempted to restrict the contexts in which such an attribute could be placed on a statement. EWG suggested allowing it on all statements instead, while also requesting that examples be added to clarify the semantics in a various scenarios.
    • An updated version of for loop exit strategies, which proposes to allow adding blocks of code at the end of a for loop that run when the loop exits by breaking (introduced by the keyword on_break), and when the loop runs to completion (introduced by on_complete). The only thing that has changed since the last revision of this proposal is the keywords – they were catch break and catch default in the previous version. EWG didn’t love the new keywords, either, and was generally lukewarm towards the proposal in terms of motivation, so it’s not clear if this is going anywhere.
    • Generalized unpacking and parameter pack slicing. This proposes a prefix slicing syntax: if T is a parameter pack, [N]T would denote the element at the Nth index of T; [N:M]T would denote a new parameter pack containing the elements from the Nth to the Mth indices of T. Additionally, the syntax can be applied to objects of any product type (roughly, a type that can be decomposed using structured bindings), in which case the object is considered to be a pack of its consituent objects (this is the “generalized unpacking” part, because it gives us a way to unpack product types into parameter packs using a simple syntax). EWG liked the goals, but felt that a proposal like this should be part of a global unified vision for metaprogramming. The proposal was sent to the Reflection Study Group, whose responsibilities going forward will include metaprogramming more generally, and which will consider it alongside other metaprogramming proposals.
      • It’s worth noting that there was another proposal on this topic in the pre-meeting mailing, that aimed to solve the problem by introducing a new type of expression resembling a for loop that would generate a parameter pack procedurally. It wasn’t presented because no one was available to champion it.
    • The Concurrency Study Group is working on SIMD support, and they consulted EWG on how that support should integrate with the type system. In particular, if a function has multiple SIMD variants, should they have different function types, potentially opening the door to overloading? This was the approach taken in the Transactional Memory TS (with transaction-safe and non-transaction-safe variants of a function). EWG discouraged further proliferation of this paradigm.
    • The constexpr operator. This is a facility that tells you whether or not you are executing a function in a constant expression context or not; it allows you to have different implementations for compile-time and runtime evaluation. EWG liked the idea, although the exact syntax remains to be nailed down. In addition, desire was expressed for a way to enforce that a constexpr function is only invoked at compile time.
    • constexpr_assert and constexpr_trace. These are proposed tools for debugging constexpr code, that allow you to direct the compiler to produce diagnostic/debugging output while performing constexpr evaluation. The idea was generally favourably received, though it was noted that for constexpr_trace, rather than having it produce output unconditionally, it would be useful to have a mechanism where it can accumulate output into a buffer, and then flush the buffer only if something goes wrong.
    • std::constexpr_vector<T>. The scope of what is allowed in constexpr functions has been steadily increasing, and it might seem that the logical next frontier is dynamic memory allocation. However, at least one implementer has performed extensive experimentation with allowing dynamic memory allocation in constexpr evaluation, and found that it could only be done at a drastic performance penalty. The reason is that the compiler is required to diagnose what would be undefined behaviour if it happens at runtime, during constexpr evaluation, and dynamic memory allocation opens up so many avenues to invoking undefined behaviour that the compiler needs extensive instrumentation to diagnose it. This proposal is an alternative to allowing full-blown dynamic allocation, that provides a specific, “magic”, vector-like type for use during constexpr evaluation, that should satisfy the large majority of use cases. EWG encouraged further exploration of this space.
    • Tuple-based for loops. This is an extension of range-based for loops to tuple-like types. Tuple-like types can be thought of as heterogeneous ranges (ranges whose elements are of different types), where the total number of elements and their types are known at compile time. Accordingly, a tuple-based for loop would be unrolled at compile time, and its body instantiated once for each element type. This gives rise to a simple and convenient syntax for processing tuple-like types, which has been desired for a long time (see e.g. the Boost.Fusion library). Concerns with this specific proposal included performance considerations (for example, it makes it very easy to write innocent-looking code that triggers a lot of template instantiations and is expensive to compile), and the fact that it didn’t generalize to some use cases (such as cases where you want the type of a result to depend on logic in your “loop”). Further exploration of the topic was encouraged.
    • Range-based for loop with initializer. This extends the C++17 selection statements with initializer feature to range-based for loops, allowing you to declare a variable “alongside” your iteration variable that is scoped to the loop and will live as long as the loop. In addition to facilitating better scoping hygiene (that is, making the scopes of variables as tight as possible), it provides a way to resolve a long-standing lifetime issue with range-based for loops. EWG requested that the author implement the proposal, and then bring it back, at which point, if no issues arise during implementation, approval is expected.
    • bit_sizeof and bit_offsetof. These are equivalents of the sizeof and offsetof operators (the latter is actually a macro) that return counts of bits, and are usable on bitfield members. EWG referred this proposal to the Reflection Study Group, as it may be implementable as a library on top of forthcoming reflection primitives.
    • Proposed changes to the Modules TS. I talk about this below.

    Rejected proposals:

    • Implicit and anonymous return types. This proposed to allow declaring an anonymous structure in the return type of a function, as a way to allow it to return multiple named values (contrast with a tuple, which allows you to return multiple values but they are unnamed), without having to define a named structure in an enclosing scope. To facilitate out-of-line definitions for such functions, it also proposed using decltype(return) to denote “the previously declared return type” (since repeating the anonymous structure declaration in the function’s definition would both be repetitive, and, according to the current language rules, actually declare a second, distinct anonymous structure type). Besides being unconvinced about the motivation (viewing the alternatives of named structured and tuples as good enough), people pointed out various technical difficulties with the proposal. decltype(return), in particular, would further complicate C++’s function redeclaration rules, and introduce potential ambiguities and situations where a definition using decltype(return) could be well-formed or not depending on what other functions have declarations visible.
    • Initialization list symmetry. This tiny proposal would have allowed a trailing comma on the last element of a constructor’s initializer list (properly called a constructor-chain-initializer), to make member reordering and other refactorings easier. It was rejected on the basis that in C++ a comma is a separator, not a terminator, and it would be strange to allow it in a trailing position in this context but not other contexts (like function parameters, function arguments, or template arguments). It’s worth noting that C++ does already allow trailing commas in a few places, like enumerations and array initializers.
    • A qualified replacement for #pragma once. The proposal here is to standardize a variant of the widely supported #pragma once extension, spelt #once, which took an identifier and optional version as argument, and used them to solve #pragma once‘s longstanding problem of having to figure out whether two files are the same (which can sometimes be tricky in situations involving symbolic links and such). EWG felt that Modules would obsolete this feature, and as such it was not worth standardizing at this stage.

    Concepts

    This meeting marked the first significant design discussion about Concepts in EWG since a proposal to merge the Concepts TS into C++17 without modifications failed at the February 2016 meeting in Jacksonville.

    The main topic of discussion was the Concepts TS revisited paper which proposed several design changes to Concepts:

    • Unifying function-like and variable-like concepts into a single concept definition syntax, as previously proposed. The unified syntax would drop the redundant bool keyword from concept bool, and the entities it would declare would be a kind unto their own, not variables or functions. The question of whether such entities can overload on the number and kinds of their template parameters (the original motivation for having function-like concepts) remains open, though it seems people are leaning towards not allowing overloading, arguing that if you have two concepts taking a different number or kind of template parameters, it’s probably clearer to give them different names (a canonical example is EqualityComparable<T> vs. EqualityComparableTo<T, U>; the latter becomes EqualityComparableTo<U> T in a constrained-parameter declaration, which reads very naturally: T must be of a type that’s equality-comparable to U). EWG encouraged continued exploration of this unification.
    • Changes to the redeclaration rules for constrained function templates. The Concepts TS provides multiple ways to express the same constrained function template. Currently, for purposes of determining whether two declarations declare the same function template, the shorthand forms are “desugared” to the long form (using requires-clauses only), and the usual redeclaration rules (which require token-for-token equivalence) are applied to the result. This means that e.g. a function template declared using the long form can be re-declared using one of the shorthand forms. The paper argued that this is brittle (among other things, it requires specifying the desugaring at the token level), and proposed requiring that redeclarations be token-for-token equivalent before desugaring. After extensive discussion, EWG was supportive of this change.
    • A minor change to the concept subsumption rules (that come into play during partial ordering of constrained function templates) where, for the purpose of determining whether two constraints are equivalent, the compiler does not “look into” atomic constraints and determine equivalence textually; two constraints are only equivalent if they refer to the same concept. This also garnered support.
    • Addressing the issue that subsumption checking can sometimes be expontential-time in the presence of disjunctions. The paper proposes addressing this by removing disjunctions, and instead introducing an explicit syntax for declaring concept refinement relationships, but the authors have since withdrawn that proposal, in part because it was quite controversial. It was pointed out that the previous change (not “looking into” atomic constraints during subsumption checking) will significantly alleviate the problem by reducing how often we run into the expontential case.
    • Modifying the abbreviated function template syntax to make it clear to readers that the function being declared is a template. Currently, the Concepts TS allowed an “abbreviated” syntax like void foo(Sortable& s); which declares a function template if Sortable is a concept. Many members of the committee and the larger C++ community expressed concern about having a template look exactly like a non-template, discriminated only by the result of name lookup on the argument types.

      EWG had a vigorous debate on this topic. On the one hand, people argued that templates and non-templates are fundamentally different entities, due to differences like the way name lookup works inside each, requiring typename in some contexts inside templates, and so on. Countering this, others argued that these differences are relatively minor, and that the long-term aim should be to make generic programming (programming with templates) be just like regular programming.

      One argument I found particularly interesting was: instead of having syntax to discriminate between templates and non-templates, why don’t we rely on tooling, such as having concept names syntax-colored differently from type names? I found this fairly convincing: since we are designing modern language features, it seems reasonable to design them with modern tools in mind. Then again, while many editors are capable of performing the sort of semantic highlighting contemplated here, programmers also spend a lot of time looking at code in non-editor contexts, such as in review tools, and I’ve yet to see one of those with semantic highlighting (although such a thing is conceivable).

      EWG did not reach a consensus on this topic. Several concrete proposals for syntax that would alert readers to the template-ness of an abbreviated function template were briefly discussed, but none of them were given serious consideration, because many people weren’t convinced of the need to have such syntax in the first place.

    There was another proposal in the mailing concerning Concepts – one that I coauthored – that touched on the semantics of a concept name appearing twice in an abbreviated function template. It was not presented at this meeting for procedural reasons; I expect it will be presented at the next meeting in Toronto.

    Definition Checking

    There is one other topic related to Concepts that I’ve talked about before, and would like to touch on again: definition checking. To recap, this involves having the compiler check an uninstantiated template definition to make sure that it only uses its template parameters in ways allowed for by their constraints. In principle, definition checking combined with checking constraints at call sites (which the Concepts TS already does) should completely eliminate the possibility of compiler errors with instantiation backtraces: either the error is that the caller is not passing in types that meet the constraints, in which case the error pertains to the call site only; or the error is that the implementation uses the template parameters in ways not provided for by the constraints, in which case the error pertains to the uninstantiated definition site only.

    As I described in my Jacksonville report, one of the reasons Concepts failed to make C++17 is that people had concerns about whether concepts in their current form are conducive to definition checking. However, that was not the only reason, and since Jacksonville I’ve increasingly heard the sentiment expressed that definition checking is a hard problem, and we should not hold up Concepts while we figure out how to do it. To quote the “vision for C++20” paper that I talked about above:

    At the risk of sounding like a broken record, I will repeat a particular point: we need to throw definition checking under the bus. If we insist on having it, we will probably get nothing in C++20, and chances are we’ll get nothing in C++23. Such a trade-off is unacceptable. The benefits of Concepts as proposed far outweigh the benefits of definition checking, and most users wouldn’t care less about not having definition checking.

    While I personally disagree with the sentiment that “most users wouldn’t care less about not having definition checking” – I believe it’s actually a critical part of a complete generic programming design – I do agree that Concepts is still very useful without it, and having to wait for Concepts until C++23 or beyond on its account would be very unfortunate.

    A year ago, I was quite hopeful that we could make progress on the technical problems surrounding definition checking in time to make appropriate revisions to the Concepts TS (to, for example, tweak the way concepts are defined to be more amenable to definition checking) and get the result into C++20. Today, based on statements like the above, I am significantly less hopeful. My prediction is that, at this point, we’ll get Concepts in C++20, without any changes geared towards definition checking, and then maybe at some point in the future we’ll get some form of definition checking, that will be constrained by choices made in the Concepts TS as currently written. In this scenario, the desirable property I described above – that all errors are caught either purely at the call site, or purely at the definition site – which, I’ll note, is a property that other languages like Haskell and Rust do have – is unlikely to be achieved.

    Modules

    EWG spent half a day on the Modules TS. (I summarized the procedural developments above.)

    The first main topic of discussion was a name lookup issue that came up during wording review of the Modules TS working draft in the Core Working Group. The issue concerns situations like this:

    • A module A defines a template foo, which uses an operation op on its argument.
    • A module B includes a non-modular (“legacy”) header that defines a type S and provides operation op for it.
    • B imports A, and defines a template bar that invokes foo with S as an argument, but still in a dependent context (so as not to trigger immediate instantiaion of foo).
    • A translation unit C imports B and instantiates bar.

    What happens here is, the instantiation of foo happens in the context of C, where S‘s op is not visible. This could lead to:

    • A compiler error, if no other viable definition of op is visible.
    • A different (viable) definition of op than the intended one being silently called.
    • An ODR violation (undefined behaviour) if another translation unit has already instantiated foo, and op resolved to something else there.

    Note that if the modules are replaced with headers, and imports with #includes, this setup works just fine.

    To work around this, the programmer can do one of two things:

    • Have B export S‘s op, so it’s visible in all units that import B. There’s syntax for doing this even though S is defined inside a non-modular header.
    • Include the non-modular header that defines S and its op from C.

    Neither of these is particularly satisfying. The first, because it involves repeating the declaration of op; the second, because S may be an implementation detail of B that C can’t be expected to know anything about.

    The implementers of Modules at Microsoft argued that they haven’t run into this situation very much while deploying their implementation in a large codebase, and suggested shipping Modules v1 as a PDTS without addressing this issue, to gather feedback about how widespread of a problem it is. The Clang implementers stated that they had run into this, and needed to adjust the semantics of their modules implementation to deal with it. In the end, there was no consensus on changing the Modules TS semantics to deal with this problem before releasing the PDTS.

    The other main topic of discussion was a paper containing proposed changes to the Modules TS from the Clang implementers – specifically the ones approved in Jacksonville for which there was confusion about whether they were meant to apply to Modules v1:

    • Requiring the module declaration to be the first declaration in a module file. Currently, it doesn’t have to be, and preceding declarations belong to the global module. The proposal would come with a mechanism to “reopen” the global module after the module declaration and place declarations in it. Apart from implementation considerations (from which point of view there are arguments on both sides), the motivation is readability: making it immediately clear to the reader that a file is a module file. There was no consensus for making this changes in Modules v1.
    • Introducing syntax to differentiate the module declaration for a module interface file from the module declaration for a module implementation file. EWG expressed support for this for Modules v1, and a preference to add the extra syntax to the interface declaration. No specific syntax was chosen yet.
    • Introducing syntax for module partitions (module interfaces spread across multiple files). EWG supported putting this in Modules v1 as well, though again no specific syntax was yet chosen.

    As stated above, the hope is that Modules v1, as amended with the approved changes I described, can ship as a PDTS at the next meeting in Toronto.

    Other Working Groups

    The Library Working Group spent the week, including most evenings, heroically processing the large quantity of C++17 CD comments that concerned the standard library (a lot of them relating to the recently-merged Filesystem TS, though there were many others too), so that we could stay on schedule and send C++17 out for its DIS ballot at the end of the week (which we did).

    The Library Evolution Working Group was working through its large backlog of proposed new library features. As much as I’d love to follow this group in as much detail as I follow EWG, I can’t be in two places at once, so the best I can do is point interested readers to the mailings to check out library proposals.

    Regarding the various Study Groups, I’ve largely mentioned as much as I know about their progress in the Technical Specifications section above, but I’ll say a few more words about a couple of them:

    SG 7 (Reflection)

    SG 7 looked at two proposals for static reflection that can be thought of as alternatives to the proposal approved earlier by the group (and approved this week by EWG).

    Both proposals are essentially “isomorphic” to the approved proposal in terms of what can be reflected, they just propose doing the reflection with a different syntax, and in particular with a syntax that represents meta-objects (reflected information about program entities) as values rather than types.

    The differences between the two proposals are mostly just syntax and interface, e.g. the first uses a member function interface for operations on the meta-objects, while the second one uses a free function interface.

    In addition, the author of the second proposal presented an extension (not in the paper) that would essentially allow generating source code from compile-time strings, which would be a very powerful and general metaprogramming facility. It was pointed out that, while we may want such a general facility for advanced metaprogramming use cases, it seems like overkill for the reflection use cases being considered.

    The outcomes of the session were that: there is interest in moving towards reflection through values rather than through types; that the already-approved proposal (which does it through types) should nonetheless go forward as-is (which it did, with EWG approving it the next day); that a free function interface is preferable to a member function interface; and that the group should aim to (also) standardize more general metaprogramming features.

    This latter – expanding the purview of SG 7 from just reflection, to metaprogramming more generally – is a deliberate change supported by the committee leadership. The group may be renamed “Reflection and Metaprogramming” or similar in due course.

    SG 14 (Game Development & Low-Latency Applications)

    SG 14 did not meet at GDC this year like it did last year, because this year’s GDC was the same week as the committee meeting I’m writing about 🙂

    They do hold regular teleconferences (see the mailing list for details), and the latest status of their various proposals can be found in this summary paper.

    Over the past year, the group has also been courting the interest of the embedded programming community, which is interested in many of the same issues (memory-constrained environments, hard/soft real-time applications, avoidance of dynamic memory allocation, etc.) as the existing consituencies represented in SG 14.

    Next Meeting

    The next meeting of the Committee will be in Toronto, Canada (which is where I’m based!), the week of July 10th, 2017.

    Conclusion

    C++17 is effectively out the door, with its Draft International Standard sent out for ballot, and the official release expected later this year.

    Development on C++20 is well under way, with numerous core language and library features already earmarked for it, and several Technical Specifications expected to be merged into it. A proposal for an overall vision for the release aims to focus the committee’s efforts on four headliner features – Concepts, Modules, Ranges, and Networking. That is, of course, not a guarantee these features will be in C++20 (nor is it intended to exclude other features!), but I believe with some luck and continued hard work we can make part of all of that plan a reality.

    Modules, in particular, are expected to be a game-changer for C++. Whether or not they make C++20, they will be available as a Technical Specification very soon (possibly as soon as later this year), and they are already available for experimentation in Clang and MSVC today.

    Stay tuned for continued reporting on C++ standardization on my part!

    Posted in c++, programming | Tagged , , | 8 Comments

    Trip Report: C++ Standards Meeting in Issaquah, November 2016

    Summary / TL;DR

    Project What’s in it? Status
    C++17 See below Committee Draft published; final publication on track for 2017
    Filesystems TS Standard filesystem interface Published! Part of C++17
    Library Fundamentals TS v1 optional, any, string_view and more Published! Part of C++17
    Library Fundamentals TS v2 source code information capture and various utilities Voted for publication!
    Concepts (“Lite”) TS Constrained templates Published! Not part of C++17
    Parallelism TS v1 Parallel versions of STL algorithms Published! Part of C++17
    Parallelism TS v2 Task blocks, library vector types and algorithms, context tokens (maybe), and more Under active development
    Transactional Memory TS Transaction support Published! Not part of C++17
    Concurrency TS v1 future.then(), latches and barriers, atomic smart pointers Published! Not part of C++17
    Concurrency TS v2 TBD. Exploring synchronic types, atomic views, concurrent data structures, sycnhronized output streams. Executors to go into a separate TS. Under active development
    Networking TS Sockets library based on Boost.ASIO Voted for balloting by national standards bodies
    Ranges TS Range-based algorithms and views Voted for balloting by national standards bodies
    Numerics TS Various numerical facilities Under active development
    Array Extensions TS Stack arrays whose size is not known at compile time Withdrawn; any future proposals will target a different vehicle
    Modules TS A component system to supersede the textual header file inclusion model Initial TS wording reflects Microsoft’s design; changes proposed by Clang implementers expected. Not part of C++17.
    Graphics TS 2D drawing API In design review stage. No new progress since last meeting.
    Coroutines TS Resumable functions First revision will reflect Microsoft’s await design. Other approaches may be pursued in subsequent iterations. Not part of C++17.
    Reflection Code introspection and (later) reification mechanisms Introspection proposal undergoing design review; likely to target a future TS
    Contracts Preconditions, postconditions, and assertions In design review stage. No new progress since last meeting.

    Introduction

    Last week I attended a meeting of the ISO C++ Standards Committee (also known as WG21) in Issaquah, Washington (near Seattle). This was the third and final committee meeting in 2016; you can find my reports on previous meetings here (February 2016, Jacksonville) and here (June 2016, Oulu), and earlier ones linked from those. These reports, particularly the Oulu one, provide useful context for this post.

    This meeting was heavily focused on C++17, with a secondary focus on in-progress Technical Specifications, and looking forward to C++20.

    At the end of the last meeting, the C++17 Committee Draft (CD) – a first feature-complete draft of the C++17 spec – was sent out for comment from national standards bodies. The comment period concluded prior to this meeting, and as such, the main order of business at this meeting was to go through the comments and address them.

    Note that, while the committee is obligated to respond to each comment, it is not obligated to accept the proposed resolution of the comment (if it has one); “there was no consensus for a change” is an acceptable response. (Technically, if a national standards body is unhappy with the response to their comment, it can vote “no” on the final standard, but this practically never happens; the prevailing practice is to respect the consensus of the committee.)

    Addressing the CD comments is a process that typically takes two meetings. Indeed, the committee did not get through all of them this meeting; resolution of the comments will continue at the next meeting, at which point a revised draft, now labelled Draft International Standard (DIS) will be published, and sent out for a second round of comments.

    C++17

    Since the C++17 CD is supposed to be feature-complete, no new features were voted into C++17 at this meeting. See my Oulu report (and things linked from there) for features that were voted into C++17 at previous meetings.

    However, some changes to C++17 (that don’t qualify as new features, but rather tweaks or bugfixes to existing features) were voted into C++17 at this meeting, mostly in response to national body comments.

    Changes voted into C++17 at this meeting

    It’s worth observing that some of these library changes involve taking language changes previously accepted into the CD, such as structured bindings, and making use of them in the library (for example, adding structured bindings for node_handle). Since these types of library changes naturally “lag behind” the corresponding language changes, there have been requests to close the door to new language features earlier than for library features, to give the library time to catch up. No formal decision along these lines has been made, but authors of language features have been asked to give thorough consideration to library impact for future proposals.

    Proposed changes to C++17 that were rejected

    One notable change to C++17 that was proposed at this meeting was rejected: this introduction of byte type whose intended use was unambiguously “a unit of storage” rather than “a character” or “an 8-bit integer” (which is not true of existing byte-like types such as char or unsigned char). The proposal involved the definition of a library type named std::byte (defined as an enum class), and core wording changes to grant the type special treatment, such as allowing the construction of an arbitrary object into a suitable-sized array of byte, as is currently allowed for char (this treatment is relied upon by the implementations of containers such as std::vector that allocate a block of memory some but not all of which contains constructed objects). The long-term hope is for std::byte to replace char as the type that gets this special treatment, and eventually deprecate (and later) remove it for char.

    The proposal to add this type to C++17 failed to gain consensus. This was partly because we’re late into the process (this would have had to be another exception to the “no new features beyond the CD” rule), but also because there were objections to naming the type “byte”, on the basis that there is a lot of existing code out there that uses this name, some of it for purposes other than the one intended in this proposal (for example, as an 8-bit integer type).

    It seemed like there is still a chance for this proposal to gain consensus with the type’s name changed form “byte” to something else, but this is unlikely to happen for C++17.

    Technical Specifications

    In spite of the heavy focus on addressing comments on the C++17 CD, notable progress was also made on Technical Specifications (TS) at this meeting.

    The procedure for publishing a Technical Specification is as follows:

    • Once it has completed design and wording review and is considered to be in good enough shape, a Preliminary Draft Technical Specification (PDTS) is published, and sent out for comment by national standards bodies.
    • The comments are reviewed and addressed (much like comments on a C++ Committee Draft)
    • The revised Technical Specification is sent out for final publication. (Optionally, if the committee believes the TS is not ready for publication and needs a second round of comments, it can publish a Draft Technical Specification (DTS) and send it out for comment, and only subsequently publish the final TS. However, this generally hasn’t been necessary.)

    At this meeting, two TS’s were approved for being sent out for a PDTS ballot, and one was approved for final publication.

    Library Fundamentals TS v2

    The Library Fundamentals TS v2 had previously been sent out for its PDTS ballot, and the library working groups had been hard at work addressing the comments over the past few meetings.

    At this meeting, the process was finally completed. With a few final changes being voted into the TS (a tweak to the searchers interface and miscellaneous other fixes), the TS was approved for final publication!

    Ranges TS

    The Ranges TS has passed its initial wording review. It picked up a couple of changes, and was approved to be sent out for its PDTS ballot!

    The Ranges TS is unique in that it is, so far, the only TS to have a dependency on another one – the Concepts TS. There is nothing wrong with this; the only caveat is that, obviously, the Ranges TS can only be merged into the C++ standard itself after (or together with) the Concepts TS. Over time, I expect other TS’s in the future to be in a similar situation.

    The Ranges TS is also notable for containing the beginnings of what could end up being a “standard library v2” – a refresh of the C++ standard library that uses Concepts and makes some (but not a gratuitous amount) of breaking changes compared to the current standard library. I’m excited to see it move forward!

    Networking TS

    The Networking TS has also passed its initial wording review. It, too, picked up a couple of changes, and was approved to be sent out for its PDTS ballot!

    I’m also quite excited to see the Networking TS move forward. In addition to providing a socket library for C++, it defines foundational abstractions for asynchronous programming in C++. Its design has influenced, and will continue to influence, C++ proposals in other areas such as concurrency and (perhaps at some point in the future) input handling.

    Coroutines TS

    The Coroutines TS contains the co_await proposal, based on Microsoft’s original design.

    As mentioned previously, there are efforts underway to standardize a proposal for a different, stackful flavour of coroutines, as well as an exploratory effort to unify the two flavours under a common syntax. These proposals, however, are not currently slated to target the Coroutines TS. They may instead target a different TS (and if a unified syntax emerges, it could be that syntax, rather than the one in the Coroutines TS, that’s ultimately merged into the C++ standard).

    In any case, the Coroutines TS is currently moving forward as-is. A proposal to send it out for its PDTS ballot came up for a vote at this meeting, but failed to gain consensus, mostly on the basis that there has not been time for a sufficiently thorough review of the core language wording parts. Such review is expected to be completed by the next meeting, at which time – if all goes well – it could be sent out for its PDTS ballot.

    Concepts TS

    To recap the status of the Concepts TS: it was published last year, not merged into C++17, and now has a Working Draft that’s available to accept changes. Whether that Working Draft will eventually be published as a Concepts TS v2, or merged directly into C++20, remains to be decided.

    One change was voted into the Concepts Working Draft at this meeting: a proposal to allow a requires-expression to appear in any expression context, not just in a concept definition. This is useful for e.g. using a requires-expression in a static_assert.

    There is some uncertainty regarding the longer-term future direction of Concepts. The following areas seem to be somewhat contentious:

    • Definition checking, which I wrote about in a previous post. Definition checking is a feature that was part of the original C++0x Concepts design, and which has long been promised as an eventual extension to the current Concepts Lite design. However, there doesn’t seem to be consensus on how amenable the Concepts Lite design is to definition checking, or at least, what quality of definition checking it is amenable to. In my view, for example, if the definition checking doesn’t have the crucial property that “if a template definition passes the check, then all instantiations of it with arguments that satisfy the constraints will be successful”, then there is little point to the whole exercise. (It’s worth noting that Rust has the equivalent of Concepts (called traits in Rust), and the equivalent of definition checking (the checking that’s performed on generic parameters with trait bounds, to ensure that they’re not used in ways other than what’s allowed by the trait). Definition checking in Rust does have the property I mentioned above – this is why in Rust we don’t see the horrifying long compiler errors with instantiation backtraces that we’ve come to dread in C++.)
    • The proliferation of concept definition syntaxes. The “abbreviated function template” notation (where you get to write a function template that looks like a non-template function, using concept names in place of type names) in particular seems to be somewhat controversial. Allowing this syntax was one of the reasons the proposed merger of the Concepts TS into C++17 was rejected (the other major reason being insufficient implementation and use experience). Based on my conversations with other committee members, I get the impression that this objection is likely to persist the next time Concepts comes up for a vote (for example, for merger into C++20).

    Modules TS

    The Modules TS has a working paper, which largely reflects Microsoft’s design. It is under active wording review.

    The implementers of Modules in clang have a proposal for some design changes based on their implementation experience. It is unclear at this point whether these changes, if approved, would go into the initial Modules TS; some of them, particularly the more controversial ones such as the support for exporting macros, may end up targeting a second revision of the Modules TS instead.

    Parallelism TS v2

    The Parallelism TS v2 is making good progress. It’s expected to contain task blocks, library vector types and algorithms, and perhaps context tokens. The TS should be ready for a PDTS ballot once wording review of the vector proposal is completed.

    Concurrency TS v2

    The Concurrency TS v2 (doesn’t have a working draft yet) is also making progress. It’s expected to contain a synchronized output stream facility, atomic_view, a synchronized value abstraction, queues, and counters, possibly among other things.

    Executors, which have originally been slated for Concurrency TS v1 but got bogged down in lengthy design discussions over the years, have made notable progress at this meeting: for the first time, the various parties agreed on a unified proposal! This may end up targeting a separate Executors TS, so it doesn’t hold back the Concurrency TS v2.

    The chair of SG 1 (the Study Group concerned with parallelism and concurrency) remarked that splitting proposals into “parallelism” and “concurrency” buckets seems to be less useful as time goes on and some topics, such as executors, concern both. It’s possible that these two series of TS’s will be folded together into a single series in the future, released more frequently.

    Future Technical Specifications

    In addition to the above already-inflight Technical Specifications, a number of new ones are planned for the future.

    Reflection

    The Reflection Study Group (SG 7) has been reviewing a proposal for static introspection (design, specification). At this meeting, the proposal was approved by SG 7, and sent onward for review by the Evolution and Library Evolution working groups starting at the next meeting. The ship vehicle will be determined by these working groups, but it’s expected to be a TS (the other possibility is C++20).

    I write about SG 7’s meeting this week in more detail below.

    Numerics

    The Numerics Study Group (SG 6) is planning a Numerics TS that will contain a variety of facilities, as outlined here. The initial draft of the TS will likely just be a concatenation of the various individual proposals (which are being developed by various authors; see proposals with “Numerics” as the audience in the list here); the SG 6 chair hopes such an initial draft will be produced at the next meeting.

    There was also a proposal to have a separate Technical Specification concerning random number generation, which received no objections.

    Graphics

    The Graphics TS, which proposes to standardize a set of 2D graphics primitives inspired by cairo, is still under design review. No time was spent reviewing the proposal at this meeting, so there is no new progress to report compared to last meeting.

    Evolution Working Group

    As usual, I spent my time in the Evolution Working Group (EWG), which spends its time evaluating and reviewing the design of proposed language features.

    EWG did two things this week: first, it looked at national body comments on the C++17 CD which touched on the design of the language; and second, it looked at new language proposals, all of which were targeting C++20 or beyond (or a Technical Specification). I’ll talk about each in turn.

    National Body Comments

    The national body comments can be found in two documents: the official ones, and the late ones which therefore aren’t considered official, but were still looked at. I can’t link to individual comments directly, so I refer to them below by country and number, e.g. “US 1”.

    A couple of procedural notes on comment processing:

    • When the C++17 CD was published, the document enjoyed the committee members’ consensus (otherwise it wouldn’t have been published). A change to it at this stage is only considered if it increases consensus, which is a high bar. Comments proposing changes which do not meet this high bar are disposed with the response “there was no consensus for a change”.
    • As the comments originate from a variety of authors, they sometimes ask for contradictory things (sometimes even within a single national body). In such cases, both options are considered, but again, a change is only made if it increases consensus (which is less likely in this scenario).

    With that said, here are the comments that were looked at, grouped by the feature they concern:

    • Comments concerning class template argument deduction
      • Implicit deduction guides (GB 21, US 19, US 20)

        To recap, class template argument deduction is a feature where template arguments for a class template can be deduced at construction time, instead of being explicitly specified, like so:

        std::pair p(42, "waldo"s); // deduce std::pair<int, std::string>

        The deduction can be guided either by the constructors of the primary template, which are called implicit deduction guides in this context, or by explicit deduction guides, which are new constructs declared outside the template specifically for the purpose of guiding this sort of deduction.

        The proposal authors analyzed the impact of this feature on the standard library and found that, while in many cases the existing constructors provide the desired deduction behaviour, in some other cases explicit guides would need to be added to complement or correct the behaviour of the implicit ones.

        The comments listed here are concerned with what to do with implicit deduction guides in light of this library impact. One comment proposed removing them altogether, requiring explicit guides to be written in all cases; two others request tweaks to the behaviour of implicit guides.

        EWG expressed a strong preference for keeping implicit deduction guides, but also for adding to the standard library whatever explicit guides are necessary to get desired deduction behaviour for standard library types.

        The proposed behaviour tweaks were accepted. The first proposed that if, for a given constructor call, an explicit guide and an implicit guide are equally good matches, the explicit guide be preferred, instead of resulting in an ambiguity.

        The second tweak was more interesting. It concerned the behaviour of a T&& parameter in a constructor of the primary template. Parameters of the form T&& have the unique property that they behave differently depending on whether or not T is deduced. If T is not deduced, they are always rvalue references (unless T is explicitly specified to be an lvalue reference type); if T is deduced, they are forwarding references (formerly called universal references), which may end up being lvalue or rvalue references. Now, if T is a template parameter of a class, and a constructor of that class has a T&& parameter, normally T is not deduced; but when the constructor is used as an implicit deduction guide, it is! As a result, the semantics of the parameter silently change. To avoid this, a tweak to the rules was made to ensure that the parameter retains its non-forwarding semantics in the implicit guide context.
      • Uniform initialization (FI 21, GB 13, US 94). These comments concerned the fact that, while the feature allows std::pair p(42, 43), std::pair p{42, 43}, and std::pair(42, 43), it does not allow std::pair{42, 43}. EWG agreed that this inconsistency should be fixed, although it did ask for a paper to be written, as specifying this was deemed sufficiently non-trivial.
    • Comments concerning expression evaluation order (CA 18, US 1, US 3, US 93, US 102, Late 4).

      Several of these comments concerned the discrepancy in the order of evaluation between a @= b (where b is evaluated before a, for consistency with assignment) and a.operator=(b) (where a is evaluated before b, for consistency with member function calls). (Note that @ here is meant to stand in for any operator that can be combined with =, such as +=, -=, etc.) This issue was discussed previously, and the comments didn’t really bring any new information to the table; there was no consensus for a change.

      Another comment asked to revisit the decision previously made to have the evaluation of function arguments with respect to each other be unsequenced, and instead evaluate them left-to-right. There was no consensus for a change here, either.
    • Comments concerning decomposition declarations (“structured bindings”)
      • Syntax – [] vs. {} (ES 2, FI 23, US 23, US 71, Late 9, Late 12). The original proposal for decomposition declarations used the syntax auto {a, b, c}; that was changed at the last meeting to auto [a, b, c]. This change was fairly controversial, and several comments asked to change it back to {} (while others encouraged keeping the []). There are technical arguments on both sides (the [] syntax can conflict with attributes once you start allowing nested decompositions; the {} syntax can conflict with uniform initialization if you throw Concepts into the mix and allow using a concept-name instead of auto), so in the end it’s largely a matter of taste. The clang implementers did report that they tried both, and found the ambiguities to be easier to work around with []. In the end, there was no consensus for a change, so the status quo ([] syntax) remains.
      • static, thread_local, constexpr, extern, and inline decomposition declarations (GB 16, GB 17, US 95). There was general agreement that allowing these modifiers is desirable, but the exact semantics need to be nailed down (for example, for constexpr is only the unnamed compound object constexpr, or the individual bindings too?), and EWG felt it was too late to do that for C++17. The comment authors were encouraged to come back with proposals for C++20.
      • Decomposition in init-captures (US 92). EWG considered this an extension, and was open to it, but not in the C++17 timeframe.
      • Discarding values in decomposition declarations (US 100). This was rejected as the topic had been previously discussed.
      • Decomposition declarations and arrays (GB 18). This comment pointed out an inconsistency where decomposition declarations copy arrays by value, but the underlying mechanism used to specify them is template argument deduction, which decays arrays to pointers. The suggestion was to remove the special-case behaviour for arrays in decomposition declaration. Others, however, defended the special case, arguing that not copying arrays by value is a mistake inherited from C, and new features like this are opportunities not to repeat such mistakes. There was no consensus for a change.
      • Explicit types in decomposition declarations (FI 3). This was a request (also accompanied by a paper) to allow explicitly specifying the type of the compound object (and/or of the individual bindings). (As a strawman syntax, consider auto [a : T, b : U, c : V] = expr, where the decomposition is ill-formed if the types of a, b, and c do not match T, U, and V, respectively). EWG was open to an extension along these lines, but not in the C++17 timeframe.
      • Decomposition declarations in parentheses (FI 20). This was a request to allow the form auto [a, b, c](expr) in addition to auto [a, b, c] = expr and auto [a, b, c]{expr}; that was approved.
      • When are get<>() functions called in decomposition declarations? (Late 3). This comment concerned the case where type being decomposed is neither an aggregate strucure nor an array, but a tuple-like user-defined type where the individual bindings are extracted using get<>(). The specification wasn’t clear as to whether these get<>() calls occur “eagerly” (i.e. at the point of decomposition) or “lazily” (at the point of use of the individual bindings, which can potentially mean calling get<>() multiple times for a given binding). EWG decided in favour of “lazy”, because it enabled certain use cases (for example, decomposing a type such as a status/value pair where it’s only legal to access the value if the status has a certain value), while types that do nontrivial work in get<>() (thus making multiple calls expensive) seem rare.
    • Comments concerning default comparisons (ES 7, RU 5, US 5, US 69, Late 7, Late 14). As you’ll recall from my Oulu report, default comparisons failed to achieve consensus to go into C++17. These comments were an attempt to save the feature by putting a less-controversial subset into C++17. There were three specific proposals for doing so on the table:
      • The first proposal concerned only generating operator!= from operator==, and operator>, operator<=, and operator>= from operator<; operator== and operator< themselves still have to be manually defined (although automatic generation of those would be a compatible extension). The proposal also contained a new mechanism for “generating” these derived operators: rather than having the compiler generate what behave like new overloaded functions, expressions of the form a != b are reinterpreted/rewritten to be of the form !(a == b) if a suitable operator!= cannot be found (and similarly for the operators derived from operator<). It was pointed out that this mechanism, like the mechanisms underlying some of the previous proposals, suffers from the slicing problem: if a base class defines both operator== and operator!= (as a class in existing code might) while a derived class defines only operator== (as a class written with this proposal in mind might), then an expression of the form a != b, where a and b are objects of the derived class, will call the base’s operator!= because there is a matching operator!= (and as a result, any data members in the derived class will not participate in the comparison).
      • The second proposal concerned default generation of operator== (but not operator<), based on the following simple rule: if operator= is auto-generated, so is operator==, the idea being that the semantics of assignment and equality are fundamentally entwined (if you make a copy of something, you expect the result to behave the same / be equal). The idea had support, but some people were still concerned about having even == be auto-generated without an explicit opt-in.
      • The third proposal concerned adding an opt-in syntax for asking for any of the comparison operators to be generated by declaring them as = default. This has been previously proposed, and people’s concerns largely mirrored those at the previous discussion.

      None of these proposals achieved consensus for C++17. The main reason had to do with another proposal concerning comparison, which wasn’t slated for C++17. This proposal tried to bring some mathematical rigour to comparison in C++, by observing that some types were totally ordered, while others were only weakly or partially ordered. The proposal suggested an API, based on functions rather than operators, to perform tasks such as a three-way comparison of two objects of a totally ordered type. This got people thinking that perhaps down the line, we could build == and < on top of a three-way comparison primitive (for totally ordered types); this would, for example, enable us to generate an operator<= that’s more efficient than what’s possible today. People liked this future direction, and in light of it, each of the above proposals seemed like a half-baked attempt to rush something into C++17, so the group settled on getting this right for C++20 instead.

    • Comments concerning concepts (US 2). While Concepts was not accepted into C++17, a comment asked that a subset of the proposal, consisting of requires-clauses and requires-expressions, be accepted. EWG had no consensus for making a change here; it was felt that the proposed subset was sufficiently substantial that several of the reasons not to put Concepts as a whole into C++17 still applied to them.
    • constexpr static members of enclosing class type (US 24). This comment concerned the fact that a class cannot contain a constexpr static data member whose type is that class type itself. The comment proposed making this work by deferring the processing of such a data member’s initializer (which is what requires the type to be complete) until the end of the class definition. Doing this in general (i.e. for all constexpr static data members) would be a breaking change, since declarations that occur later inside the class definition can use the data member. However, doing it for a subset of cases, that are currently ill-formed, would work, and some ideas were bounced around about what such a subset could be. (A simple one is “when the data member’s type matches the class type exactly”, but we might be able to do better and cover some cases where the data member’s type isn’t the class type exactly, but still requires the class type to be complete.) EWG encouraged people to work out the details and come back with a paper.
    • There was a comment requesting to rename __has_include (US 104) to have a “less ugly” name, such as has__include. This was rejected because there is existing practice using the name __has_include

    New Language Features

    Here are the post-C++17 features that EWG looked at, categorized into the usual “accepted”, “further work encouraged”, and “rejected” categories:

    Accepted proposals:

    • template keyword in unqualified-ids. This concerns a parsing quirk of C++. When the compiler encounters a name followed by a left angle bracket, such as foo<, it needs to decide whether the < starts a template argument list, or is a less-than operator. It decides this by looking up the name foo: if it names a template (in standardese, if it’s a template-name), the < is assumed to start a template argument list, otherwise it’s assumed to be a less-than operator. This heuristic often works, but sometimes falls down: if you have code like foo<type>(arg), where foo is a template function that’s not visible in the current scope, but rather found by argument-dependent lookup (by being in one of the associated namespaces of arg), then at the time the compiler looks up foo, no template-name is found, so the construct is parsed wrongly. This proposal allows the programmer to rectify that by writing template f<type>(arg); think of the template as meaning “I promise the name that follows will resolve to a template”. This mirrors the existing use of the template keyword when naming a template nested inside a dependent type, such as Base<T>::template nested<U>. Some people had reservations about this proposal resulting in programmers sprinkling template about rather liberally, but the proposal passed nonetheless.
    • Allowing lambdas in unevaluated contexts such as inside decltype(). This came up previously, and the feedback was “we like it, but please make sure appropriate restrictions are in place such that the bodies of lambdas never need to be mangled into a signature”. The author revised the proposal to put in place appropriate restrictions. EWG asked for one more tweak – to exclude the body of the lambda expression from the “immediate context” of an instantiation for SFINAE purposes – and with that tweak passed the proposal.
    • Familiar template syntax for generic lambdas. This will allow writing generic lambdas like []<typename T>(T arg) in addition to [](auto arg). The advantage of the first form is that it can express things the second form cannot, such as []<typename T>(T a, T b). The two forms can be combined as in []<typename T>(T a, auto b); in such a case, the invented template parameters (for the autos) are appended to the explicitly declared ones.
    • Allowing the lambda capture [=, this]. The semantics are the same as [=], but this form emphasizes that the we are just capturing the this pointer, and not the pointed-to object by value (syntax for the latter, [*this], was previously added to C++17). (The question of allowing this change into C++17 came up, but there wasn’t a strong enough consensus for it.)
    • A class for status and optional value. This is a library proposal, meant to be an error handling mechanism for cases where throwing an exception is not possible or not ideal (for example because the absence of a value is commonplace, and exceptions would impose undue overhead). The proposal sailed by EWG on its way to LEWG (the Library Evolution Working Group), mostly to see if EWG was OK with standardizing an alternative to exceptions (it was).
    • Benchmarking primitives. This can be considered a follow-up to the timing barriers proposal which was discussed at the previous meeting and revealed to be unimplementable. The paper proposes two benchmarking primitives which are implementable (with equivalents being widely used in production benchmarking libraries today): touch(), which pretends to write to all bits of an object (to prevent the compiler from using information it might have had about the previous value of the object for optimizations), and keep(), which pretends to read all bits of an object (to prevent the compiler from optimizing the object away on account on no one looking at it). They would be library functions, in the namespace std::benchmark, but the compiler would impart special meaning to them. The choice of names was disputed, but that was left for LEWG to bikeshed. (There was a suggestion to put the functions in a namespace other than std::benchmark on the basis that they could be useful for other applications, such as secure zeroing. However, it was pointed out that these functions are not sufficient for secure zeroing, as the hardware can also play shenanigans such as eliding writes.)

    Proposals for which further work is encouraged:

    • Querying the alignment of an object. C++11 gave us an alignas specifier to use on a type or a variable, and an alignof operator to query the alignment of a type; missing is an alignof operator to query the alignment of a variable. In practice implementations already provide this, and this proposal thus standardizes existing practice. The discussion centred around whether alignof x (without parentheses) should be allowed, like sizeof x (the consensus was “no”), and whether alignof((x)) (with double parentheses) should return the alignment of the type of x rather than the alignment of the variable x (mirroring the behaviour of decltype, where decltype(x) returns the declared type of the entity x, whereas decltype((x)) returns the type of the expression x; the consensus here was also “no”).
    • Pattern matching for types. This is a compile-time pattern matching mechanism for types in the same vein as the runtime pattern matching mechanism for values that was proposed earlier. It complements if constexpr in a similar way to how switch (or the run-time pattern matching) complements if. The proposed construct would be usable in a statement, expression, or type context, and would have “best match” semantics (where, if multiple patterns match, the best match is chosen). EWG encouraged further work on the proposal, including exploring the possibility of matching on non-type values and multiple types (you can accomplish either with the current proposal using std::integral_constant and std::tuple, respectively, but first-class support might be nicer).
    • Bitfield default member initializers. The initial version of this proposal allowed the naive syntax, int x : width = init;, by adding some disambiguation rules. At the time, EWG thought the rules would be hard to teach, and asked for a new syntax instead. The proposal was revised, suggesting the syntax int x : width : = init; (notice the extra colon). EWG didn’t like this syntax, nor any of the proposed alternatives (another was int x:[width] = init;), and instead settled on allowing the naive syntax after all, but with different disambiguation rules that avoid any code breakage, at the expense of forcing people who add initializers to their bitfields to sprinkle parentheses in more cases.
    • A unified API for suspend-by-call and suspend-by-return coroutines. As I’ve described in previous posts, two flavours of coroutines are being proposed for standardization in C++ – ones with suspend-by-return semantics (a.k.a. “stackless” coroutines), and ones with suspend-by-call semantics (a.k.a. “stackful” coroutines) – and EWG has expressed an interest in exploring whether the two models can be unified under a common syntax. This is a concrete proposal for such a syntax, taking the form of a library API. Feedback from EWG fell into two main categories. First, there was a question of whether this API is at the appropriate level of abstraction; some felt that a higher-level API that includes the notion of a scheduler may be better (the proposal author posited that such an API could be built on top of this one). Second, some felt that it was starting to become clear that a unified API necessarily comes at the cost of some overhead – depending on the implementation strategy, either compile- and link-time overhead, or runtime overhead – and in light of this, the unification may not be worth it. To elaborate on this point: suspend-by-call semantics gives you certain freedoms that suspend-by-return does not – for example, the ability to write code that’s unaware of whether the functions it calls suspend. The proposed unified API preserves these freedoms, even if a suspend-by-return implementation is used, and this is the source of the overhead.
    • Operator dot, for which there are two proposals on the table.
      • The original proposal almost made C++17, but was booted at the last minute when people realized it failed to specify how operator dot interacts with other user-defined conversions. The authors now have an updated proposal that addresses these interactions.
      • Meanwhile, there’s another proposal, which aims to achieve the same goals via an inheritance-like mechanism. Instead of having the wrapper class declare an operator. that returns the wrapped class, the wrapper class declares the wrapped class as a delegate base, using the syntax class Wrapper : using Wrapped, and provides a conversion operator to access the wrapped object (which is stored as a member, or obtained from somewhere else; it’s not implicitly allocated as part of the wrapper object as it would be with real inheritance). The beauty behind this proposal is that the desired behaviour (“when you access a member of the wrapper object, it resolves to a member of the wrapped object if there is no such member in the wrapper object”) falls naturally out of the existing language rules for inheritance (lookup proceeds from the derived class scope to the base class scope), without having to invent new language rules. As a result, the proposal enjoyed a positive reception.

      Both proposals will be discussed further at the next meeting.

    • Attributes for likely and unlikely branches. These would be standardized versions of the widely implemented __builtin_expect(condition, true) and __builtin_expect(condition, false) constructs, spelt [[likely]] condition and [[unlikely]] condition, and restricted to appearing in the condition of an if-statement. EWG liked the idea, but expressed a preference for putting the attribute on statements, such as if (condition) [[likely]] { ... }; this would then also generalize to other control flow constructs like while and switch.
    • Procedural function interfaces. This paper presents a theoretical framework for statically reasoning about the correctness of a program. Described as a “long-term feature”, the eventual goal is to annotate interfaces in a program with claims/assertions in such a way that a tool can statically prove aspects of the program’s correctness. There is some overlap with contracts: this proposal can be thought of as an alternative to contracts, with more ambitious goals; the author believes unification of the proposals is possible. A notable difference from existing proposals is that, rather than trying to express reasoning about a procedural program in language resembling mathematics, this seeks to “express the mathematical proof of a program’s correctness in a procedural way”.
    • Template deduction for nested classes. Currently, a type like A<T>::type, where T is a template parameter, is a “non-deduced context”, meaning that if a function parameter’s type has this form, T cannot be deduced from the corresponding argument type. (Template argument deduction also comes up in the process of matching class template partial specializations, so this restriction means you also can’t specialize a template for, say, “vector<T>::iterator for all T“). The main reason for this restriction is that in A<T>::type, type can name either a nested class, or a typedef. If it names a typedef, the mapping from A<T>::type to T may not be invertible (the typedef may resolve to the same type for different values of T), and even if it’s invertible, the inverse may not be computable (think complex metaprograms). However, if type names a nested class (and we make the case where an explicit or partial specialization makes it a typedef ill-formed), there is no problem, and this proposal suggests allowing that. EWG’s feedback was mainly positive, but a significant concern was raised: this proposal would make whether type names a nested class or a typedef part of A‘s API (since one is deducible and the other isn’t), something that wasn’t the case before. In particular, in a future world where this is allowed, the common refactoring of moving a nested class out to an outer level and replacing it with a typedef (this is commonly done when e.g. the enclosing class gains a template parameter, but the nested class doesn’t depend on it; in such cases, leaving the class nested creates unnecessary code bloat), becomes a breaking change. The author may have a way to address this using alias-templates; details with forthcome in a future revision of the proposal.
    • Pointers to reference members. It is currently invalid to form a pointer to a reference, which means you can’t have a pointer to a member if that member has reference type. This is inconvenient for the reflection proposal, which allows iterating over the data members of a class and getting a pointer to each; currently, such iteration has to skip over members of reference type. This proposal explores filling that hole by allowing pointers to reference members (without allowing pointers to references in general). EWG was open to the idea, but was concerned about this being a slippery slope and eventually opening the door to things like arrays of references. It was also pointed out that reflection has other options available to it. For example, some have proposed an unreflexpr operator which does the reverse of reflexpr: that is, given a meta-object representing an entity in a program (as obtained by reflexpr, or by navigating the meta-object graph starting from another meta-object obtained via reflexpr), unreflexpr gives you back that entity. This would avoid the need to form a pointer to a reference data member: given a meta-object representing the reference data member, you’d just call unreflexpr on it and use the result in places where you’d dereference the pointer.
    • Implicit move on return from local and function parameter rvalue references. This proposes that when a return-expression names a local or parameter variable of rvalue reference type, the return implicitly move it (currently, if you don’t use std::move, std::forward, or similar, a copy is made, because a named rvalue reference is still an lvalue). This would be a breaking change, but the breakage is likely to be limited to situations where the code is already buggy, or using move semantics improperly. EWG encouraged exploration of the scope of breakage in real-world code.

    Rejected proposals:

    • Reconsidering literal operator templates for strings. This is a proposal to allow user-defined literal strings, such as "string"op, where op would get the characters of the string as arguments to a template<char...>. This was originally rejected over compile-time performance concerns (processing many template arguments is expensive), and it was suggested that the proposal be revised with additional machinery for compile-time string processing (which would presumably address the performance concerns). This reincarnation of the proposal argued that literals of this form have a variety of uses unrelated to string processing, and as such requiring accompanying string processing machinery is overkill; however, the underlying performance concerns are still there, and as a result the proposal was still rejected in its current form. It was pointed out that a more promising approach might be to allow arrays (of built-in types such as characters) as non-type template parameters; as such, the string would be represented as a single template argument, alleviating many of the performance issues.
    • A char8_t type for UTF-8 character data, analogous to the existing char16_t and char32_t. This was previously proposed, albeit in less detail. The feedback was much the same as for the previous proposal: consult more with the Library Evolution Working Group, to see what approach for handling UTF-8 data is likely to actually gain traction.
    • Static class constructors. These would be blocks of code associated with classes that run once, during static initialization. EWG found this proposal to be insufficiently motivated, observing that at least some of the problems the proposal aims to solve are addressed by inline variables. It was also observed that the proposal doesn’t solve the issue of order-of-initialization of static objects across translation units; some consider solving that to be a blocker for other advancements in the area of static initialization.
    • Template argument deduction for non-terminal function parameter packs. The motivation here is to be able to write things like template<typename... Args, typename Last> void foo(Args... args, Last last) – basically, pattern-matching on a list of variadic arguments to separate and deal with the last one first. This is currently ill-formed, mostly because it’s unclear what the semantics should be in the presence of default arguments. EWG was disinclined to allow this, preferring instead to address the use case of “get the last element of a parameter pack” with a more general pack indexing facility (one such facility is reportedly in the works; no paper yet).

    Other Working Groups

    Having sat in EWG all week, I don’t have a lot of details to report about the proceedings of the other groups (such as Library Evolution or Concurrency) besides what I’ve already said above about the progress of Technical Specifications and other major features.

    I do have a few brief updates on some Study Groups, though:

    SG 7 (Reflection)

    SG 7 had an evening session this meeting, during which it reviewed and gave its final blessing to the static introspection proposal, also known as reflexpr after the operator it introduces. This proposal will now make it way through the Evolution and Library Evolution groups starting next meeting.

    Being a first pass at static introspection, the proposal has a well-defined scope, providing the ability to reflect over the data members and nested types of classes and the enumerators of enumerations, but not some other things such as members of namespaces. Reflecting over uninstantiated templates also isn’t supported, in part due to difficulty-of-implementation concerns (some implementations reportedly represent uninstantiated templates as “token soup”, only parsing them into declarations and such at instantiation time).

    Notably, the proposal has a reference implementation based on clang.

    The proposal currently represents the result of reflecting over an entity as a meta-object which, despite its name, is a type (keep in mind, this is compile-time reflection). A suggestion was made to use constexpr objects instead of types, in the same vein as the Boost Hana library. SG 7 was hesitant to commit to this idea right away, but encouraged a paper exploring it.

    The facilities in this proposal are fairly low-level, and there is a room for an expressive reflection library to be layered on top. Such a reflection library could in turn use a set of standard metaprogramming facilities to build upon. SG 7 welcomes proposals along both of these lines as follow-ups to this proposal.

    SG 13 (Human-Machine Interaction)

    SG 13’s main work item, the Graphics TS, is working its way through the Library Evolution Working Group.

    The group did meet for an evening session to discuss a revision of another proposal concerning input devices. I wasn’t able to attend, but I understand the main piece of feedback was to continue pursuing harmony with the asynchronous programming model of the Networking TS.

    SG 14 (Game Development & Low-Latency Applications)

    SG 14 didn’t meet this week, but has been holding regular out-of-band meetings, such as at GDC and CppCon, as well as teleconferences. The group’s mailing list is a good place to keep up with progress in the area.

    Next Meeting

    The next meeting of the Committee will be in Kona, Hawaii, the week of February 27th, 2017.

    Conclusion

    C++17 is turning out to be an exciting release of the language, with the most talked-about features including: on the language side, structured bindings, class template argument deduction, and if constexpr; on the library side, the filesystem facilities, and vocabulary types like variant and optional; and on the concurrency side, the parallel versions of the standard library algorithms.

    This meeting was spent polishing this feature set in preparation for the C++17 standard’s official release next year.

    Meanwhile, we are looking forward to an even more exciting C++20, which may contain features ranging from Concepts, Ranges, and Networking to Modules and Coroutines, with some of these already available as Technical Specifications, or soon to be.

    I look forward to continuing to participate in and report on the standardization process!

    Posted in c++, programming | Tagged , , | 6 Comments