Profuse apologies for the long delay in writing this report.
Report on Boost Conversion Library Review, August 20-29, 2011.
I want to thank Vicente Botet Escriba for submitting the Conversion library for review and for his general good nature in receiving criticism and alternate designs.
The Conversion library presents a general framework for plugging in conversion operations between arbitrary types, providing a consistent interface for type-to-type conversions.
The library is unfortunately rejected. During the review, there were two votes for acceptance and two against, and some interesting conversation from about a dozen participants.
The major reason the library can't be accepted in its current form is that there was near consensus that there is no universal conversion domain, especially when the source or destination type might be a string.
Much of the review focused on possible One Definition Rule (ODR) violations, which are a consequence of having a universal customization point using template specializations or function overloads. Many solutions were offered, which will make up the second part of this report, "How to Avoid Universality."
I. Concerns about the library
Conversions Are Not Generic?
While some reviewers didn't see the need for a generic conversion library (and I was a little surprised at the vehemence of their opinions), I don't see this in itself as a reason to reject the library. The library's stated purpose is to provide a common interface for general type <-> type conversions, like lexical_cast does for string <-> type conversions. However, it was interesting that seemingly no one could come up with applications of truly generic conversion, although Jeffrey Lee Hellrung and Antony Polukhin alluded to their existence.
Also, some reviewers pointed out that you often need to choose what kind of conversion to do, and a generic library can get in the way here. Strings are the most obvious example: if you are converting from a string representing a binary value it would not work to use a decimal converter. Antony Polukhin pointed out a more subtle example: "lexical_cast<char>(1) and numeric_cast<char>(1) will produce different output."
Jeff Hellrung summed this point up nicely: "I think it's certainly possible for different clients using the same generic component to want different conversion implementations for a given pair of types, and that point, Boost.Conversion's universally-defined conversion implementations become useless. One wants the conversion operation to be parametrized as well as the types involved in the conversion."
Multi-Client Specialization Concerns
Leaving aside possible ODR violations, which we'll return to in Part II, some reviewers questioned the scalability of using template specialization and overloads when many clients (i.e. independent headers) may be customizing the behavior. Vladimir Batov claimed that a system which allows partial specializations on both Source and Target can't be made to work generally. Jeroen Habraken said SFINAE/enable_if "does make code fragile". I'm not clear if these conversations were resolved (or resolvable ;).
Some reviewers objected that conversions should just be defined within individual libraries, but of course this begs the question (as came up recently on the ML between DateTime and Chrono), "which library should house the conversions?"
Others (such as Phil Endecott) thought that simple c-style functions such as rgb_to_cmyk() were more explicit and direct.
Why is this so complex?
Kevlin Henney, initially excited about a general solution to the problem which lexical_cast first set out, commented on the documentation: "Based on casual reading, it feels a little more complex and requires a higher-entry level of knowledge than would be appropriate for many of the people who actually need this functionality."
II. How to Avoid Universality
One of the positive results of this review was a small catalog of alternatives to a universal customization point involving template specialization or overloaded functions.
a. Avoid the Problem
In the strictest sense, any library which allows either kind of universal customization can be prone to ODR violations. But many reviewers particularly thought that a customization point involving two UDTs was especially dangerous.
To his credit, Vicente was very up-front about the limitations of his design, and attempted to formulate rules for how the library could be used safely. In the documentation, he suggests (IIUC) that header-only libraries could use generic conversions as long as they don't define them, or define them as long as they don't use them.
John Bytheway suggested a tag-dispatch system where conversions are tagged with their source library, and any library which depends on conversions from two libraries would define a tag which inherits from the tags of both libraries. Thus ODR violations are avoided at the expense of having to specify an extra tag (effectively a sort of global conversion domain).
c. Conversion Domains and Overloaded Function Objects
Going on the consensus that there is no universal conversion domain, your humble review manager suggested a metaprogramming solution that defines conversion domain objects which combine a set of conversions within an object.
A more general solution would be to create an overloaded polymorphic function object, much like a polymorphic-source version of Lorenzo Caminiti's OverloadedFunction library (http://tinyurl.com/72nolyj). However, I have been warned (by Daveed Vandevoorde) that the rules for function overloading are too dangerously complicated to implement in a metaprogram.
Matthias Gaunard announced that he is working on a library particularly to
"solve the problem of specializing a function template for a category of types with best-match selection."