www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Spec: can a class method change the type of the object (vtable) ?

reply Johan <j j.nl> writes:
Hi all,
   I am looking for a (legal D) counterexample where a class 
method alters the vtable of the object it is called on. In other 
words, a counterexample where the following transformation is 
invalid:

```
class A {
     void foo();
     ...
}

void g() {
     A a = new A();
     a.foo();
     a.foo();
}
---Transformed into --->
void g() {
     A a = new A();
     a.A.foo(); // devirtualized
     a.A.foo(); // devirtualized because `A.foo(a)` may not change 
the type of `a`.
}
```

Although accepted by the compiler currently, I believe this is 
forbidden by the spec (can't find it, if it is not in the spec it 
should be added):
```
     void foo() {
         this = new B(); // illegal D code
     }
```

Thanks,
   Johan
Mar 17
next sibling parent reply Nick Treleaven <nick geany.org> writes:
On Sunday, 17 March 2024 at 12:47:49 UTC, Johan wrote:
 Although accepted by the compiler currently, I believe this is 
 forbidden by the spec (can't find it, if it is not in the spec 
 it should be added):
 ```
     void foo() {
         this = new B(); // illegal D code
     }
 ```
With dmd v2.108.0-rc.1 I get: ``` thislval.d(7): Error: cannot modify expression `this` because it is not an lvalue ``` `this` was changed to be an lvalue for a few releases recently, see: https://issues.dlang.org/show_bug.cgi?id=24157
Mar 18
parent reply kinke <noone nowhere.com> writes:
On Monday, 18 March 2024 at 12:44:46 UTC, Nick Treleaven wrote:
 On Sunday, 17 March 2024 at 12:47:49 UTC, Johan wrote:
 Although accepted by the compiler currently, I believe this is 
 forbidden by the spec (can't find it, if it is not in the spec 
 it should be added):
 ```
     void foo() {
         this = new B(); // illegal D code
     }
 ```
With dmd v2.108.0-rc.1 I get: ``` thislval.d(7): Error: cannot modify expression `this` because it is not an lvalue ``` `this` was changed to be an lvalue for a few releases recently, see: https://issues.dlang.org/show_bug.cgi?id=24157
Yeah, IIRC, this was only allowed in v2.105.0 and v2.105.1, then reverted in v2.105.2. But it never changed the vptr, it just made `this` point to another object after the assignment (not affecting the callER though). I think the assumption/optimization should be safe. The only exception might be `extern(C++)` ctors in the future, if we really made those C++-compatible - they set the vptr (base ctors first to their vptr, then derived ctors overriding it later).
Mar 18
parent Johan <j j.nl> writes:
On Monday, 18 March 2024 at 13:50:59 UTC, kinke wrote:
 The only exception might be `extern(C++)` ctors in the future, 
 if we really made those C++-compatible - they set the vptr 
 (base ctors first to their vptr, then derived ctors overriding 
 it later).
Any extern(C++) method is not safe, because C++ allows placement new on `this` (a known issue for devirtualizing in C++). And indeed during construction things are particularly tricky in C++. -Johan
Mar 18
prev sibling parent Dukc <ajieskola gmail.com> writes:
On Sunday, 17 March 2024 at 12:47:49 UTC, Johan wrote:
 Although accepted by the compiler currently, I believe this is 
 forbidden by the spec (can't find it, if it is not in the spec 
 it should be added):
 ```
     void foo() {
         this = new B(); // illegal D code
     }
 ```
This wouldn't accomplish anything if it was allowed. Remember, `foo` is ```D void foo(A this) { this = new B; } ``` under the hood. You aren't modifying the existing instance of the class with this, you're only allocating a new instance and then not doing anything neither with the old nor the new instance. I believe you meant ```D void foo() { import core.lifetime; this.destroy(false); emplace(cast(B) cast(void*) this); } ```
Mar 18