$include_dir="/home/hyper-archives/boost/include"; include("$include_dir/msg-header.inc") ?>
Subject: Re: [boost] [Review] UUID library (mini-)review starts today, November 23rd
From: Vladimir.Batov_at_[hidden]
Date: 2008-12-02 18:15:56
> ...
> Hmm, I looked at some other value types in boost and this is what I
> found.
> 
> boost::gregorian::date() creates an 'not_a_date_time'.
>   One can exclude this constructor with a #define.
> boost::posix_time::ptime() is the same as above
> boost::function() is initialized as empty
> std::string() is initialized as empty
> boost::numeric::interval() the created interval is the singleton zero
> boost::quaternion() initialized each component/member to the default
>   values for their type (i.e. zero for floating numbers)
> boost::optional() is uninitialized
> boost::rational() is 'zero'
Some usages are legitimate (like an empty std::string is still a string 
and boost::rational() default initialization to 0). Some usages are IMHO 
mildly confusing (like boost::function()) as there is a clear 
understanding that it has to have some function, i.e. no-function is 
clearly invalid. Some others are IMHO unfortunate and quite confusing -- 
does
boost::gregorian::date() mean 'not_a_date_time'
or
boost::gregorian::date() means 'now'?
My view is that the interface needs to be intuitive. With the date I would 
not probably use the default constructor at all as it is not immediately 
clear what it does. Instead I'd have boost::date::invalid() and 
boost::date::now(). Deploying the default constructor for something apart 
from default construction is a hack unfortunately abused quite often. It 
does not make it right though.
> ...
> And, what should the default constructor do?  Create a null uuid or a 
> unique one?
It feels like you are struggling to associate the default constructor with 
something. :-) You know, you really do not have to. The default 
constructor has quite a clear meaning. If a class has no functionality 
matching that meaning, that class should not be defining the default 
constructor and should not be hijacking that constructor for anything 
else. Convenient? Sure. Good API? Hmm, I am not sure -- a good interface 
should be saying what it means. 
> ...
> This is what I want to prevent as well.  I'm concerned about the user
> who does:
>  boost::uuid u; // this create a unique uuid
> and does not realize that they just ran a computational intensive 
> function when they didn't need or want to.
I am not sure what there is not to realize? The language is clear that 
"boost::uuid u" calls the default constructor... whatever that constructor 
does (intensive or not). Treating object creation as it were built-in 
types (i.e. created uninitialized/invalid) is wrong, encourages the wrong 
programming practice and expectations and should not be encouraged.
> ...
> Fair.  These people are likely either doing:
> 
> boost::uuid u = get_uuid_from_somewhere(); // eg from database
> 
> or
> 
> boost::uuid u;
> get_uuid_from_somewhere(u); // eg from database
> 
> The second case would create a unique uuid unless they remembered to do:
> boost::uuid u(boost::uuid::null());
There is a big difference between #1 and #2 and the language is lucidly 
clear what the difference is -- #1 does just one step and creates and 
object from another object; #2 does 2 steps -- creates an object with the 
default constructor and then applies operator=(). Painting over that 
difference and encouraging user's ignorance of that important subtlety 
(for a novice) won't do anyone any good.
> It sounds very easy for one to forget.  This doesn't change symentics,
> it is just less efficient.
It *does* change semantics and it does change execution flow and the 
language cannot be any clearer on that. If you mean #1, then instead of 
making #2 to behave like #1, I'd prohibit #2 altogether by not providing 
the default constructor. Having said that to *me* "boost::uuid id;" makes 
sense as I read it as the language describes -- I create a UUUID with the 
default constructor. My interpretation of it is  that I trust the 
implementer to do the right thing for me -- the user. I'd say, if that 
interpretation is subtle and really controversial, just get rid of the 
default constructor altogether. 
In the end, it's just my view. I am not prepared to die fighting for it. 
:-)
Thanks,
Vladimir.