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 ;-)


Reply via email to