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.

Reply via email to