Why don't concepts look like and get called like functions?

207 views
Skip to first unread message

gmis...@gmail.com

unread,
Oct 24, 2018, 9:09:52 PM10/24/18
to ISO C++ Standard - Future Proposals
A few thoughts on Concepts:

As Concepts have evolved, I have found it difficult to get a handle on what Concepts actually are.
i.e.: Are Concepts functions, types, or something else?

Bjarne's CppCon 2018 talk "Concepts: The Future of Generic Programming" answers that question clearly.
In his talk, Bjarne says:
* Concepts are NOT types of types. They are NOT type classes.
* Concepts can take more than one argument.
* Concept is a specification of what one or more types can do.

At around 1:06:30 in his talk Bjarne says:
* "it's just like defining functions, you *ARE* DEFINING FUNCTIONS".


So I want to ask:

-----
If concepts ARE functions why don't they look like functions?
Perhaps they should?
-----


The Concepts defined in Bjarne's talk look more like variable definitions *defined* in what feels (to me) like an odd mix of logic and type like syntax:

template<typename X> using Value_type = X::value_type;
template<typename X> using Iterator_of = X::iterator;

template<typename For, typename For2, typename Out>
concept Mergable =
    ForwardIterator<For>
    && ForwardIterator<For2>
    && OutputIterator<Out>
    && Assignable<Value_type<For>,Value_type<Out>>
    && Assignable<Value_type<For2>,Value_type<Out>>
    && Comparable<Value_type<For>,Value_type<For2>>;


The above looks like a variable definition. If it is not, then is it right that it looks like one?
It's a definition, with conditional logic et al. i.e it uses &&. etc. like an inline function.
So why are we defining it NOT using function like snytax?
Why is this a good thing?

I find this function as a variable thing confusing to coming to terms with what Concepts actually are.

If Concepts ARE functions as Bjarne says, why shouldn't they look and be composed using functional notation?

It seems I'm not alone in this feeling. J. Monnon proposes this:
Type functions and beyond
An exploration of type functions and concept functions
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0844r0.html

He says: "This document proposes to extend functions to let them operate directly on types and concepts.
The goal is to allow writing metaprogramming in the most intuitive and consistent way with the rest of the language."

J. Monnon says:

Here is an example of a type function:
    ForwardIterator IteratorType(typename T) {
        // In a type function, an `if` behaves as a `if constexpr`.
        if (Container(T))  // `Container` is a concept
            return T::iterator;
        else if (Array(T)) // `Array` is a concept
            return Decay(T);
    }

    // On call site:
    typename I = IteratorType(C);


J. Monnon says:
"A type function is always executed at compile-time. Here, it takes a type T and returns another type that models the ForwardIterator concept. Type functions allow a natural and straightforward notation to manipulate types."

This also justifies his comment which I emphasise: // In a type function, an `if` behaves as a `if constexpr`.

At this time, I agree with J. Monnon's proposal. I find it intuitive and insightful if I understand it correctly.
If J. Monnon's paper has been discussed at any length anywhere, can someone please tell me the outcome?
His proposal appeared on Reddit at one point but attracted a near zero response there, which stunned me.
I'd certainly like to see more commentary on that proposal here before the next Standards meeting that is imminent.

I may be wrong, but doesn't the D language go this route also? What is so wrong with that approach that C++ goes it's own way?

There is more I would like to say about Concepts such as why I hate the syntax as currently proposed.
But for now, I'd really like to focus this discussion on the main elements I've raised.
1. If concepts ARE functions, why aren't we defining and using them with function like syntax? And using () not <>.
2. It seems J. Monnon's proposal is making the same point as I am, only much better? Can we please address all that he proposes?
3. I feel a more formal response to J. Monnon's paper from the main proponents of Concepts as currently defined should be made before concepts get wired in any further in it's current direction?

I know many people would like Concepts be the marquee feature of C++20, but to me Concepts still seem quite away from where I'd like them to be.
Even Bjarne can only 'begrudgingly live' with the current syntax.
All this flux and begrudging really doesn't suggest to me that Concepts are ready to go for C++20.
This is even before any of my comments or J. Monnon's paper is taken into account.

Right now, I feel that if Modules and Coroutines were the only main features that hit for C++20, I'd be happy with that.
If people can explain why my comments are on the mark or misplaced and what the issues are with J. Monnon's proposal, I'd be grateful.

Thanks

mihailn...@gmail.com

unread,
Oct 25, 2018, 3:04:06 AM10/25/18
to ISO C++ Standard - Future Proposals
If you dig the history of Concepts - they were allowed to be defined as functions, though used the same way as today.
And until literally an year ago, the were like a variable, one had to add bool before the name.

Right now the syntax does not have anything superficial, which is an improvement. 

What Bjarne meant was two things - if you have complex logic you extract ito a function, or chop it in multiple functions. He meant composition. 
He repeated it, this time in the meaning that they are ultimately functions that take type and return bool (pass/no-pass).

 

I find this function as a variable thing confusing to coming to terms with what Concepts actually are.

It is best to think of Concepts as, well, Concepts, a type-consternating construct that is instantiated as templated variable,
 but the compiler uses it as function returning bool

Instead of 
requires something<T>()
you can
requires Something<T>
 

All in all, a care is taken to streamline Concepts as much as possible. 

 

If Concepts ARE functions as Bjarne says, why shouldn't they look and be composed using functional notation?

It seems I'm not alone in this feeling. J. Monnon proposes this:
Type functions and beyond
An exploration of type functions and concept functions
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0844r0.html

He says: "This document proposes to extend functions to let them operate directly on types and concepts.
The goal is to allow writing metaprogramming in the most intuitive and consistent way with the rest of the language."

J. Monnon says:

Here is an example of a type function:
    ForwardIterator IteratorType(typename T) {
        // In a type function, an `if` behaves as a `if constexpr`.
        if (Container(T))  // `Container` is a concept
            return T::iterator;
        else if (Array(T)) // `Array` is a concept
            return Decay(T);
    }

    // On call site:
    typename I = IteratorType(C);



Now this is something completely different - note how the function returns a different type, not a bool

This proposal  is adding type transformation machinery,  in contrast to  Concepts which are type filtering machinery


 
J. Monnon says:
"A type function is always executed at compile-time. Here, it takes a type T and returns another type that models the ForwardIterator concept. Type functions allow a natural and straightforward notation to manipulate types."

This also justifies his comment which I emphasise: // In a type function, an `if` behaves as a `if constexpr`.

At this time, I agree with J. Monnon's proposal. I find it intuitive and insightful if I understand it correctly.
If J. Monnon's paper has been discussed at any length anywhere, can someone please tell me the outcome?
His proposal appeared on Reddit at one point but attracted a near zero response there, which stunned me.
I'd certainly like to see more commentary on that proposal here before the next Standards meeting that is imminent.

I may be wrong, but doesn't the D language go this route also? What is so wrong with that approach that C++ goes it's own way?

There is more I would like to say about Concepts such as why I hate the syntax as currently proposed.
But for now, I'd really like to focus this discussion on the main elements I've raised.
1. If concepts ARE functions, why aren't we defining and using them with function like syntax? And using () not <>.
2. It seems J. Monnon's proposal is making the same point as I am, only much better? Can we please address all that he proposes?
3. I feel a more formal response to J. Monnon's paper from the main proponents of Concepts as currently defined should be made before concepts get wired in any further in it's current direction?

I know many people would like Concepts be the marquee feature of C++20, but to me Concepts still seem quite away from where I'd like them to be.
Even Bjarne can only 'begrudgingly live' with the current syntax.
All this flux and begrudging really doesn't suggest to me that Concepts are ready to go for C++20.
This is even before any of my comments or J. Monnon's paper is taken into account.

 
Right now, I feel that if Modules and Coroutines were the only main features that hit for C++20, I'd be happy with that.
If people can explain why my comments are on the mark or misplaced and what the issues are with J. Monnon's proposal, I'd be grateful.

Modules and Coroutines don't have good chances for 20. 
The main new features will be Concepts and Contracts. 

Your comments are perfectly valid and people teaching C++ should take them into account - the fact people can be confused about variable vs function.

As for J. M, proposal - we must see how this would compare with Reflections as Reflection will also be able to "emit code" and "return a type".
 

Thanks

Klaim - Joël Lamotte

unread,
Oct 26, 2018, 6:19:46 AM10/26/18
to std-pr...@isocpp.org
On Thu, 25 Oct 2018 at 09:04, <mihailn...@gmail.com> wrote:
> Modules and Coroutines don't have good chances for 20.
> The main new features will be Concepts and Contracts.

Quick correction: from what I hear, Modules have good chances as there
have been a strong convergence in the last weeks/months and
apparently.

> As for J. M, proposal - we must see how this would compare with Reflections as Reflection will also be able to "emit code" and "return a type".

It would be interesting to have some feedback of this proposal from
the MetaProg/Reflection group, I believe they didn't publicly comment
on it yet.

A. Joël Lamotte

Arthur O'Dwyer

unread,
Oct 27, 2018, 4:27:58 PM10/27/18
to ISO C++ Standard - Future Proposals
On Wednesday, October 24, 2018 at 9:09:52 PM UTC-4, gmis...@gmail.com wrote:
A few thoughts on Concepts:

As Concepts have evolved, I have found it difficult to get a handle on what Concepts actually are.
i.e.: Are Concepts functions, types, or something else?

Something else.
 

In his talk, Bjarne says:
* Concepts are NOT types of types. They are NOT type classes.


Well, they sort-of are. To a first approximation, they're predicates (type -> bool), which can be understood as partitions of the set of all types.
For any type T, either T is-a Range or T is-not-a Range. So the set of Ranges is a subset of the set of all possible types.
BUT! Look closer and there are at least three caveats.
(1) Concepts have deep structure known as "normal form"; see below.
(2) Concepts don't have to map (type -> bool); you can have multi-parameter concepts such as ConvertibleTo<T,U>, which are not as easily to gloss as predicates over single types. (But darned if the Concepts TS doesn't try! For any type T, either T is-a ConvertibleTo<U> or T is-not-a ConvertibleTo<U>.)
(3) Concepts don't have to accept types at all. For example, you can make a concept that maps (int -> bool).

    template<int V>
    concept EvenValue = ((V % 2) == 0);

I don't think this kind of concept is useful in real code (I'd prefer this kind of concept be kicked out of the Working Draft before C++2a is shipped). But you definitely can't by any mental gymnastics claim that concept `EvenValue` is a "type function" or a "type of types" or anything remotely like that.


At around 1:06:30 in his talk Bjarne says:
* "it's just like defining functions, you *ARE* DEFINING FUNCTIONS".


I believe that was an ad-lib not to be taken 100% literally. To a first approximation, a concept like Mergeable is a function mapping an ordered tuple of types to a bool. But that doesn't mean that all concepts ever must be thought of as functions.
That way lies functional programming and madness. ;)

[...]
The Concepts defined in Bjarne's talk look more like variable definitions *defined* in what feels (to me) like an odd mix of logic and type like syntax:

template<typename X> using Value_type = X::value_type;
template<typename X> using Iterator_of = X::iterator;

template<typename For, typename For2, typename Out>
concept Mergable =
    ForwardIterator<For>
    && ForwardIterator<For2>
    && OutputIterator<Out>
    && Assignable<Value_type<For>,Value_type<Out>>
    && Assignable<Value_type<For2>,Value_type<Out>>
    && Comparable<Value_type<For>,Value_type<For2>>;


The above looks like a variable definition. If it is not, then is it right that it looks like one?
It's a definition, with conditional logic et al. i.e it uses &&. etc. like an inline function.
So why are we defining it NOT using function like snytax?
Why is this a good thing?

Because of the first caveat I listed above: Concepts are not just predicates. They are logical predicates with deep structure, described by their normal form. For example, there is no special relationship between the variable templates

    template<class T> inline constexpr bool is_scalar_v = std::is_scalar<T>::value;
    template<class T> inline constexpr bool is_integral_v = is_scalar_v<T> && std::is_integral<T>::value;

but there is a very special relationship between the concept( template)s

    template<class T> concept is_scalar_c = std::is_scalar<T>::value;
    template<class T> concept is_integral_c = is_scalar_c<T> && std::is_integral<T>::value;

The special relationship is called subsumption, and we say that is_integral_c<X> subsumes is_scalar_c<X>.
If it weren't for subsumption, there would be no fundamental difference between a concept and a variable template of type `bool`.

The compiler determines the subsumption relationships between concepts by cracking open their definitions and peering inside. The definitions are cracked open only along the boundaries of the logical `&&` and `||` operators. So it is critically important that the definition of a concept be a single logical expression. If a concept were allowed to be expressed as a function body, the compiler wouldn't be able to crack it open, lift it into normal form, and figure out the subsumption relationships between this concept and all the other concepts in your program.

Figuring out these relationships is important to the compiler because these relationships affect overload resolution.

Please see my CppCon 2018 talk "Concepts as she is spoke" for a truly painful amount of information on how Concepts are different from plain old variable templates.

[...]
1. If concepts ARE functions, why aren't we defining and using them with function like syntax? And using () not <>.

I hope my answers above have pointed the way on this one.
 
2. It seems J. Monnon's proposal is making the same point as I am, only much better? Can we please address all that he proposes?

I think P0844 "Type functions and beyond" is thought-provoking. It's very large, though, which I believe is why it's targeted at SG7 Compile-Time Programming (formerly SG7 Reflection).
P0844 major section 3, "Concepts introducing types," seems to ignore the existence of non-type concepts in the Working Draft. Perhaps there should be a concerted effort to kick non-type concepts out of the Working Draft in order to gain some freedom of motion for these recurring theories of "concepts == types of types."
I do not believe that P0844 is making the same points (or, asking for clarification on the same points) as you are. I have only skimmed P0844, but it does not seem to be engaging with Concepts-as-they-are at all; it seems to be trying to reuse Concepty words to refer to elements of the author's more naïve "types of types" theory.
(More naïve is not necessarily bad!  I think C++2a Concepts is far too much of an experts-only feature, and we could use a lot more naiveté in this area.)

3. I feel a more formal response to J. Monnon's paper from the main proponents of Concepts as currently defined should be made before concepts get wired in any further in it's current direction?

I know many people would like Concepts be the marquee feature of C++20, but to me Concepts still seem quite away from where I'd like them to be.
Even Bjarne can only 'begrudgingly live' with the current syntax.
All this flux and begrudging really doesn't suggest to me that Concepts are ready to go for C++20.

FWIW, I agree with your conclusion.
The question is, do C++2a Concepts need wholesale kicking-out, as happened in C++11? or can they be rescued by judicious cuts?
The other question is, can anyone stop Concepts at this point or are the wise people getting out of the way of the train? (Cynic says: observe the recent formation of EWGI and LEWGI for those people tired of engaging with C++2a issues and eager to move on to C++2b.)

–Arthur

mihailn...@gmail.com

unread,
Oct 28, 2018, 6:44:32 AM10/28/18
to ISO C++ Standard - Future Proposals
Arthur, 
If you don't think value concepts should not be in, then you should write a paper - it is probably worth a careful investigation. 

Should be noted, Concepts are template argument filters and as such people will argue that for consistency alone it is worth having concepts over values
simply because template arguments can be values as well.

That said, concepts over values might have outlived their usefulness with the introduction of static assert, constexpr if and contracts.

An investigating where exactly they are still useful will be nice to have, if for no other reason then teachability. 

Gašper Ažman

unread,
Oct 28, 2018, 7:27:48 AM10/28/18
to std-pr...@isocpp.org
It might be useful to have a SmallerThan<int, int> concept to check whether a type-erased type whose size is only known numerically can fit into an SBO buffer.

It's a bit of a stretch, but might be a good case for keeping value concepts in, even if they only have rare usefulness.

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposal...@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/17eb2726-8feb-4cdf-a58e-43d6dc81549a%40isocpp.org.

mihailn...@gmail.com

unread,
Oct 28, 2018, 9:10:15 AM10/28/18
to ISO C++ Standard - Future Proposals


On Sunday, October 28, 2018 at 1:27:48 PM UTC+2, Gašper Ažman wrote:
It might be useful to have a SmallerThan<int, int> concept to check whether a type-erased type whose size is only known numerically can fit into an SBO buffer.

It's a bit of a stretch, but might be a good case for keeping value concepts in, even if they only have rare usefulness.

I just realized, with the downgrade of constexpr if to require a scope there is no other way to check a class template argument. 

template<GoodValue val> 
class C
{
  // ...
};


Also, things will become genuinely interesting with custom class non-type template arguments.  

gmis...@gmail.com

unread,
Oct 29, 2018, 2:08:19 AM10/29/18
to ISO C++ Standard - Future Proposals


On Sunday, October 28, 2018 at 9:27:58 AM UTC+13, Arthur O'Dwyer wrote:
On Wednesday, October 24, 2018 at 9:09:52 PM UTC-4, gmis...@gmail.com wrote:
A few thoughts on Concepts:

As Concepts have evolved, I have found it difficult to get a handle on what Concepts actually are.
i.e.: Are Concepts functions, types, or something else?

Something else.
 

In his talk, Bjarne says:
* Concepts are NOT types of types. They are NOT type classes.


Well, they sort-of are. To a first approximation, they're predicates (type -> bool), which can be understood as partitions of the set of all types.
For any type T, either T is-a Range or T is-not-a Range. So the set of Ranges is a subset of the set of all possible types.
BUT! Look closer and there are at least three caveats.
(1) Concepts have deep structure known as "normal form"; see below.
(2) Concepts don't have to map (type -> bool); you can have multi-parameter concepts such as ConvertibleTo<T,U>, which are not as easily to gloss as predicates over single types. (But darned if the Concepts TS doesn't try! For any type T, either T is-a ConvertibleTo<U> or T is-not-a ConvertibleTo<U>.)
(3) Concepts don't have to accept types at all. For example, you can make a concept that maps (int -> bool).

    template<int V>
    concept EvenValue = ((V % 2) == 0);

I don't think this kind of concept is useful in real code (I'd prefer this kind of concept be kicked out of the Working Draft before C++2a is shipped). But you definitely can't by any mental gymnastics claim that concept `EvenValue` is a "type function" or a "type of types" or anything remotely like that.


At around 1:06:30 in his talk Bjarne says:
* "it's just like defining functions, you *ARE* DEFINING FUNCTIONS".


I believe that was an ad-lib not to be taken 100% literally. To a first approximation, a concept like Mergeable is a function mapping an ordered tuple of types to a bool. But that doesn't mean that all concepts ever must be thought of as functions.
That way lies functional programming and madness. ;)

See I think it can be taken pretty much 100% literally.

From what I can tell, a Concept is 100% a constexpr function. A concept function verifies that a given list of types (passed to that function) passed to it conform to a specification - as defined by the logic of that function. The name of the function signifies what the concept is.
The function returns true if the types passed to the function meet the requirements of logic of the function and false if they do not.

There may be more to how the compiler deals with such a function, but it seems to me that this minimum I've described above is true.
Can we agree this far?

If a concrete type is passed to a function as a parameter whose type is constrained by a Concept, the Concept function is called with the concrete type and if it returns false, it yields a compilation error.
If a concrete type is returned from a function and assigned to a Concept variable the same check is performed. I'm sure this is reasonably off base but it seems like the gist of things. If this is correct or not though isn't the core of anything to me though. It's just how I'm visualizing it at the moment before I understand this more and subsumption and all of that.

Why does thinking of all concepts as functions madness? Because it seems to me that's exactly what all concepts as currently discussed are. They ALL seem to be constexpr functions that take a list of types and return bool to indicate the types satisfy the concept or they don't. What more is there and where is the madness?
Not yet no, sorry. But the discussion is helpful to me all the same so thank you.
I can see the topic of subsumption complicates the conversation though. However the subsumption etc. is seems to be an additive aspect to the basic fact that a concept IS a constexpr bool function, regardless of whatever extra rules come into effect after that or around that.

 
2. It seems J. Monnon's proposal is making the same point as I am, only much better? Can we please address all that he proposes?

I think P0844 "Type functions and beyond" is thought-provoking. It's very large, though, which I believe is why it's targeted at SG7 Compile-Time Programming (formerly SG7 Reflection).
P0844 major section 3, "Concepts introducing types," seems to ignore the existence of non-type concepts in the Working Draft. Perhaps there should be a concerted effort to kick non-type concepts out of the Working Draft in order to gain some freedom of motion for these recurring theories of "concepts == types of types."
I do not believe that P0844 is making the same points (or, asking for clarification on the same points) as you are. I have only skimmed P0844, but it does not seem to be engaging with Concepts-as-they-are at all; it seems to be trying to reuse Concepty words to refer to elements of the author's more naïve "types of types" theory.
(More naïve is not necessarily bad!  I think C++2a Concepts is far too much of an experts-only feature, and we could use a lot more naiveté in this area.)

3. I feel a more formal response to J. Monnon's paper from the main proponents of Concepts as currently defined should be made before concepts get wired in any further in it's current direction?

I know many people would like Concepts be the marquee feature of C++20, but to me Concepts still seem quite away from where I'd like them to be.
Even Bjarne can only 'begrudgingly live' with the current syntax.
All this flux and begrudging really doesn't suggest to me that Concepts are ready to go for C++20.

FWIW, I agree with your conclusion.
The question is, do C++2a Concepts need wholesale kicking-out, as happened in C++11? or can they be rescued by judicious cuts?
The other question is, can anyone stop Concepts at this point or are the wise people getting out of the way of the train? (Cynic says: observe the recent formation of EWGI and LEWGI for those people tired of engaging with C++2a issues and eager to move on to C++2b.)

–Arthur

I think P0844 "Type functions and beyond" seems to reach far and very consistently given that reach and it keeps the programming function based. My thoughts on Concepts is that it's syntax is unappealing with the angle bracket fest and the auto Concept x; versus Concept x storm.

I think Concept definitions need to retain a similar functional feel and that means exposing Concepts to look more like the functions and enabling them to be defined more like that. Or at least it's not clear to me why we can't and shouldn't go further down that road.

template <class T>
concept Semiregular = DefaultConstructible<T> &&
    CopyConstructible<T> && Destructible<T> && CopyAssignable<T> &&
requires(T a, size_t n) { 
    requires Same<T*, decltype(&a)>;  // nested: "Same<...> evaluates to true"
    { a.~T() } noexcept;  // compound: "a.~T()" is a valid expression that doesn't throw
    requires Same<T*, decltype(new T)>; // nested: "Same<...> evaluates to true"
    requires Same<T*, decltype(new T[n])>; // nested
    { delete new T };  // compound
    { delete new T[n] }; // compound
};
instead of something like this:
concept Semiregular(T)
{
    require DefaultConstructible(T) && CopyConstructible(T) && Destructible(T) && CopyAssignable(T);
    with (T a, size_t n) { 
       ...
    };
}

To me, Concepts as defined obfuscates a function as a variable definition. But if it is a function it remains unclear to me why it should not look a function and be able to be called like one and in that I think that would connect more with the style that P040844 reaches for.

As it stands I feel with Concepts, Reflection and Metaclasses all coming along, putting in Concepts so far ahead of these other features might mean that Concepts will not fit together well them. My comments are aimed at revealing that fact (or not) and if Concepts should wait to avoid that but also at understanding Concepts. 

Bjarne talks about remember the Vasa, but I'm worried that ironically Concepts might be that extra level of guns on deck that we are not ready for just yet.

Hopefully I am wrong about much of this. I don't want those working on Concepts don't feel I'm knocking their work. I am appreciative of their efforts. Hopefully this discussion helps even if it just helps me understand Concepts better and get on-board with them.

Thanks

mihailn...@gmail.com

unread,
Oct 29, 2018, 5:21:25 AM10/29/18
to ISO C++ Standard - Future Proposals
Things are simple - yes they are functions, they don't use curly braces because types are passed using the angle brackets

There is little need to change this and it consistent with old behavior. The only divination is removing tokens that are 100% redundant -  the bool return type and the empty parenthesizes that call the function.

As for "but this is not a function but a variable", well, so are lambdas.  
 


The problem with  "Type functions and beyond" is they introduces a new language. Talking about the Vasa this vastly more heavyweight then "few more guns" 

And even if we have this new language, the syntax will not be less verbose as far as concepts are concerned, because the verbosity comes from the expressions that must be valid - one way or another you must type that out. 

As said, what Type functions introduce is type transformation, this however will be handled by reflection and it will also be function based
The difference is - it will not introduce a new language - it will have converting expression that turn types into objects and use normal constexpr functions to transform these objects, then another expression to convert the object into a type. 
Again no new language! 

Will this affect Concepts as well - might be, but only the definition, not the usage as we want types passed to the concepts, without the need to convert that type to an object.   
In other words Concept<T> will remain correct and preferred even after functions based reflection and their possible use in Concepts

Tom Honermann

unread,
Oct 29, 2018, 10:08:57 AM10/29/18
to std-pr...@isocpp.org, gmis...@gmail.com

There is a fair amount of history here.  The model you are describing was the basis for the Concepts Lite design that eventually became the Concepts TS.  WG21 moved on from that model when integrating Concepts into C++20.  Though concept definitions are, effectively, constexpr predicates, specifying them as a new kind of entity avoids a fair amount of special casing while also leaving more room for future evolution.

You might appreciate the analysis at http://honermann.net/blog/2016/03/24/refining-concepts-the-quiddity-of-concept-definitions

Tom.

Arthur O'Dwyer

unread,
Nov 4, 2018, 3:12:06 PM11/4/18
to std-pr...@isocpp.org
On Mon, Oct 29, 2018 at 2:08 AM <gmis...@gmail.com> wrote:
On Sunday, October 28, 2018 at 9:27:58 AM UTC+13, Arthur O'Dwyer wrote:
On Wednesday, October 24, 2018 at 9:09:52 PM UTC-4, gmis...@gmail.com wrote:
A few thoughts on Concepts:

As Concepts have evolved, I have found it difficult to get a handle on what Concepts actually are.
i.e.: Are Concepts functions, types, or something else?

Something else.

[...] To a first approximation, they're predicates (type -> bool), which can be understood as partitions of the set of all types.
For any type T, either T is-a Range or T is-not-a Range. So the set of Ranges is a subset of the set of all possible types.
BUT! Look closer and there are at least three caveats.
(1) Concepts have deep structure known as "normal form"; see below.
(2) Concepts don't have to map (type -> bool); you can have multi-parameter concepts such as ConvertibleTo<T,U> [...]
(3) Concepts don't have to accept types at all. [...]

At around 1:06:30 in his talk Bjarne says:
* "it's just like defining functions, you *ARE* DEFINING FUNCTIONS".

I believe that was an ad-lib not to be taken 100% literally. To a first approximation, a concept like Mergeable [emphasis added —A] is a function mapping an ordered tuple of types to a bool. But that doesn't mean that all concepts ever must be thought of as functions.

See I think it can be taken pretty much 100% literally.

From what I can tell, a Concept is 100% a constexpr function. A concept function verifies that a given list of types (passed to that function) passed to it conform to a specification - as defined by the logic of that function. The name of the function signifies what the concept is.
The function returns true if the types passed to the function meet the requirements of logic of the function and false if they do not.

There may be more to how the compiler deals with such a function, but it seems to me that this minimum I've described above is true.
Can we agree this far?

A Concept is a "constexpr function" from some-inputs-that-may-or-may-not-be-types to `bool`, yes, but also more.  The "more" is the part you hadn't yet discovered, i.e., subsumption and normal form.

If a concrete type is passed to a function as a parameter whose type is constrained by a Concept, the Concept function is called with the concrete type and if it returns false, it yields a compilation error.
If a concrete type is returned from a function and assigned to a Concept variable the same check is performed. I'm sure this is reasonably off base but it seems like the gist of things. If this is correct or not though isn't the core of anything to me though. It's just how I'm visualizing it at the moment before I understand this more and subsumption and all of that.

Why does thinking of all concepts as functions madness? Because it seems to me that's exactly [emphasis added —A] what all concepts as currently discussed are.

All concepts are "functions" in that sense, but also more.  You are wrong when you say that a concept is exactly a function.

[...]
Please see my CppCon 2018 talk "Concepts as she is spoke" for a truly painful amount of information on how Concepts are different from plain old variable templates.
 
[...] I think Concept definitions need to retain a similar functional feel and that means exposing Concepts to look more like the functions and enabling them to be defined more like that. Or at least it's not clear to me why we can't and shouldn't go further down that road.

Because if you replace all your C++2a Concepts with plain old functions, you slice away the one way in which a C++2a Concept is more than a plain old function. Namely, subsumption.

By the way, the "plain old constraint on a function template" part of a Concept can be perfectly forwarded through a forwarding wrapper.
The "subsumption" part of a Concept cannot (as of the C++2a Working Draft) be forwarded through a forwarding wrapper (and I'm not aware of any proposal on the table to fix that).
Example:

I think C++2a's subsumption rules are fairly problematic. I think that the reason they're problematic is that they're new — they're literally the one new thing about C++2a concepts relative to C++17 traits, so of course they are the least baked. Everything else about C++2a Concepts is essentially unchanged since C++03: If you understand C++03 traits-based metaprogramming, then you understand everything about C++2a Concepts — except for subsumption.

–Arthur
Reply all
Reply to author
Forward
0 new messages