What is the case against a struct post-blit default constructor?

Andrei Alexandrescu SeeWebsiteForEmail at erdani.org
Thu Oct 11 05:19:23 PDT 2012


On 10/10/12 6:45 AM, Don Clugston wrote:
> On 10/10/12 11:21, Jonathan M Davis wrote:
>> On Monday, October 08, 2012 18:47:43 Malte Skarupke wrote:
>>> So I really can't think of a reason for why you wouldn't want
>>> this. Yet this discussion has happened several times already.
>>> There is clear demand for it and very good reasons, such as those
>>> mentioned in all the linked discussions.
>>>
>>> So why is this being rejected?
>>
>> It buys you pretty much nothing. There are plenty of places in the
>> language
>> where init is required (e.g. member variables that can't be directly
>> initialized and the elements in an array). So, init _will_ be used 				
>> regardless
>> of what you do with the default constructor. If you want to prevent
>> that, then
>> you need to disable init, which we can already do. But you're not
>> going to get
>> those things initialized with the default constructor, which kind of
>> defeats
>> the purpose of the default constructor. If you can't guarantee that every
>> instance which isn't explicitly constructed is default constructed, then
>> what's the point?
>
> Of course there would be no point.
> You have not answered the question. The issue is, WHY can we not
> guarantee that that the struct default constructor is called?

We could (after all, C++ does it). There are a few disadvantages to 
doing so, however.

1. Defining static data is more difficult. Currently, all static data is 
statically-initialized. With default constructors, we'd need to define 
the pre-construction state of such objects anyway, and then change the 
compiler to call constructors prior to main(). I find the current design 
simpler and easier to use.

2. Creating a temporary object cannot be anymore assumed to be a O(1), 
no-resources-allocated deal. Instead, generic code must conservatively 
assume that objects are always arbitrarily expensive to create. That 
makes some generic functions more difficult to implement.

3. Two-phase object destruction (releasing state and then deallocating 
memory), which is useful, is made more difficult by default 
constructors. Essentially the .init "pre-default-constructor" state 
intervenes in all such cases and makes it more difficult for language 
users to define and understand object states.

4. Same as above applies to an object post a move operation. What state 
is the object left after move? C++'s approach to this, forced by the 
existence of default constructors and other historical artifacts, has a 
conservative approach that I consider inferior to D's: the state of 
moved-from object is decided by the library, there's often unnecessary 
copying, and is essentially unspecified except that "it's valid" so the 
moved-from object can continue to be used. This is in effect a back-door 
introduction of a "no-resources-allocated" state for objects, which is 
what default constructors so hard tried to avoid in the first place.

5. There are a few minor issues such as correct array creation etc. but 
I don't consider them decisive.

There are obvious disadvantages of the lack of a default constructor. I 
believe they are overcome by the advantages, although clearly reasonable 
people may disagree.

> I have a vague memory that Walter mentioned a technical difficulty once
> but I don't remember anything about what it was.
>
> I can't imagine what it would be. Even in the worst case, it would be
> possible to run CTFE on the default constructor in order to create
> ..init. This would limit the default constructor to things which are
> CTFEable, but even that would still be useful for templated structs.

Allowing a default constructor that's computable during compilation 
would be a very interesting idea.

> Really, there does not seem to me to be any point in having an invariant
> for a struct, without a default constructor.

Could you please give a few examples? (Honest question.) Most structures 
I define have an obvious quiescent state that vacuously satisfies the 
invariant. Exceptions that come to mind are: (a) value types that must 
always allocate something on the heap, see e.g. the contortions in 
std.container; (b) values as permits (the existence of the value 
guarantees a resource has been secured, as in scoped locks on mutexes).


Andrei


More information about the Digitalmars-d mailing list