Re: [boost] [uuid] Interface

Great in theory, but I think it'll break lexical_cast<uuid>("21f7f8de-8051-5b89-8680-0195ef798b6a"), since the lexical_cast wants to default-construct the target type into which it will read.
Yes, the default lexical_cast behavior requires the default constructor. Having said that I've been routinely specializing lexical_cast to optimize away the overhead. Something like namespace boost { template<> inline std::string lexical_cast<std::string> (std::string const& v) { return v; } template<> inline std::string lexical_cast<std::string> (char const* const& v) { return v; } template<> inline std::string lexical_cast<std::string> (bool const& v) { return v ? "yes" : "no"; } } If we do that for boost::uuid, then the user gets the familair interface and we have our class clean and minimal. Having said that I am honestly unsure about uuid id = lexical_cast<uuid>(str); as it seems already covered by template<typename InputIterator> uuid(InputIterator, InputIterator); I certainly want the explicitness of "string str = lexical_cast<string>(id);" though. Still, keeping the bidirectional nature of lexical_cast is probably important for the user. Therefore, I'd *probably* have namespace boost { template<> inline boost::uuid lexical_cast<std::string> (std::string const& v) { return boost::uuid(v.begin(), str.end()); } }
template <typename ByteInputIterator> uuid(ByteInputIterator begin, ByteInputIterator end);
Can we take it one step further and replace it with a more generic: template<class ForwardReadableRange> uuid(ForwardReadableRange const& range) { typedef typename boost::range_iterator< ForwardReadableRange
::type Iterator;
Iterator begin = boost::begin(range); Iterator end = boost::begin(end); ... the rest is the same. } That way uuid id(string) is supported without the need for an explicit "uuid::uuid(string const&)" constructor as other containers as well.
// valid expression // generator() - result type must be convertible to a uuid template <typename Generator> explicit uuid(Generator & generator);
I feel that the "generator() - result type must be convertible to a uuid" requirement is somewhat excessive. Given the rest of the code it results in a generator having to know and even be able to create boost::uuid. That seems like an unnecessary coupling. I think generators should know *nothing* about uuid and certainly *not* create those. Instead, the generators should provide the necessary *ingredients* but it'd be uuid (well, its uuid(generator) constructor) actually creating an uuid instance. That might be as straghtforward as template<class Generator> uuid(Generator const& gen) { std::pair<Iterator, Iterator> range = gen(); ... something that uuid(begin, end) or uuid(range) does. } That way, the requirements for a generator are looser as all it needs is to provide a range. More so, the design maintains the locality of uuid creation and destruction -- those are created and destructed in the conventional way, i.e. by the uuid constructor and destructor (rather than created by a generator but destroyed by the uuid::~uuid()). As Scott noted template<class Generator> uuid(Generator const& gen) constructor is somewhat redundant. However, I'd personally like to keep it as it communicates to the user one of the main ways of creating a uuid.
bool is_nil() const; operator unspecified_bool_type() const; // return !is_nil();
It's a minor point but I'd ask whay we need both? The reason I greatly favor "bool" converter is that it is idiomatic and does *not* introduce a new vocabulary. That is important from the usability point of view as any new vocabulary is obviously only usable *after* one learnt it. Why ask the user to learn something (like "is_nil") if he can get by without? Thanks, Vladimir.

On Thu, Dec 18, 2008 at 16:15, <Vladimir.Batov@wrsa.com.au> wrote:
Yes, the default lexical_cast behavior requires the default constructor. Having said that I've been routinely specializing lexical_cast to optimize away the overhead.
If we do that for boost::uuid, then the user gets the familair interface and we have our class clean and minimal.
This seems like possibly the best idea, though it does mean extra care will be needed to match the normal lexical_cast semantics. I'm still not convinced that that providing the default constructor is such a bad thing, so I would still like Andy's #define to allow it. (Or IMHO better, a define to make it private.)
Having said that I am honestly unsure about
uuid id = lexical_cast<uuid>(str);
as it seems already covered by
template<typename InputIterator> uuid(InputIterator, InputIterator);
No. The input iterator constructs from the raw octets, expecting them as in 4.1.2. Layout and Byte Order in http://www.faqs.org/rfcs/rfc4122.html . The elements in the passed range will be equal to those in the id.begin(), id.end() range.
Can we take it one step further and replace it with a more generic:
template<class ForwardReadableRange> [...]
I'm not convinced it's helpful for the constructor, but it would be a very good plan for the name-based generators. Making those accept string literals and std::vectors and std::strings directly would be a very worth-while interface improvement. ~ Scott
participants (2)
-
Scott McMurray
-
Vladimir.Batov@wrsa.com.au