Boost logo

Boost :

From: David Abrahams (dave_at_[hidden])
Date: 2005-09-20 13:34:15


"Robert Ramey" <ramey_at_[hidden]> writes:

> David Abrahams [mailto:dave_at_[hidden]] wrote:
>
> The following message is a courtesy copy of an article
> that has been posted to gmane.comp.lib.boost.devel as well.
>
>
> Hi Robert,
>
> Are you going to reply to
>
> http://article.gmane.org/gmane.comp.lib.boost.devel/131257
>
> ??
>
> Thanks,
>
> I considered your comments and re-wrote the section Archive Concept and it's
> checked into RC_1_33_0.

It's an improvement, but either you missed or intentionally discarded
some of my more important remarks. The most important question was:

 **** Isn't something in an Archive required to call "serialize?" ****

If not, how does an Archive work with Serializable types?

> There are two Archive concepts. Given a set of C++ data
> structures consisting of Serializable types, a Saving Archive
> will create a sequence of bytes. Given a sequence of bytes
> created by a Saving Archive, a Loading Archive will reconstitute
> the orginal configuration of C++ data structures. Both Archive
> concepts are derived from the more basic concept of Archive.

This is confusing and self-contradictory. Your text clearly states
that there are two Archive concepts and then goes on to describe three
Archive concepts: Archive, Saving Archive, and Loading Archive.

> Notation
>
> In the following descriptions, it is assumed that:
                               ^^^^^^^^^^^^^^^^^^^^
   Strike this. You are telling the reader what these identifiers
   mean, not interpreting something about which you need to make
   some assumption.

> • A is an Archive type
> • T is an Serializable Type
> • ar is an instance of type A.
> • x is an instance of type T.
> • u is an address.

An address is an abstract notion; it doesn't have any value in the
type system. You have to say "u is any pointer"... but see below.

> Common Type Definitions in all Archives

This should be a section for the "Archive" concept. These are not
type definitions but valid expressions.

> A::is_saving
>
> An integral constant of type boost::mpl::bool_.

I'm sorry to be so blunt, but that's nonsense. A::is_saving is a
type, not an integral constant, and boost::mpl::bool_ is a class
template, not a type. If you mean to refer to the MPL Integral
Constant concept, the correct thing to say would be:

         A boolean MPL Integral Constant

with a link to the documentation for that concept.

> Value is boost::mpl::bool_<true>

"Value?" This is also nonsense. The ::value member of an MPL Integral
Constant is an integral constant, not a type, but
boost::mpl::bool_<true> is a type. I normally

> if the Archive is a Saving Archive (see below) and
> boost::mpl::bool_<false> otherwise.

> A::is_loading
>
> An integral constant of type boost::mpl::bool_. Value is
> boost::mpl::bool_<true> if the Archive is a Loading Archive
> (see below) and boost::mpl::bool_<false> otherwise.

Ditto.

> Common Member Functions in all Archives

Again, these are not member functions, but valid expressions.
Presumably "ar & x" can be implemented by a free function and
"ar.template register_type<T>()" invokes a member function template.

> ar & x
>
> Returns a reference to ar. Appends the value of x along with
> other information to ar.

I think you should swap the two sentences; emphasis should be on
effects and only secondarily on return value.

But wait. Surely this expression, with the specified semantics,
doesn't have to be valid for loading archives? Are you saying that
all archives have to be able to save?

> ar.template register_type<T>();

You should leave out "template." This is a little tricky, but that
expression will never be valid in a context where A is not a dependent
type. I realize you do need it when A is a dependent type, but the
convention is to use the simpler notation. The author of an
archive isn't going to be calling register_type anyway (especially not
in a dependent context), so it won't help prevent him from making errors.

> ar.register_type(u);
>
> Append information about class T to the archive.
            ^--"s"

If so then you need to say that u is an expression of type T*

> This information is used to construct the correct class when a
> derived pointer is loaded. Invocation of this member function is
> referred to as "class registration". This is explained in detail
> in Special Considerations - Derived Pointers.

> ar.library_version()
>
> Returns an unsigned integer containing the version number of
> the serialization library that created the archive. This
> number will be incremented each time the library is altered
> in such a way that serialization could be altered for some
> type. For example, suppose the type used for a count of
> collection members is changed. The code that loads
> collections might be conditioned on the library version to
> make sure that libraries created by previous versions of the
> library can still be read.

Good!

> Saving Archive
>
> A Saving Archive is a refinement of the Archive Concept.
  ^--- strike "A." The Saving Archive concept refines Archive. "A
saving archive" referes either to a model of Saving Archive or an
instance of such a model.
  
> Notation
>
> In the following descriptions, it is assumed that:
>
> • ar is an instance of a Saving Archive.
> • x is an instance of a Serializable Type.
> • u is an address.

    A pointer again.

> • count is an integer that can be converted to std::size_t.
                  ^^^^^^^
no, it's an instance of any type that can be so converted. Your
"strong typedef" isn't an integral type.

>
> Common Member Functions

Valid expressions again.

> ar << x
>
> Returns a reference to ar. Appends the value of x along with
> other information to ar.

Doesn't this have to call serialize(...) somehow?

> ar.save_binary(u, count)
>
> Appends to the archive count bytes found at address.

Actually it must be

    Appends to ar the std::size_t(count) bytes found at address.

but doesn't it have to call serialize(...) somehow?

> Loading Archive
>
> Notation
>
> In the following descriptions, it is assumed that:
>
> • ar is an instance of a Loading Archive.
> • x is an instance of a Serializable Type.
> • u, v are pointers to any type.
> • count is an integer that can be converted to std::size_t.
>
> Common Member Functions in all Archives
>
> ar >> x
>
> Returns a reference to ar. Sets x with a value retrieved from
                                        ^^^^
                                        I would say "to"
> the ar.
      ^^^
      strike this.

Doesn't this have to call serialize(...) somehow?

> ar.load_binary(u, count)
>
> Retrieves from the archive count bytes and stores them in
                     ^^^^^^^^^^
                     "ar"
> memory starting at address.
                         ^^^^^^^
                         "u"

Doesn't this have to call serialize(...) somehow?

> ar.reset_object_address(v, u)
>
> Communicates to the archive that the object originally at
> address u has been moved to address v.
>
> In order to facilitate loading of objects through a pointer
> and to elminate redundant loading of objects, this system
> implements object address tracking. Normally this is done
> automatically with no action required on the part of the
> user.

For an implementor of an archive, this whole statement is confusing.
Do I need to implement object tracking, or is provided for me somehow
by "this system?" Is it done automatically? If so, by whom?

I think I know the answers to these questions, but I'm not sure a new
reader will.

> However, there are cases when an object must be de-serialized to
> a temporary location then moved to its final destination. This
> is common in loading collections.
>
> In such cases, reset_object_address should be invoked to
> communicate the final address of the last item loaded. This
> permits the internal tables to be correctly maintained in
> these special cases.

> ar.delete_created_pointers()
>
> Deletes all objects created by the loading of pointers. This
> can be used to avoid memory leaks that might otherwise occur if
> pointers are being loaded and the archive load encounters an
> exception.

The following sentence belongs under "Archive Models."

> There are archives based on text, binary and XML file formats but
> all have the above interface.

> Given that all archives present the
> same public interface, specifcation of serialization is exactly
> the same for all archives. Archive classes have other members not
> mentioned here. However they are related to the internal
> functioning of the library and are not meant to be called by
> users of an archive.

Are you telling me, after all this, that there are additional
requirements on archives not documented in the section on Archive
concepts? I find this rather alarming. Haven't I made it abundantly
clear that the concept documentation has to give at least a minimal
and complete documentation of what's required of an Archive?

> Implementation of new archives is discussed in New Archives -
> Implementation.

Which then goes on to describe some "input archive" idea that hasn't
been defined, etc...

<snip>

Okay, I don't know what to say at this point. I'm about to give up,
because I don't have the time to keep going over this. It sure seems
like you want to do this your own way, rather than by following the
established practices and norms. If you were just "creative" but
still rigorous, it would be one thing, but it doesn't even seem like
you're paying close attention to what you yourself are writing. What
should I do?

> ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
>
> © Copyright Robert Ramey 2002-2004. Distributed under the Boost
> Software License, Version 1.0. (See accompanying file
> LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

You might want to update the copyright date.

-- 
Dave Abrahams
Boost Consulting
www.boost-consulting.com

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk