[serialization] concept requirements

Hi Robert, Once again I find myself confounded by the true concept requirements for archives. Once upon a time, the truth-as-we-knew-it was that the following (copied from the library docs) was part of the input archive requirements. All input archives should be derived from the following template: template<class Archive> detail::common_iarchive; But, as I just discovered: polymorphic_iarchive doesn't meet those requirements. Since you have struggled with how to write the concept requirements for archives, I have a brilliant suggestion: create concept checking classes and archetypes using Boost.ConceptCheck, and use those to formulate and validate your concepts. Then you can simply copy the concept checking classes into your documentation and add a description of semantic constraints. You can't go wrong if you do that; the compiler will check your work for you, and make sure your code is consistent with your documentation. [I have recently upgraded the ConceptCheck library to allow some nicer but as-yet-undocumented syntax. When (if?) you decide to do this, I'll give you the quick skinny] -- Dave Abrahams Boost Consulting www.boost-consulting.com

David Abrahams wrote:
Hi Robert,
Once again I find myself confounded by the true concept requirements for archives. Once upon a time, the truth-as-we-knew-it was that the following (copied from the library docs) was part of the input archive requirements.
All input archives should be derived from the following template:
template<class Archive> detail::common_iarchive;
The above state isn't correct - as you've discovered. it seems to me that it should say something like" "archives included as part of the library have been derived from the following template: template<class Archive> detail::common_iarchive; In order to factor out common code to fewer modules."
But, as I just discovered: polymorphic_iarchive doesn't meet those requirements.
Note that polymorphic_?archive is an abstract base class. Hence, it cannot perform the operations required by the archive concept. So I would say only a derivation from polymorphic_?archive can fulfill the archive concept. All derivations from polymorphic_?archive included with the library do in fact also derive from common_?archive. Actually, the application of "Concepts" in the context of an abstract base class is a little ambiguous to me. I would have to think about it.
Since you have struggled with how to write the concept requirements for archives, I have a brilliant suggestion: create concept checking classes and archetypes using Boost.ConceptCheck, and use those to formulate and validate your concepts. Then you can simply copy the concept checking classes into your documentation and add a description of semantic constraints. You can't go wrong if you do that; the compiler will check your work for you, and make sure your code is consistent with your documentation.
This is an idea that has occurred to me before - actually during our memorable discussion regarding documentation of the serialization library. Actually until that time I had only the barest notion of the utility and usage of the the "Concepts" concept. When I looked at it more carefully, I saw the utility of building and maintain the concept classes during library development. This would help a lot in maintaining a consistent view, avoid dead ends, etc, etc. And of course it would help the documentation. I resolved to look into it when I had some time. That opportunity presented itself when I had occasion to use the multi-array library. I tried to use the concepts included to check my code deriving from this class which didn't work out for me. Then I dug deeper and found that although the concepts were included, the code was written in terms of specific classes rather than templates which used type arguments checked with the concepts. Oh and there were some compiler dependent quirks. All in all it seemed that the concept checking classes were added on at the end to satisfy some documentation requirement. They weren't really used as far as I could tell. So, all in all, I was very disappointed. My general impression was - great concept - but not quite ready for "the rest of us"(r). I do see much merit in the idea of developing the library, concepts and documentation skeleton in parallel. When I made the serialization documentation, I followed the boost pages regarding how to make boost documentation and they didn't (don't) mention anything about concepts and how to use them. What is really needed is a tutorial/example on making a very small boost library which would show how this is done. Starting with a small idea and showing how each change ripples through the library, concepts, skeletal documenation, compile - only tests - for testing the concepts, and runtime tests - for programming errors.
[I have recently upgraded the ConceptCheck library to allow some nicer but as-yet-undocumented syntax. When (if?) you decide to do this, I'll give you the quick skinny]
By the time I get to something like this, I would expect that the required information will have migrated into boost documentation. Robert Ramey

"Robert Ramey" <ramey@rrsd.com> writes:
David Abrahams wrote:
Hi Robert,
Once again I find myself confounded by the true concept requirements for archives. Once upon a time, the truth-as-we-knew-it was that the following (copied from the library docs) was part of the input archive requirements.
All input archives should be derived from the following template:
template<class Archive> detail::common_iarchive;
The above state isn't correct - as you've discovered. it seems to me that it should say something like"
"archives included as part of the library have been derived from the following template:
template<class Archive> detail::common_iarchive;
In order to factor out common code to fewer modules."
Okay. Or maybe that implementation detail of the library doesn't need to be documented at all.
But, as I just discovered: polymorphic_iarchive doesn't meet those requirements.
Note that polymorphic_?archive is an abstract base class. Hence, it cannot perform the operations required by the archive concept. So I would say only a derivation from polymorphic_?archive can fulfill the archive concept. All derivations from polymorphic_?archive included with the library do in fact also derive from common_?archive.
Actually, the application of "Concepts" in the context of an abstract base class is a little ambiguous to me. I would have to think about it.
You might express many of the requirements in terms of a class that must be derivable from the model of the concept.
Since you have struggled with how to write the concept requirements for archives, I have a brilliant suggestion: create concept checking classes and archetypes using Boost.ConceptCheck, and use those to formulate and validate your concepts. Then you can simply copy the concept checking classes into your documentation and add a description of semantic constraints. You can't go wrong if you do that; the compiler will check your work for you, and make sure your code is consistent with your documentation.
This is an idea that has occurred to me before - actually during our memorable discussion regarding documentation of the serialization library.
Actually until that time I had only the barest notion of the utility and usage of the the "Concepts" concept. When I looked at it more carefully, I saw the utility of building and maintain the concept classes during library development. This would help a lot in maintaining a consistent view, avoid dead ends, etc, etc. And of course it would help the documentation.
I resolved to look into it when I had some time.
That opportunity presented itself when I had occasion to use the multi-array library. I tried to use the concepts included to check my code deriving from this class which didn't work out for me.
Which class were you deriving from? IIUC the MultiArray library doesn't have any classes meant to be derived from in it, and until very very recently there was no way to use derivation with the concept checking library either, so what you're saying doesn't make much sense.
Then I dug deeper and found that although the concepts were included, the code was written in terms of specific classes rather than templates which used type arguments checked with the concepts.
That doesn't square with what I'm seeing in the multi_array code. For example, in multi_array.hpp: template <class ExtentList> explicit multi_array(ExtentList const& extents, const general_storage_order<NumDims>& so) : super_type((T*)initial_base_,extents,so) { boost::function_requires< detail::multi_array::CollectionConcept<ExtentList> >(); allocate_space(); }
Oh and there were some compiler dependent quirks. All in all it seemed that the concept checking classes were added on at the end to satisfy some documentation requirement. They weren't really used as far as I could tell.
How do you think they're supposed to be "used?"
So, all in all, I was very disappointed. My general impression was - great concept - but not quite ready for "the rest of us"(r).
That's wrong, actually. "The rest of us" simply haven't tried to learn to use them.
I do see much merit in the idea of developing the library, concepts and documentation skeleton in parallel. When I made the serialization documentation, I followed the boost pages regarding how to make boost documentation and they didn't (don't) mention anything about concepts and how to use them.
What is really needed is a tutorial/example on making a very small boost library which would show how this is done. Starting with a small idea and showing how each change ripples through the library, concepts, skeletal documenation, compile - only tests - for testing the concepts, and runtime tests - for programming errors.
Well, that's a great idea, actually. But seriously, you don't need that much hand-holding. Who is likely to go to the trouble to write that, when http://www.boost.org/libs/concept_check/using_concept_check.htm is already *extremely* generous and easy on the reader?
[I have recently upgraded the ConceptCheck library to allow some nicer but as-yet-undocumented syntax. When (if?) you decide to do this, I'll give you the quick skinny]
By the time I get to something like this, I would expect that the required information will have migrated into boost documentation.
I see. -- Dave Abrahams Boost Consulting www.boost-consulting.com

David Abrahams wrote: \
Okay. Or maybe that implementation detail of the library doesn't need to be documented at all.
It's in a section of the manual titled "Implementation" which is designed to help those who want to make their own archive implementations. Of course they should be able to start from scratch but this section is for those who want to leverage on what's already been don.
That opportunity presented itself when I had occasion to use the multi-array library. I tried to use the concepts included to check my code deriving from this class which didn't work out for me.
Which class were you deriving from?
multi_array and array_view
IIUC the MultiArray library doesn't have any classes meant to be derived from in it,
Hmmm, the class was there, there was no prohibition in either the code nor in the documentation indicated that it was not to be derived from. My interest was adding information regarding each row/column which would be carried along as the matrices were sliced and diced. I verified that my derived classes did in fact model the multi_array concept. I tried to verify this with the included concepts - but couldn't make it work. So gave up on the concepts and just used the code.
and until very very recently there was no way to use derivation with the concept checking library either, so what you're saying doesn't make much sense.
well maybe that was my problem.
Then I dug deeper and found that although the concepts were included, the code was written in terms of specific classes rather than templates which used type arguments checked with the concepts.
That doesn't square with what I'm seeing in the multi_array code. For example, in multi_array.hpp:
template <class ExtentList> explicit multi_array(ExtentList const& extents, const general_storage_order<NumDims>& so) : super_type((T*)initial_base_,extents,so) { boost::function_requires< detail::multi_array::CollectionConcept<ExtentList> >(); allocate_space(); }
How do you think they're supposed to be "used?"
well what I'm seeing is the operation a == b is a valid operaton where a and be are models of multi_array. A plain reading of the concept documentation suggests that this is a valid operaton for any pair of types modeling the multi_array concept. However when you actually try it - it only works when a and b are the same type. I went back to the documentation and could see that my plain reading was not the only way to interprete the documentation. And looking at the code you find that a==b is defined as member function for each class. Rather than as a stand alone operator which will work with any pair of types modeling multi_array concept. In my view the appeal of the the concept concept would be to permit that that a==b be implemented as a template with for any type A and B modeling multi_array concept. That would have been less code to write and would have resulted in something much closer to what a user of this library expects to see. That is what I mean when I say that the Concept isn't used. The a==b operation was what I needed when I wanted to compare a view slice from one multi_array with another full multi_array - a very reasonable expectation it seems to me. That's just one example the currently sticks in my mind - there are others.
Well, that's a great idea, actually. But seriously, you don't need that much hand-holding. Who is likely to go to the trouble to write that, when http://www.boost.org/libs/concept_check/using_concept_check.htm is already *extremely* generous and easy on the reader?
Actually a pretty good start. But as I've said, I think total potential of the concept concept can't be appreciated from the documentation. Robert Ramey

"Robert Ramey" <ramey@rrsd.com> writes:
David Abrahams wrote: \
Okay. Or maybe that implementation detail of the library doesn't need to be documented at all.
It's in a section of the manual titled "Implementation" which is designed to help those who want to make their own archive implementations. Of course they should be able to start from scratch but this section is for those who want to leverage on what's already been don.
That opportunity presented itself when I had occasion to use the multi-array library. I tried to use the concepts included to check my code deriving from this class which didn't work out for me.
Which class were you deriving from?
multi_array and array_view
IIUC the MultiArray library doesn't have any classes meant to be derived from in it,
Hmmm, the class was there, there was no prohibition in either the code nor in the documentation indicated that it was not to be derived from.
It's not prohibited, but that isn't the way the library is designed to be used. In any case, deriving from multiarray<...> or array_view<...> has little or nothing to do with concept checking.
My interest was adding information regarding each row/column which would be carried along as the matrices were sliced and diced. I verified that my derived classes did in fact model the multi_array concept. I tried to verify this with the included concepts - but couldn't make it work. So gave up on the concepts and just used the code.
function_requires<MutableMultiArrayConcept<my_array_class,N> >(); seems pretty straightforward to me.
and until very very recently there was no way to use derivation with the concept checking library either, so what you're saying doesn't make much sense.
well maybe that was my problem.
Maybe.
Then I dug deeper and found that although the concepts were included, the code was written in terms of specific classes rather than templates which used type arguments checked with the concepts.
That doesn't square with what I'm seeing in the multi_array code. For example, in multi_array.hpp:
template <class ExtentList> explicit multi_array(ExtentList const& extents, const general_storage_order<NumDims>& so) : super_type((T*)initial_base_,extents,so) { boost::function_requires< detail::multi_array::CollectionConcept<ExtentList> >(); allocate_space(); }
How do you think they're supposed to be "used?"
well what I'm seeing is the operation
a == b is a valid operaton where a and be are models of multi_array.
I don't believe that text appears anywhere. The actual text is missing a description for b in table 1 (http://www.boost.org/libs/multi_array/doc/reference.html#id832486). It should read a, b objects of type A
A plain reading of the concept documentation suggests that this is a valid operaton for any pair of types modeling the multi_array concept. However when you actually try it - it only works when a and b are the same type.
I went back to the documentation and could see that my plain reading was not the only way to interprete the documentation. And looking at the code you find that a==b is defined as member function for each class. Rather than as a stand alone operator which will work with any pair of types modeling multi_array concept.
I don't know why that should surprise you. It isn't possible to write a standalone operator that will work with any two types modeling the concept, and will always be found. Given two arbitrary types, in arbitrary namespaces, the operator== in a == b has to come from one of those namespaces, or it has to be a member of a.
In my view the appeal of the the concept concept would be to permit that that a==b be implemented as a template with for any type A and B modeling multi_array concept.
No, that's not what concepts are about. Concepts are about typechecking and verifying documentation. You can easily write a generic algorithm that would compare any two models of MultiArray, but Concepts can only help you understand how to do it correctly. They won't be useful in your code, except as a fancy kind of static assertion. They don't provide functionality.
That would have been less code to write and would have resulted in something much closer to what a user of this library expects to see. That is what I mean when I say that the Concept isn't used.
You're expecting the wrong things of concepts.
The a==b operation was what I needed when I wanted to compare a view slice from one multi_array with another full multi_array - a very reasonable expectation it seems to me. That's just one example the currently sticks in my mind - there are others.
If they're all of that ilk, you should allow them to unstick, because your expectations are misaligned with the intended purpose of the technology. You can't help but be disappointed.
Well, that's a great idea, actually. But seriously, you don't need that much hand-holding. Who is likely to go to the trouble to write that, when http://www.boost.org/libs/concept_check/using_concept_check.htm is already *extremely* generous and easy on the reader?
Actually a pretty good start. But as I've said, I think total potential of the concept concept can't be appreciated from the documentation.
That's probably true, but not at all for the reasons you think. If you want to understand the total potential of concepts you have to read something like http://www.generic-programming.org/software/ConceptGCC/... but that describes extensions to the C++ language. -- Dave Abrahams Boost Consulting www.boost-consulting.com
participants (2)
-
David Abrahams
-
Robert Ramey