Discussion:
[std-proposals] Why don't concepts look like and get called like functions?
g***@gmail.com
2018-10-25 01:09:52 UTC
Permalink
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
--
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-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/ae920b87-e062-4b2c-b74c-ae3067d3c604%40isocpp.org.
m***@gmail.com
2018-10-25 07:04:06 UTC
Permalink
Post by g***@gmail.com
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.
* 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.
* "it's just like defining functions, you *ARE* DEFINING FUNCTIONS".
-----
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
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?
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).
Post by g***@gmail.com
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.
Post by g***@gmail.com
If Concepts ARE functions as Bjarne says, why shouldn't they look and be
composed using functional notation?
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."
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);
}
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
Post by g***@gmail.com
"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".
Post by g***@gmail.com
Thanks
--
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-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/bffc5427-9959-47b0-9e89-852d4430b6e3%40isocpp.org.
Klaim - Joël Lamotte
2018-10-26 10:19:07 UTC
Permalink
Post by m***@gmail.com
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.
Post by m***@gmail.com
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
--
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-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAOU91OO3t8yeS4ZE6H6QFP2z%2BoNwwTN1doXL8YUBjTJejj4Jqw%40mail.gmail.com.
Arthur O'Dwyer
2018-10-27 20:27:57 UTC
Permalink
Post by g***@gmail.com
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.
Post by g***@gmail.com
Bjarne's CppCon 2018 talk "Concepts: The Future of Generic Programming"
answers that question
clearly.
* 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.
Post by g***@gmail.com
* "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. ;)

[...]
Post by g***@gmail.com
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
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.

[...]
Post by g***@gmail.com
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.
Post by g***@gmail.com
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"
<http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0844r0.html> 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
Post by g***@gmail.com
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
--
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-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/9f8f8811-f1cb-4f4b-b4fb-15dfa8568881%40isocpp.org.
m***@gmail.com
2018-10-28 10:44:32 UTC
Permalink
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.
Post by Arthur O'Dwyer
Post by g***@gmail.com
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.
Post by g***@gmail.com
Bjarne's CppCon 2018 talk "Concepts: The Future of Generic Programming"
http://youtu.be/HddFGPTAmtU answers that question
clearly.
* 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.
Post by g***@gmail.com
* "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. ;)
[...]
Post by g***@gmail.com
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
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"
http://youtu.be/CXn02MPkn8Y for a truly painful amount
of information on how Concepts are different from plain old variable
templates.
[...]
Post by g***@gmail.com
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.
Post by g***@gmail.com
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"
<http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0844r0.html> 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
Post by g***@gmail.com
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
--
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-proposals+***@isocpp.org.
To post to this group, send email to std-***@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.
Gašper Ažman
2018-10-28 11:27:34 UTC
Permalink
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.
Post by m***@gmail.com
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.
Post by Arthur O'Dwyer
Post by g***@gmail.com
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.
Post by g***@gmail.com
Bjarne's CppCon 2018 talk "Concepts: The Future of Generic Programming"
http://youtu.be/HddFGPTAmtU answers that question
clearly.
* 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.
Post by g***@gmail.com
* "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. ;)
[...]
Post by g***@gmail.com
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
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"
http://youtu.be/CXn02MPkn8Y for a truly painful amount
of information on how Concepts are different from plain old variable
templates.
[...]
Post by g***@gmail.com
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.
Post by g***@gmail.com
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"
<http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0844r0.html>
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
Post by g***@gmail.com
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
--
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
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
<https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/17eb2726-8feb-4cdf-a58e-43d6dc81549a%40isocpp.org?utm_medium=email&utm_source=footer>
.
--
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-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAANG%3DkUSFekt__DVJ6VZYeZtrNpk%2BV11FxL%3DWZ4y0L0XS5qWxA%40mail.gmail.com.
m***@gmail.com
2018-10-28 13:10:15 UTC
Permalink
Post by Gašper Ažman
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.
Post by Gašper Ažman
Post by m***@gmail.com
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.
Post by Arthur O'Dwyer
Post by g***@gmail.com
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.
Post by g***@gmail.com
Bjarne's CppCon 2018 talk "Concepts: The Future of Generic Programming"
http://youtu.be/HddFGPTAmtU answers that question
clearly.
* 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.
Post by g***@gmail.com
* "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. ;)
[...]
Post by g***@gmail.com
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
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"
http://youtu.be/CXn02MPkn8Y for a truly painful
amount of information on how Concepts are different from plain old variable
templates.
[...]
Post by g***@gmail.com
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.
Post by g***@gmail.com
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"
<http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0844r0.html>
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
Post by g***@gmail.com
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
--
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
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
<https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/17eb2726-8feb-4cdf-a58e-43d6dc81549a%40isocpp.org?utm_medium=email&utm_source=footer>
.
--
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-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/09414975-5749-4158-b9eb-897426556314%40isocpp.org.
g***@gmail.com
2018-10-29 06:08:19 UTC
Permalink
Post by Arthur O'Dwyer
Post by g***@gmail.com
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.
Post by g***@gmail.com
Bjarne's CppCon 2018 talk "Concepts: The Future of Generic Programming"
http://youtu.be/HddFGPTAmtU answers that question
clearly.
* 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.
Post by g***@gmail.com
* "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?
Post by Arthur O'Dwyer
[...]
Post by g***@gmail.com
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
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"
http://youtu.be/CXn02MPkn8Y for a truly painful amount
of information on how Concepts are different from plain old variable
templates.
[...]
Post by g***@gmail.com
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.
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.
Post by Arthur O'Dwyer
Post by g***@gmail.com
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"
<http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0844r0.html> 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
Post by g***@gmail.com
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"
<http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0844r0.html> 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.

In other words, why this from
https://en.cppreference.com/w/cpp/language/constraints):
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
--
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-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/04c3ef3d-4950-47bf-9e32-6d48247a095e%40isocpp.org.
m***@gmail.com
2018-10-29 09:21:25 UTC
Permalink
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
Post by g***@gmail.com
Post by Arthur O'Dwyer
Post by g***@gmail.com
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.
Post by g***@gmail.com
Bjarne's CppCon 2018 talk "Concepts: The Future of Generic Programming"
http://youtu.be/HddFGPTAmtU answers that question
clearly.
* 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.
Post by g***@gmail.com
* "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?
Post by Arthur O'Dwyer
[...]
Post by g***@gmail.com
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
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"
http://youtu.be/CXn02MPkn8Y for a truly painful amount
of information on how Concepts are different from plain old variable
templates.
[...]
Post by g***@gmail.com
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.
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.
Post by Arthur O'Dwyer
Post by g***@gmail.com
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"
<http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0844r0.html>
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
Post by g***@gmail.com
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"
<http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0844r0.html> 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.
In other words, why this from
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
};
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
--
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-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/0b563669-ad01-4386-b08c-ae9c964b2247%40isocpp.org.
Tom Honermann
2018-10-29 14:08:54 UTC
Permalink
On Wednesday, October 24, 2018 at 9:09:52 PM UTC-4,
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.
Bjarne's CppCon 2018 talk "Concepts: The Future of Generic
Programming" http://youtu.be/HddFGPTAmtU
answers that question clearly.
* 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.
* "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?
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.
--
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-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/f8d88afe-9de4-93b9-c8c0-e953be5f650d%40honermann.net.
Arthur O'Dwyer
2018-11-04 20:11:51 UTC
Permalink
Post by g***@gmail.com
Post by Arthur O'Dwyer
Post by g***@gmail.com
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. [...]
Post by g***@gmail.com
* "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
Post by g***@gmail.com
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.

[...]
Post by g***@gmail.com
Post by Arthur O'Dwyer
Please see my CppCon 2018 talk "Concepts as she is spoke"
http://youtu.be/CXn02MPkn8Y 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:
https://concepts.godbolt.org/z/StUlc4

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
--
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-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CADvuK0L6Fq6NKY-_-OGvA-mg6DuHkoTgC6%2BivpwJimiOBxDbiQ%40mail.gmail.com.
Continue reading on narkive:
Loading...