A Quick Look at What P1754 Will Change (Part 1)

*Date published: 2019-07-08

P1754, or Rename concepts to standard_case for C++20, while we still can is a proposal with a single, abundantly clear goal outlined in its name: to change the naming convention for all standard concepts from PascalCase to snake_case. Examples in P1754 are sadly lacking: it would have been nice to see an algorithm or two with the differences displayed side-by-side. I was curious about what it would look like, so I decided to contrast the two using the library that’s benefited from concepts the most: our algorithms library.

// Status quo
template<InputIterator I, Sentinel<I> S, class T, class Proj = identity>
requires IndirectRelation<ranges::equal_to, projected<I, Proj>, T*>
constexpr I find(I first, S last, const T& value, Proj proj = {});

// P1754's suggestion
template<input_iterator I, sentinel_for<I> S, class T, class Proj = identity>
requires indirect_relation<ranges::equal_to, projected<I, Proj>, T*>
constexpr I find(I first, S last, const T& value, Proj proj = {});
// Status quo
template<ForwardIterator I, Sentinel<I> S, class T, class Proj = identity,
         IndirectStrictWeakOrder<const T*, projected<I, Proj>> Comp = ranges::less>
constexpr I upper_bound(I first, S last, const T& value, Comp comp = {}, Proj proj = {});

// P1754's suggestion
template<forward_iterator I, sentinel_for<I> S, class T, class Proj = identity,
         indirect_strict_weak_order<const T*, projected<I, Proj>> Comp = ranges::less>
constexpr I upper_bound(I first, S last, const T& value, Comp comp = {}, Proj proj = {});
// Status quo
template<InputIterator I1, Sentinel<I1> S1, RandomAccessIterator I2, Sentinel<I2> S2,
         class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity>
requires IndirectlyCopyable<I1, I2> && Sortable<I2, Comp, Proj2> &&
         IndirectStrictWeakOrder<Comp, projected<I1, Proj1>, projected<I2, Proj2>>
constexpr I2 partial_sort_copy(I1 first, S1 last, I2 result_first, S2 result_last,
                               Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {});

// P1754's suggestion
template<input_iterator I1, sentinel_for<I1> S1, random_access_iterator I2, sentinel_for<I2> S2,
         class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity>
requires indirect_copyable<I1, I2> && sortable<I2, Comp, Proj2> &&
         indirect_strict_weak_order<Comp, projected<I1, Proj1>, projected<I2, Proj2>>
constexpr I2 partial_sort_copy(I1 first, S1 last, I2 result_first, S2 result_last,
                               Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {});

The underscores serve as spaces in the names, which in my opinion, make the concepts significantly easier to read – particularly in the case of partial_sort_copy, which is quite a mouthful. I’ve also applied the snake_case concepts to my numeric algorithms proposal, and it’s helped to improve that document’s readability there too. I imagine production code using the snake_case concepts will benefit even more than the spec.

Concerns and the status quo

I’ve seen many people express distaste for the proposed change side due to the fact that ‘we’ve always named our concepts using PascalCase’. We haven’t: we have a set of tables in the standard library that outline requirements, and we name these requirements EqualityComparable, and so on. While they do use PascalCase, those names are used to alias tables that appear only to aid in understanding the standard prose, and don’t represent any standard identifier.

Secondly, it’s easy to come to the conclusion that because there’s a named requirement called EqualityComparable and a concept called EqualityComparable, of course the concept is just a way for us to express our requirements in a compiler-checkable way. This is misguided: the concept EqualityComparable goes way deeper than the named requirement EqualityComparable. It is left as an exercise to the reader to distinguish the differences between the two. (One should note that the named requirement has been rebranded as Cpp17EqualityComparable to signify that it’s different to the concept, and that the font face has changed from verbatim to italics, which means that there shouldn’t be any more names in the standard spelt using PascalCase.)

Finally, our current templates look like this:

template<class I>
template<typename I>
template<auto N>
template<int N>

They do not look like this:

template<Class I>    // error: template type parameter declared using 'class' or 'typename'
template<Typename I> // error: template type parameter declared using 'class' or 'typename'
template<Auto N>     // error: template non-type parameter declared using 'auto' or an integral type
template<Int N>      // error: template non-type parameter declared using 'auto' or an integral type

In other words, my take on this, is that P1754 aims to restore what we’ve always done, which is to use a synonym of typename to declare a type parameter in snake_case, and we name our type parameter in PascalCase. When I pointed this out to Herb, he mentioned that this is already articulated in §1.1.3.

Who’s co-authoring it?

All of the major authors for both concepts and ranges have co-authored P1754, and are unanimous that this should happen. Being the architects for these features, it is likely that they collectively and individually have the most experience of anyone with these names. We should solemnly acknowledge this experience, and at least heavily experiment with their proposal before digging our heels in and claiming that the aberration in the standard library should remain status quo.

Conclusion

Some of the names, such as has_common_reference and range_type are a bit controversial, but can be bikeshedded (‘workshopped’) in the committee meeting next week. If I get around to it, I’ll throw up a Part 2 concerning my thoughts about the less savoury names, but I want to make my position unambiguously clear: I do not think that the current P1754 names should be a showstopper for letting this proposal be standardised.

I understand that there’s concern around renaming these concepts – and P1754’s authors are also aware of this – but I fear that the concern is misplaced. We should embrace the change that P1754 seeks to make, so that our code doesn’t become too squashed, like partial_sort_copy.

At the very least, please write a non-trivial example with the new names, so that you’ve got something to back you up when you say “I don’t like it”.