Boost logo

Boost :

From: Robert Ramey (ramey_at_[hidden])
Date: 2005-09-14 23:28:33


David Abrahams wrote:

> How to solve this problem is not a mystery. We just had a long thread
> about it entitled "[range] How to extend Boost.Range?" Have you
> completely missed it?

I haven't followed it.

>
> I am getting frustrated here because it seems to me that you haven't
> done your homework,

That's why I asked for more time to consider the issue - but you couldn't
accept that.

> yet, after asking me to propose solutions, you
> resist and call them ugly.

>> That was the only way I could get everything to compile on all
>> platforms.

> It seems to me from what you've been saying that your approach to
> solving the serialize( ... ) dispatching/customization problem here
> has been to try different configurations of the code until you could
> get it to pass select tests on certain platforms, without regard for
> standard conformance and theoretical portability.

That's only partly true. I start out with what I believe is standard
conforming code. The I compile it on all my platforms and discover
problems. Then try to make modifications so that it passes with all the
compilers and still is standard conforming. BOOST macros play an important
role here. Sometimes standard conforming code has to be suppresed and
replaced with other standard conforming code - e.g ar.template
register_type<my_class>() gets replaced with
ar.register_type(static_cast<my_class *>(NULL)). (God I hope that's
conforming.).

In this case I had to confront the question of which namespace
serializations of standard containers should be placed in and still have the
code compile and function with all compilers. The first solution used
either std or boost::serialization depending upon configuration macros. It
seemed very arbitrary to me. By arranging things so that the serialize(..)
template was allways called from within the boost::serialization namespace I
thought I had fixed the problem by permiting the overloads to be found via
ordinary lookup.

> That's a well-known
> way to end up with code that doesn't work portably or in
> configurations you haven't tried (for example, hmm, let me
> think... when the order of headers changes).

I'm aware of this.

>> Then generated the requirement to address the issue in the
>> documentation with a table on what the user should use. That's what
>> I call ugly.
>
> Huh? I didn't propose a table.

I was refering to my previous solution.

> And, IMO there's nothing particularly
> inelegant about using a table in documentation; there's
> well-established precedent for it in the standard and Boost.
> Certainly documenting what the user should do is a must. So I don't
> see what you're unhappy about.

> If you don't like having to tell users to do something special on
> nonconforming compilers, well, the answer is to either find a clean
> idiom that works everywhere (for this particular problem, many have
> tried -- I don't believe such an idiom exists)

The problem when one writes code which is to be portable accross compilers -
say serialization of the std::set .

Its not enough for it compile and run on my platform - it has to run on them
all. So one ends up with #if ... all over the place to vary the destination
namespace depending on whether or not the compiler supports ADL - that's
ugly.

> or stop supporting those broken compilers.

This the crux of the matter right here. From the prespective of two-phase
lookup - they're all "broken" except CW which can't use the most interesting
parts of the serilization library because its broken in other ways. I made
one choice - you would make another.

> Read the passage of the standard I quoted to you, and look carefully
> at the example above. Do your homework.

I'm trying.

> Lots of generic libraries have a similar dispatching issue to address,
> e.g. Boost.Range. There's a nice, free online compiler againist which
> you can test your 2-phase problems.

I downloaded and installed comeau 4.3 sometime ago specifically in order to
be able to test this. I still use it to compile all the library modules and
tests as a double check. They all pass. Alas, they don't link due to some
collision with the Boost Test library that cropped up after 1.32. Now I'm
informed that we have the test compile time switches set so supress
two-phase lookup (or parts of it) so I have no "conforming" compiler
available. This is a hinderence to addressing problems such as this.

>I've quoted the standard chapter
> and verse. I've given you simple example programs that demonstrate
> the problem. I don't know what more I can do... do I need to build a
> program that actually uses the serialization library before you'll
> believe me?!

That's what I'll have to do. FWIW its not that don't believe you're correct
about the way two-phase lookup works. But I"m curious to know why things
have worked so well so far. Is it because no one is using conforming
compilers? Is it because common use cases don't trip on this? This is so
far unexplained. The only way I'll discover this is by "doing my homework"
which I haven't been able to get to.

Maybe there is a real simple solution here. The relevent passage in the
documentation currently states:
Namespaces for Free Function Overrides
For maximum portability, include any free functions templates and
definitions in the namespace boost::serialization. If portability is not a
concern and the compiler being used supports ADL (Argument Dependent Lookup)
the free functions and templates can be in any of the following namespaces:
  a.. boost::serialization
  b.. namespace of the archive class
  c.. namespace of the type being serialized
So if I were to change it to the following would that be satisfactory?
Namespaces for Free Function Overrides
If your compiler supports two-phase lookup and ADL (Argument Dependent
Lookup) the free functions and templates can be in any of the following
namespaces:

    namespace of the archive class
    namespace of the type being serialized

If your compiler doesn't support two-phase lookup but it does support ADL
free functions and templates can be in any of the following namespaces
  a.. boost::serialization
  b.. namespace of the archive class
  c.. namespace of the type being serialized
If your compiler doesn't support ADL free functions and templates must be in
the boost::serialization namespace.

Of course that begs the main question I set out to answer. How to make ones
code work on all boost platforms - but we can just leave that to the
judgement of the library user.

Robert Ramey


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