Introducing Nullable Reference Types in C#. Is there hope for D, too?
Timon Gehr
timon.gehr at gmx.ch
Sun Nov 19 02:25:53 UTC 2017
On 19.11.2017 01:07, Walter Bright wrote:
> On 11/18/2017 6:16 AM, Timon Gehr wrote:
>> On 18.11.2017 05:05, Walter Bright wrote:
>>> On 11/17/2017 6:05 AM, Timon Gehr wrote:
>>>> There are type systems that do that, which is what is being proposed
>>>> for C#. It's pretty straightforward: If I have a variable of class
>>>> reference type C, it actually contains a reference to a class
>>>> instance of type C.
>>>
>>> One of the difficulties with this is you'll still need an "empty"
>>> instance of C for the non-null reference to point to.
>>
>> Why would you need an empty instance?
>
> Consider the ClassDeclaration in the DMD source. Each ClassDeclaration
> has a pointer to its base class, `baseClass`. Except for `Object`, which
> doesn't have a base class. This is represented to assigning `null` to
> `baseClass`.
> ...
I.e., baseClass should have type Nullable!ClassDeclaration. This does
not in any form imply that ClassDeclaration itself needs to have a null
value.
> So I can run up the base class list by:
>
> for (b = c; b; b = b.baseClass) { ... }
> > If it cannot be null, I just have to invent something else that does the
> same thing:
>
> for (b = c; b != nullInstanceOfClass; b = b.baseClass) { ... }
>
> and nothing really has changed.
> ...
Nullable!ClassDeclaration can be null, so this is not relevant.
>> Just use a Nullable!C instead of a C if a special 'null' state is
>> actually required.
>
> What should the default initializer for a type do?
> ...
There should be none for non-nullable types.
>
>>> Any attempts to use a method on the empty instance should throw.
>>
>> The idea is that the type system makes potential such attempts
>> explicit while verifying that they don't occur in most of the cases.
>> Then you can grep for potential null dereferences.
>
> There are cases where the actual path taken guarantees initialization,
> but the graph of all paths does have uninitialized edges. Figuring out
> which are paths never taken is the halting problem.
The same applies to all other errors prevented by a type system. It's
just not a useful argument. The halting problem is undecidable mostly
because it is possible to write ridiculous programs. The ones we write
in practice are often easier to understand (especially when they come
with some useful documentation), because they were /designed/ to serve a
particular purpose. Note that the undecidability of the halting problem
is not something that applies exclusively to programs, it also applies
to programmers.
> I found this out
> when testing my DFA (data flow analysis) algorithms.
>
> void test(int i) {
> int* p = null;
> if (i) p = &i;
> ...
> if (i) *p = 3;
> ...
> }
>
> Note that the code is correct, but DFA says the *p could be a null
> dereference. (Replace (i) with any complex condition that there's no way
> the DFA can prove always produces the same result the second time.)
Yes, there is a way. Put in an assertion. Of course, at that point you
are giving up, but this is not the common case. Also, you can often just
write the code in a way that the DFA will understand. We are doing this
all the time in statically-typed programming languages.
More information about the Digitalmars-d
mailing list