Why does nobody seem to think that `null` is a serious problem in D?

Patrick Schluter Patrick.Schluter at bbox.fr
Wed Nov 21 09:31:41 UTC 2018


On Tuesday, 20 November 2018 at 23:14:27 UTC, Johan Engelen wrote:
> On Tuesday, 20 November 2018 at 19:11:46 UTC, Steven 
> Schveighoffer wrote:
>> On 11/20/18 1:04 PM, Johan Engelen wrote:
>>>
>>> D does not make dereferencing on class objects explicit, 
>>> which makes it harder to see where the dereference is 
>>> happening.
>>
>> Again, the terms are confusing. You just said the dereference 
>> happens at a.foo(), right? I would consider the dereference to 
>> happen when the object's data is used. i.e. when you read or 
>> write what the pointer points at.
>
> But `a.foo()` is already using the object's data: it is 
> accessing a function of the object and calling it. Whether it 
> is a virtual function, or a final function, that shouldn't 
> matter.

It matters a lot. A virtual function is a pointer that is in the 
instance, so there is a derefernce of the this pointer to get the 
address of the function.
For a final function, the address of the function is known at 
compile time and no dereferencing is necessary.

That is a thing that a lot of people do not get, a member 
function and a plain  function are basically the same thing. What 
distinguishes them, is their mangled name. You can call a non 
virtual member function from an assembly source if you know the 
symbol name.
UFCS uses this fact, that member function and plain function are 
indistinguishable in a object code point of view, to fake member 
functions.


> There are different ways of implementing class function calls, 
> but here often people seem to pin things down to one specific 
> way. I feel I stand alone in the D community in treating the 
> language in this abstract sense (like C and C++ do, other 
> languages I don't know). It's similar to that people think that 
> local variables and the function return address are put on a 
> stack; even though that is just an implementation detail that 
> is free to be changed (and does often change: local variables 
> are regularly _not_ stored on the stack [*]).
>
> Optimization isn't allowed to change behavior of a program, yet 
> already simple dead-code-elimination would when null 
> dereference is not treated as UB or when it is not guarded by a 
> null check. Here is an example of code that also does what you 
> call a "dereference" (read object data member):
> ```
> class A {
>     int i;
>     final void foo() {
>         int a = i; // no crash with -O
>     }
> }
>
> void main() {
>     A a;
>     a.foo();  // dereference happens
> }

No. There's no dereferencing. foo does nothing visible and can be 
replaced by a NOP. For the call, no dereferencing required.

> ```
>
> When you don't call `a.foo()` a dereference, you basically say

Again, no dereferencing for a (final) function call. `a.foo()` is 
the same thing as `foo(a)` by reverse UFCS. The generated code is 
identical. It is only the compiler that will use different 
mangled names.

> that `this` is allowed to be `null` inside a class member 
> function. (and then it'd have to be normal to do `if (this) 
> ...` inside class member functions...)
>
> These discussions are hard to do on a mailinglist, so I'll stop 
> here. Until next time at DConf, I suppose... ;-)
>
> -Johan
>
> [*] intentionally didn't say where those local variables _are_ 
> stored, so that people can solve that little puzzle for 
> themselves ;-)




More information about the Digitalmars-d-learn mailing list