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