 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Daniel Krügler Guest
|
Posted: Thu Sep 15, 2005 6:30 am Post subject: Some remarks to N1849 (2nd trial) |
|
|
{
Introductory comment: This is my 2nd trial to post this contribution.
The previous one was rejected, because the moderator argued, that it was
truncated, but the rejection mail did not show up any truncation and
such the posting is provided below (The only thing I changed where to
replace the single dot in the MyConcept definition by 3 dots).
**This note might be removed by the followup moderator**
}
Hello,
At first I want to emphasize, that I really liked the clearness and
thoroughness of the paper presented on:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1849.pdf
It doesn't evade any details of the proposals problems because it
explicitely mentions them. So although the following points seem
numerous on the first sight, they are mostly harmless (I hope):
1) Class analoga:
- Is it possible to define an object/instance of a concept or model? E.g.
template<typename T>
concept MyConcept {
..
};
MyConcept<int> c;
Assumption: No, it makes no sense, because concepts and models are pure
compile type entities which do have leave runtime traces.
2) I refer again to my most recent posting, where it was answered, that
reuse of typeid has been removed, and that the construction "!typename"
allows disabling of concept checking.
My personally feeling is, that I liked the previous syntax more than new
one. The reason are:
- The change of meaning of typename is more indirect and silent in
combination with concepts, because one has to recognize that there
exists a where clause (positionally quite late) to explain the suddenly
occuring names (injected typenames from concepts). Reusing "typeid"
seems better to me and visually at the right position. It also has the
convenient side effect, that the word "typeid" fits quite well (at least
to me )
- The meaning of "!typename" really seems counterintuitive! My first
impression was: "It is not a type - so what is it?"
Was there somewhat more behind the decision other than: "It seems better
now"? (OK, I see at least one reason, and that is the usage of
simplified template-parameter syntax combined with concept checking
disablement)
3) A second reference to my previous posting: Doug Gregor explained
quite well the difference between loose matching of actual signatures
and the need of exact matching of pseudo signatures. Now the heretical
question: If I write a more specialized concept (i.e. a model), what
says the compiler, if I do the following:
// Original concept, as before:
template<typename Iter>
concept RandomAccessIterator : BidirectionalIterator<Iter>
{
typename difference type; // associated type requirement
difference type operator-(Iter const&, Iter const&); // operation
requirement
};
// Specialized model template, but **differing** from its original:
template<typename T>
concept RandomAccessIterator<const T*>
{
typedef ptrdiff t difference type;
ptrdiff t operator-(const T* x, const T* y) { return x-y; } // Note: No
const& in sight!
};
Is the compiler required to point to the wrong signature of operator-()
in the model for pointers?
4) It is probably a simple question, but one which needs an answer:
which relative positions of a "where" clause and an "inline" keyword are
allowed? Consider
template <typename T>
where {..}
inline void foo(T) {
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
|
|
| Back to top |
|
 |
Douglas Gregor Guest
|
Posted: Fri Sep 16, 2005 3:29 am Post subject: Re: Some remarks to N1849 (2nd trial) |
|
|
Daniel Krügler wrote:
Thanks!
| Quote: | So although the following points seem
numerous on the first sight, they are mostly harmless (I hope):
1) Class analoga:
- Is it possible to define an object/instance of a concept or model? E.g.
template<typename T
concept MyConcept {
.
};
MyConcept
Assumption: No, it makes no sense, because concepts and models are pure
compile type entities which do have leave runtime traces.
|
Your assumption is absolutely correct.
| Quote: | 2) I refer again to my most recent posting, where it was answered, that
reuse of typeid has been removed, and that the construction "!typename"
allows disabling of concept checking.
My personally feeling is, that I liked the previous syntax more than new
one. The reason are:
|
Let's see if we can sway your opinion :)
| Quote: | - The change of meaning of typename is more indirect and silent in
combination with concepts, because one has to recognize that there
exists a where clause (positionally quite late) to explain the suddenly
occuring names (injected typenames from concepts). Reusing "typeid"
seems better to me and visually at the right position. It also has the
convenient side effect, that the word "typeid" fits quite well (at least
to me )
|
That was our original rationale. However, while implementing and
testing ConceptGCC we found that the typeid/typename distinction
was too confusing. First, it means that there are now three ways to
declare a template type parameter (typename, class, typeid), two of
which are equivalent but very different from the third. Second, by
using a different keyword here it forced us to explain the difference
between non-dependent (or opaque) template parameters and normal,
dependent template parameters early on in the presentation of generic
programming. But in reality, most users will use one or the other
exclusively: they'll be writing completely type-safe templates or
they'll
be writing C++03 templates, but mixing the two will more likely be
reserved for migrating existing code to type-safe templates.
Finally, and most importantly, "typeid" was just too easy to forget.
While coding ConceptGCC, we of course were writing test cases, mini
STLs, etc; on many occasions I added where clauses to an existing
template, ran it through the compiler, and chuckled with glee when it
worked... only to realize later that I'd forgotten to change the
"typename" parameters to "typeid". Actually, it was worse than that:
even when writing new function templates, I kept writing "typename"
and not "typeid". If the authors/implementors of the proposal can't
use it properly, there is a serious usability problem.
With this new rule, that the presence of any constraints implies that
all template parameters are non-dependent *unless* they are marked
with '!', the aforementioned problem does not occur. Better yet, it
requires more knowledge to write a less-safe template, and less
knowledge doesn't hurt you. Now, you don't really need to
understand what "dependent" means to write a type-safe template.
When we used "typeid" for non-dependent template parameters,
users had to understand "dependent" before writing their template.
| Quote: | - The meaning of "!typename" really seems counterintuitive! My first
impression was: "It is not a type - so what is it?"
|
Just to be picky, the '!' actually precedes the parameter name, e.g.,
template<typename !Dangerous> ...
We don't read the '!' as "not", but as "unsafe". There are other
languages
out there that use '!' to mean "unsafe", and we picked up the
convention.
Granted, we don't much care about the syntax here, so long as it takes
extra work to turn off type checking. Someone else suggested to us
privately that we just provide a bult-in concept "std::Unsafe" that
could
be used in a where clause like so:
template<typename Dangerous> where { std::Unsafe<Dangerous> }
| Quote: | 3) A second reference to my previous posting: Doug Gregor explained
quite well the difference between loose matching of actual signatures
and the need of exact matching of pseudo signatures. Now the heretical
question: If I write a more specialized concept (i.e. a model), what
says the compiler, if I do the following:
// Original concept, as before:
template<typename Iter
concept RandomAccessIterator : BidirectionalIterator
{
typename difference type; // associated type requirement
difference type operator-(Iter const&, Iter const&); // operation
requirement
};
// Specialized model template, but **differing** from its original:
template
concept RandomAccessIterator
{
typedef ptrdiff t difference type;
ptrdiff t operator-(const T* x, const T* y) { return x-y; } // Note: No
const& in sight!
};
Is the compiler required to point to the wrong signature of operator-()
in the model for pointers?
|
Well, to be picky, the model should have an empty where clause
to turn on type checking for the model template:
template
concept RandomAccessIterator<const T*>
{
// ...
};
With this change, the program is ill-formed and the compiler shall emit
a
diagnostic stating that the operator-() given does not satisfy any
requirement in the model. The "real" operator- signature will have been
implicitly generated.
If we hadn't added the "where{}", the same error would be detected when
the model is instantiated, e.g., RandomAccessIterator<const int*>;
| Quote: | 4) It is probably a simple question, but one which needs an answer:
which relative positions of a "where" clause and an "inline" keyword are
allowed? Consider
template <typename T
where {..}
inline void foo(T) {
|
The where-clause follows a template header or precedes a member
declaration. The relevant portions of the grammar (from page 21 of
N1849) are:
template-declaration:
export[opt] template < template-parameter-list > where-clause[opt]
declaration
member-declaration:
where-clause member-declaration
Doug
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
|
|
| Back to top |
|
 |
Daniel Krügler Guest
|
Posted: Sat Sep 17, 2005 2:01 am Post subject: Re: Some remarks to N1849 (2nd trial) |
|
|
Hello Douglas Gregor,
At first I want to add that my posting was strongly truncated
through the moderation process, so I tried a second posting in
the main queue and not as answer to your contribution.
Douglas Gregor wrote:
| Quote: | Daniel Krügler wrote:
Let's see if we can sway your opinion :)
|
[..]
| Quote: |
That was our original rationale. However, while implementing and
testing ConceptGCC we found that the typeid/typename distinction
was too confusing. First, it means that there are now three ways to
declare a template type parameter (typename, class, typeid), two of
which are equivalent but very different from the third. Second, by
using a different keyword here it forced us to explain the difference
between non-dependent (or opaque) template parameters and normal,
dependent template parameters early on in the presentation of generic
programming. But in reality, most users will use one or the other
exclusively: they'll be writing completely type-safe templates or
they'll
be writing C++03 templates, but mixing the two will more likely be
reserved for migrating existing code to type-safe templates.
Finally, and most importantly, "typeid" was just too easy to forget.
While coding ConceptGCC, we of course were writing test cases, mini
STLs, etc; on many occasions I added where clauses to an existing
template, ran it through the compiler, and chuckled with glee when it
worked... only to realize later that I'd forgotten to change the
"typename" parameters to "typeid". Actually, it was worse than that:
even when writing new function templates, I kept writing "typename"
and not "typeid". If the authors/implementors of the proposal can't
use it properly, there is a serious usability problem.
With this new rule, that the presence of any constraints implies that
all template parameters are non-dependent *unless* they are marked
with '!', the aforementioned problem does not occur. Better yet, it
requires more knowledge to write a less-safe template, and less
knowledge doesn't hurt you. Now, you don't really need to
understand what "dependent" means to write a type-safe template.
When we used "typeid" for non-dependent template parameters,
users had to understand "dependent" before writing their template.
- The meaning of "!typename" really seems counterintuitive! My first
impression was: "It is not a type - so what is it?"
Just to be picky, the '!' actually precedes the parameter name, e.g.,
|
Yes, you got me here ;-!!
| Quote: | template<typename !Dangerous> ...
We don't read the '!' as "not", but as "unsafe". There are other
languages
out there that use '!' to mean "unsafe", and we picked up the
convention.
Granted, we don't much care about the syntax here, so long as it takes
extra work to turn off type checking. Someone else suggested to us
privately that we just provide a bult-in concept "std::Unsafe" that
could
be used in a where clause like so:
template<typename Dangerous> where { std::Unsafe<Dangerous> }
|
Yes, that is also I nice idea. But after reading your reasoning of the
proposed nameing and a long time reading bothe papers N1848 and N1849
I think I got used to the propsed syntax.
| Quote: | 3) A second reference to my previous posting: Doug Gregor explained
quite well the difference between loose matching of actual signatures
and the need of exact matching of pseudo signatures. Now the heretical
question: If I write a more specialized concept (i.e. a model), what
says the compiler, if I do the following:
// Original concept, as before:
template<typename Iter
concept RandomAccessIterator : BidirectionalIterator
{
typename difference type; // associated type requirement
difference type operator-(Iter const&, Iter const&); // operation
requirement
};
// Specialized model template, but **differing** from its original:
template
concept RandomAccessIterator
{
typedef ptrdiff t difference type;
ptrdiff t operator-(const T* x, const T* y) { return x-y; } // Note: No
const& in sight!
};
Is the compiler required to point to the wrong signature of operator-()
in the model for pointers?
Well, to be picky, the model should have an empty where clause
to turn on type checking for the model template:
template
concept RandomAccessIterator<const T*
{
// ...
};
|
while you are right concerning the proper way to write this model
template it was importand for me to understand what happens, if
programmers do make errors in writing models corresponding to concepts.
| Quote: | With this change, the program is ill-formed and the compiler shall emit
a
diagnostic stating that the operator-() given does not satisfy any
requirement in the model. The "real" operator- signature will have been
implicitly generated.
If we hadn't added the "where{}", the same error would be detected when
the model is instantiated, e.g., RandomAccessIterator
|
OK, that are good news!
| Quote: | 4) It is probably a simple question, but one which needs an answer:
which relative positions of a "where" clause and an "inline" keyword are
allowed? Consider
template <typename T
where {..}
inline void foo(T) {
The where-clause follows a template header or precedes a member
declaration. The relevant portions of the grammar (from page 21 of
N1849) are:
template-declaration:
export[opt] template < template-parameter-list > where-clause[opt]
declaration
member-declaration:
where-clause member-declaration
|
Thank you for clarification. I have must have found this grammar later
than I wrote my question and forgot to remove it...
Greetings,
Daniel
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
|
|
| Back to top |
|
 |
Douglas Gregor Guest
|
Posted: Sun Sep 18, 2005 4:22 am Post subject: Re: Some remarks to N1849 (2nd trial) |
|
|
Daniel Krügler wrote:
| Quote: | // Original concept, as before:
template<typename Iter
concept RandomAccessIterator : BidirectionalIterator
{
typename difference type; // associated type requirement
difference type operator-(Iter const&, Iter const&); // operation
requirement
};
// Specialized model template, but **differing** from its original:
template
concept RandomAccessIterator
{
typedef ptrdiff t difference type;
ptrdiff t operator-(const T* x, const T* y) { return x-y; } // Note: No
const& in sight!
};
|
For reference, our development version of ConceptGCC gives the
following error message when provided with your example:
model_check2.C:17: error: model operation 'ptrdiff_t operator-(const
T*, const T*)' does not match any concept requirement
model_check2.C:9: note: near match: 'typename
RandomAccessIterator
const&, const T* const&)'
(The line numbers match up with the operator- in the model and concept,
respectively). Also, much to my surprise, the result is the same
regardless of whether we add an empty where-clause to the model
template, because model templates need to be completely consistent with
their concept even if they have dependent template parameters.
Doug
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
|
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|