Null references redux

Jeremie Pelletier jeremiep at gmail.com
Sun Sep 27 09:21:35 PDT 2009


downs wrote:
> Jeremie Pelletier wrote:
>> Christopher Wright wrote:
>>> Jeremie Pelletier wrote:
>>>> What if using 'Object obj;' raises a warning "unitialized variable"
>>>> and makes everyone wanting non-null references happy, and 'Object obj
>>>> = null;' raises no warning and makes everyone wanting to keep the
>>>> current system (all two of us!) happy.
>>>>
>>>> I believe it's a fair compromise.
>>> It's a large improvement, but only for local variables. If your
>>> segfault has to do with a local variable, unless your function is
>>> monstrously large, it should be easy to fix, without changing the type
>>> system.
>>>
>>> The larger use case is when you have an aggregate member that cannot
>>> be null. This can be solved via contracts, but they are tedious to
>>> write and ubiquitous.
>> But how would you enforce a nonnull type over an aggregate in the first
>> place? If you can, you could also apply the same initializer semantics I
>> suggested earlier.
>>
>> Look at this for example:
>>
>> struct A {
>>     Object cannotBeNull;
>> }
>>
>> void main() {
>>     A* a = new A;
>> }
>>
>> Memory gets initialized to zero, and you have a broken non-null type.
>> You could have the compiler throw an error here, but the compiler cannot
>> possibly know about all data creation methods such as malloc, calloc or
>> any other external allocator.
>>
>> You could even do something like:
>>
>> Object* foo = calloc(Object.sizeof);
>>
>> and the compiler would let you dereference foo resulting in yet another
>> broken nonnull variable.
>>
>> Non-nulls are a cute idea when you have a type system that is much
>> stricter than D's, but there are just way too many workarounds to make
>> it crash in D.
> 
> "Here are some cases you haven't mentioned yet. This proves that the compiler can't possibly be smart enough. "
> 
> Yeeeeeah.

I allocate most structs on the gc, unless I need them only for the scope 
of a function (that includes RVO). All objects are on the gc already, so 
it's a pretty major case. The argument was to protect aggregate fields, 
I'm just pointing out that their usage usually is preventing an easy 
implementation. I'm not saying its impossible.

Besides, what I said was, if its possible to enforce these fields to be 
null/non-null, you can enforce them to be properly initialized in such 
case, making nulls/non-nulls nearly useless.

> In the above case, why not implicitly put the cannotBeNull check into the struct invariant? That's where it belongs, imho.

Exactly, what's the need for null/non-null types then?

> Regarding your example, it's calloc(size_t.sizeof). And a) we probably can't catch that case except with in/out null checks on every method, but then again, how often have you done that? I don't think it's relevant enough to be relevant to this thread. :)

Actually, sizeof currently returns the size of the reference, so its 
always going to be the same as size_t.sizeof.



More information about the Digitalmars-d mailing list