C++ Papers for Issaquah - Concepts, Database & Evolution

by Jens Weller

This is the second part about the papers for the C++ committee meeting in February in Issaquah. This time featuring papers from the subgroups of concept, database and evolution. Again, most papers in this series aim for a standard after C++14, most important for C++14 will be the national comments on the new standard. Also there are no new papers from the core working group, only the active issues, defects report and closed issues report are on this mailing. The last part featured the papers for concurrency.

Concepts

N3878 - Extension to the Concept Introcution Syntax in Concepts Lite

The following paper is the specification for Concepts Lite, this paper explores possible Extensions to the Syntax of Concept Introduction. Concept Introduction is in the paper defined as:

Concepts Lite introduced the notion of "concept introduction", a shorthand for declaring a template whose template parameters are constrained by a multi-argument constraint.

The authors now would like to move the Concept Introduction into the templates parameter list, instead of adding it before:

//currently
Mergeable{For1, For2, Out}
void merge(For1 p, For1 q, For2 p2, For2 q2, Out o);
// with the planned extension
template<Mergeable{For1, For2, Out}>
void merge(For1 p, For1 q, For2 p2, For2 q2, Out o);

This could be combined with normal template parameters. I think this proposal is a good example for how concepts lite still could be improved to have a better syntax.

N3889 - Concepts Lite Specification

This is the specification for the Concepts feature, hopefully to be part of C++1y.

Concepts was once thought to be the flagship of C++11, but was dropped, as it turned out to be as a feature just too heavy. Still, C++ should have some way of constraining templates to a certain form of concepts. There was a talk about concepts lite at the Meeting C++ 2013 conference from Peter Sommerlad, which will go more into the details, then I can do here.

This paper is the current approach, a much lighter version of concepts. Concepts Lite is currently implemented as a branch of GCC 4.9, and the authors claim that concepts lite:

  • allows programmers to directly state the requirements of a set of template arguments as part of a template’s interface
  • supports function overloading and class template specialization based on constraints
  • seamlessly integrates a number of orthogonal features to provide uniform syntax and semantics for generic lambdas, auto declarations, and result type deduction
  • fundamentally improves diagnostics by checking template arguments in terms of stated intent at the point of use, do all of this without any runtime overhead or longer compilation times
  • do all of this without longer compilation times or runtime overhead.

A short example how concepts lite could look like:

template<Sortable Cont>
void sort(Cont& container);

Here, Sortable is the constraint. It is in this case defined to require a random access iterator and the operator<. The Sortable constraint acts as type of Cont here, but is defined else where. So this is not the definition of a constraint, it is the use of a constraint. A alternative syntax allows to specify the constraints more exactly with require:

template<typename Cont>
 requires Sortable<Cont>()
void sort(Cont& cont)

This allows to explicit state the requirements for a template after its interface definition. A constraint is now defined as:

"An constant expression that evaluates properties of template arguments, determining whether or not they can be substituted into a template."

So, a more complex constraint definition could look like this:

template<typename T> concept Equality_comparable() 
{
 return has_eq<T>::value
        && is_convertible<eq_result<T>,bool>::value
        && has_ne<T>::value 
        && is_convertible<ne_result<T>,bool>::value;
}

To aid the implementation of concepts, the authors also introduce a way to implement constraints as a requires expression:

template<typename T>
constexpr bool Equality_comparable()
{
return requires (T a, T b) {
   bool = {a == b};
   bool = {a != b};
  };
}

The paper goes on further into the details of implementing a concept lite approach. Even concepts lite brings a lot of changes to the language. So that if it makes into an upcoming standard, it will change a lot how we interface with templates in C++. In exchange error messages and the work with templates would improve a lot.

Database

I think this is the first time, I ever cover papers from this subgroup. Database is still very in its beginning, so IMHO the proposals have a long way to go. Also, I think that its clear that Database support will not be part of any C++ standard soon.

N3868 - Type-safe database access

This paper sounds interesting, and I'd love to read it, sadly its only listed as missing from the mailing. :/

N3886 - A Proposal to add a Database Access Layer to the Standard Library

This paper tries to lay the foundation for a possible std::db/std::sql API that allows the access to databases and execution of SQL. The paper does define a concrete interface with classes, which for example are:

  • connection
  • statement
  • result
  • transaction
  • parameters

These classes are the public interface, they are backed by private interface classes, which shall implement the details. For example there is a connection_interface class. The interface classes consist out of pure virtual methods. Further helper classes and classes for the datatransport are defined. The authors state that this proposal is still in its early stage.

The proposal builds up on older proposals and existing libraries. Still, I'd like to see C++11 and maybe C++14 be more reflected in a future proposal, currently its only a collection of (mock up) classes to access Databases via SQL. A very interesting approach is also sqlpp11.

Evolution

N3839 - Proposing the rule of 5

Before C++11 there was the rule of 3, which even dates back to 1991, the early days of C++. The rule of 3 is a rule of class design guideline in C++. It states that a class should often have a copy constructor, a assignment operator and a destructor if any of these are needed to be explicitly implemented. This proposal now proposes that the rule of 3 should become a rule of 5, adding move constructor and move assignment operator. The authors propose:

To be known informally as the “rule of five,” we propose that no copy function, move function, or destructor be compiler-generated if any of these functions is user-provided

I'd like to add that there is also the idea of having the rule of 0 as a design principle in C++11 popular. Which means, that you should implement your classes in a way, that the compiler can generate the correct code for the "rule of 5" functions. Peter Sommerlad mentioned this in his talk "Simpler C++ Code through C++11" at Meeting C++ 2013.

N3846 - Extending static_assert

This paper wants to extend static_assert with having the option to define a text message. This could make asserts much more readable. This is a very often requested feature, the paper starts with a short overview of ideas how to improve static_assert with a the option to have a text message. The paper shows that there are 5 competing solutions:

  • "common wording":
    • std::static_assert(const-expression)
    • std::static_assert(const-expression,string-literal)
  • only the second option of above, but if the string literal is empty it gets replaced with the text of the const-expression.
  • again, only the second option of the common wording, but if no string-literal is supplied, the message shall be implementation-defined.
  • also, one option would be to only include the string-literal in the diagnostic message, if one is supplied.
  • Instead of using a string-literal for the message, this could also be a (optional) const-expression-list of values (convertible to text):
    • std::static_assert(const-expression,const-expression-list)

The authors do not draw a conclusion which would be best.

N3853 - range based for loops, the next generation

When you start using C++11, often you notice how range based for loops are often a very easy option to use in your code. This paper tries to improve the current ranged-for loop by adding another different version of it. Currently when using a ranged-for loop like this:

for(auto item: rage){...}
for(auto& item: range){...}

The first version will generate a copy for each item, which can be a serious performance problem. The second version works on the original items in the container. The first version also has the problem that it might not compile, f.e. move only types or vector<bool>.

Also the second way is not perfect, it will not work with proxy objects (vector<bool> f.e.), for(const auto& item, r) is for some situations a better solution, but still the author thinks, there should be a better way.

The paper sees some flaws in the current use of ranged-for:

  • its too easy to unintentionally copy objects
  • using the correct element type instead of auto is often harder to get right.
  • programmers might just don't think about taking parameters by value in a for-loop
  • traditionally for loops refer to the item in the container with indexes or iterators.

The author claims, that currently the best usage for a ranged-for loop would be for(auto&& item: range), but that this would also yield to introduce people to r-value references, universal references and prefect forwarding with auto&&. The author concludes that the obvious solution would be to introduce a new default syntax for ranged-for loops:

for(item:range){}
for(auto&& item:range){}

The above new syntax of just specifying the name of the iterating variable, would allow the compiler to automatically use auto&& as the default type. It would be an elegant way to let people use a shortcut to the best solution.

N3859 - Transactional Memory Support for C++

This proposal is based on the work of the Transactional Memory subgroup (SG5). New with this paper is the idea of synchronized and atomic blocks:

synchronized {block}
atomic noexcept {block}
atomic commit.except{block}
atomic cancel.except{block}

A synchronized block has the semantics of being protected by a mutex for example, always only one thread is allowed to enter, every other thread has to wait till the first thread has left the block. A synchronized block could be implemented with a mutex, or with transactional memory. A synchronized block can be nested into other synchronized blocks, a race condition should not occur.

A atomic block consists of the keyword atomic, and the exception specifier. The 3 available exception specifier offer this behavior:

  • noexcept in case of an uncaught exception std::abort is called
  • commit.except: the transaction is committed and the exception is thrown.
  • cancel.except: the transaction is canceled, and the exception is thrown if the exception is transaction safe, otherwise std::abort is called.

An exception is transaction-safe if its a scalar type or of a certain range of standard exceptions (std::bad_alloc, std::bad_cast and a few more, see the paper for details). Also the authors conclude that this list might be extended in the future.

The authors see the benefit of atomic blocks in

Atomic blocks are intended in part to replace many uses of mutexes for synchro-nizing memory access, simplifying the code and avoiding many problems introduced by mutexes (f.e. dead locks)

N3860 - Towards restrict-like semantics for C++

This paper is missing, you might want to read the previous paper N3635.

N3863 - Private Extension Methods

The goal of this proposal is to add a new method for declaring private member functions to C++. This would not break any existing code. The goal and conclusion of this paper by the author:

We conclude that non-virtual private method and private static member function declarations are not a part of the class interface and thus should not be required in the class definition.

So, the goal of this proposal is...

We propose that private non-virtual methods and private static methods should be able to be declared outside of the class definition. Not only does this change not break encapsulation, it actually improves encapsulation because unessessary implementation details are being removed from the interface. Unlike PIMPL or other related encapsulation techniques, this new feature has no run time overhead. We believe the implementation of this feature could also be another step towards modules in C++.

As this is a pure language feature, it will not be part of C++14, and may even take longer to mature for C++1y. Also this idea deals with the core syntax and semantics of classes in C++, so that some discussion on syntax and full impact is needed. In combination with modules this feature could be nice.

N3867 - Specializations and namespaces (Rev. 2)

Handling specializations and namespaces is currently in such a way, that you need to specialize a template in the namespace it is declared. So, when your class C is in the nested namespace A::B, you'll need to close the namespaces and enter the namespace std before you can specialize std::hash for class A::B::C. After this, you'll might need to reopen A::B. It would be better if you could specialize templates in the current namespace like this:

template<> struct ::std::hash 
{ std::size_t operator()(C const &c) { /* ... */ } };

The standard provides a couple of templates that need specialization, std::hash or std::less are just common examples.

N3875 - Run-time bound array data members

This paper is a follow up on the discussions of this topic in the chicago meeting, which is summarized in N3810. This paper takes a closer look at one of the options mentioned in N3810.

The goal is to provide a general way for de ning automatic storage arrays (i.e. stack allocated or side-stackallocated) whose size is not known at compile time.

Variable length Arrays (VLAs) already exist in C since C99, there has been some effort to also make this feature available in C++. Originally being part of the draft of C++14 from Bristol, they were removed from the C++14 draft in Chicago, as the committee thought that further discussion is needed. Hence the committee decided that there should be a technical report about array extensions.

This proposal now is about how to handle data members as VLAs. A short example:

class x{
  x(size_t size);
  x();
private:
  int[] iarr;
};
x::x(size_t size):iarr{size}
x::x():iarr[4]{}

N3879 - Explicit Flow Control: break label, goto case and explicit switch

This proposal wants to add a few new variations of goto, break, and continue:

  • break label
  • coninue label
  • goto case const-expression
  • goto default

The first two are inspired by Java, the last two by C#. Also the authors would like to add an explicit switch label. This would give C++ more jump statements and labels more meaning, also goto could be useful.

N3880 - Improving the Verification of C++ Programs

There has been already a very good paper on defensive programming, this paper is more about testing. It tries to summarize a what is important about software quality and testing in todays world. From this it draws a few conclusions about where C++ could be improved in order to have better verification of C++ Programs.

N3883 - Code checkers & generators

This proposal aims at adding code checkers and generators to C++, so that some code can be generated at compile time. For this, the authors want to introduce new syntax and with $ prefixed keywords. This would allow to integrate some kind of code template system into C++, generating code at compile time. The authors say they're inspiration comes from AngularJS. With the new code checkers and generators also C Macros and TMP could be deprecated the authors say.

While I like the idea (I have written Code generators for C++ for some times), I think some of the statements in this proposal are very bold, and I'd first like to see a working implementation, also this will be huge change to C++.

N3897 - Auto-type members

The author states that this is not a proposal, just a paper summing up previous discussions on this topic. The idea is, to have auto as a type specifier for member variables in classes or structs. With C++11 it its possible to initialize a member in its declaration struct foo{ int bar = 0; };, the idea is now to replace int with auto. But this idea seems not to have spread too far through the committee, as the paper ends with

"since the number of committee wizards who have voiced serious concerns about this feature outnumbers the dwindling few who have voiced a strong interest in this feature - unless the winds of opinion undergo a dramatic change - it is my view that the authors of any future paper on this topic might do better to spend there time elsewhere."

N3899 - Nested Allocation

This paper goes into the direction of VLAs and runtime sized arrays again. This time looking at the possible allocation choices. As mentioned before, VLAs and runtime sized arrays (std::dynarray) were removed from the C++14 draft in Chicago. They will now form their own technical specification. This paper gives a good overview of the current state on this topic. But its focus is on allocation, other issues with VLAs or runtime sized arrays are not handled.

 

 

Go back

Follow Meeting C++

tl_files/mcpp/yt.pngtl_files/mcpp/gplus-50.pngtl_files/mcpp/twitter.pngtl_files/mcpp/facebook.png