Document number:     
Date:
Project:
Reply-to:
N2916=09-0106
2009-06-22
Programming Language C++, Core Working Group
David Abrahams <dave at boostpro dot com>
Beman Dawes <bdawes at acm dot org>

Intentional Concept Mapping

Introduction

A C++0x concept map can be useful (among other things) as:

As of CD1, concept maps used for this purpose are often empty:

class Endian
{
  ...
};

concept_map std::Regular<Endian> {}
concept_map std::StandardLayoutType<Endian> {}
concept_map std::TrivialType<Endian> {}

Although this formulation is technically sufficient and will ensure the type models the concepts, it has some problems:

This paper proposes that the above code could also be written as:

class Endian -> std::Regular, std::StandardLayoutType, std::TrivialType
{
  ...
};

Syntax

The proposed wording uses -> as a syntax marker for the beginning of the list of concepts to be mapped. The authors considered several alternate keyword and punctuation possibilities and are not wedded to the use of ->. We welcome syntax suggestions from the committee (keeping in mind the usual "bicycle shed" caveat, of course!)

We describe here our rationale for rejecting the use of requires as a marker only because we consider the argument sufficiently subtle to be a potential time-waster for the committee. The problem is that using requires makes a concept_map look too much like a requires clause in a region of code where either one could appear. A concept_map is fundamentally different from a requires clause. When you write:

template <typename X>
  requires<EqualityComparable<X> >
class Y
{
   ...
};
you're just constraining X, nothing more.  It's pure requirement checking.  However, when you write:
template <typename X>
class Y -> EqualityComparable
{
   ...
};
you're generating a concept map for all specializations of Y, with all that that implies (e.g. generation of defaults, Y<T> can be used where EqualityComparable is required, etc):
// generated by the above
template <typename T>
concept_map EqualityComparable<Y<T> > { };

Motivation

The critical motivation for this proposal is the desire to be able to say "my type models concepts XXX, YYY, and ZZZ, and please tell me if I get it wrong (structurally)", and to do that in such a way that users and maintainers understand that this is part of my  type's public interface and not just happenstance.

This proposal is not replacement for concept maps; we view concept maps—even empty ones—as meeting critical needs. We wish to make empty concept maps more convenient, more expressive, and less verbose in the common case where one is intentionally creating a model of a known concept. Empty concept_maps will still be needed in their current form for nonintrusive post-hoc adaptation of types to concepts, an important function of concept_maps in general.

Another important motivation for this proposal is that it provides a powerful platform for the common case of exported concept maps as proposed by N2918=09-0108, with zero syntactic overhead.

Proposed Wording

Change 9 Classes [class] as indicated:

A class is a type. Its name becomes a class-name (9.1) within its scope.

class-name:
      identifier
      simple-template-id

Class-specifiers and elaborated-type-specifiers (7.1.6.3) are used to make class-names. An object of a class consists of a (possibly empty) sequence of members and base class objects.

class-specifier:
      class-head
{ member-specificationopt }

class-head:
      class-key identifieropt attribute-specifieropt mapped-concept-clauseopt base-clauseopt
      class-key nested-name-specifier identifier attribute-specifieropt mapped-concept-clauseopt base-clauseopt
      class-key nested-name-specifieropt simple-template-id attribute-specifieropt mapped-concept-clauseopt base-clauseopt

class-key:
      class
      struct
      union

After 9.9 Nested type names [class.nested.type], add:

9.10 Intentional concept mapping [class.concept.mapping]

mapped-concept-clause:
     
-> mapped-concept-list

mapped-concept-list:
      mapped-concept,  mapped-concept-list
      mapped-concept

mapped-concept:
     
::opt nested-name-specifieropt concept-name

A mapped-concept-clause contains a list of concepts to map to. A concept is "mapped to" for each mapped-concept as if by a concept_map([concept.map]). The concept_map acts as if it appears immediately after the class being defined, and is equivalent to:

concept_map Concept<Class> {};

where Concept is the mapped-concept, and Class is the class where the mapped-concept-clause appears.

[Example:

template <typename X>
  class Y -> EqualityComparable
  {
     ...
  };

The above implicitly generates the following concept map:

template <typename T>
  concept_map EqualityComparable< Y<T> > {};

--end example]

Acknowledgements

Several people on the committee reflectors suggested features similar to this proposal, often with syntax using the requires keyword. Jerry Schwarz, in committee message c++std-lib-23459, suggested syntax that mimics inheritance.