class C
{
void mem()
{
foo(this); // fails
}
}
void foo(ref C);
void test()
{
C c;
foo(c); // passes
}
-----------
test.d(5): Error: function `test.foo(ref C)` is not callable using argument types `(C)`
test.d(5): cannot pass rvalue argument `this` of type `test.C` to parameter `ref C`
Comment #1 by kinke — 2023-07-04T09:44:00Z
This is the behavior I would expect - a class-ref `this` is special and not to be mutated. What if `foo()` sets it to null?
Comment #2 by bugzilla — 2023-07-05T06:44:19Z
Looking into the code, the reason the match fails is because `this` for a class is considered only an rvalue, not an lvalue.
Comment #4 by default_357-line — 2023-07-05T09:23:31Z
I mean, in the extreme, if this was allowed, shouldn't this happen?
class C
{
void mem()
{
foo(this);
}
}
void foo(ref C c) { c = null; }
C c = new C;
c.mem;
assert(c is null);
And what about if `c` is genuinely an rvalue, such as `C createC(); createC.mem;`?
Comment #5 by bugzilla — 2023-07-05T17:14:48Z
(In reply to FeepingCreature from comment #4)
> I mean, in the extreme, if this was allowed, shouldn't this happen?
It isn't any different from:
class C
{
static void mem(C c1)
{
foo(c1);
}
}
void foo(ref C c2) { c2 = null; }
C c3 = new C;
C.mem(c3); // c1 is a copy of c3
assert(c3 is null); // c1 is set to null, not c3
> And what about if `c` is genuinely an rvalue, such as `C createC();
> createC.mem;`?
Rvalues cannot be passed by ref.
13116 created a special case, and like special cases, it works inconsistently with the rest of the semantics.
Comment #6 by default_357-line — 2023-07-05T19:47:38Z
I guess I'm just allergic to ref-passing variables that you cannot see declared anywhere. In your example, C c1 is explicitly declared; in the original example, it's implicitly declared by the method call. IMO, implicitly declared variables should always be rvalues, but I guess that's a lost cause.
Comment #7 by bugzilla — 2023-07-05T20:28:25Z
Consider UFCS and the ability to do a.foo() and foo(a). When `this` behaves differently than a parameter, it generates a corner case with surprise behavior.
Early on I spent much care to make the address of a nested function (i.e. a delegate) indistinguishable from the address of a member function. This symmetry and consistency turned out to be a big win.
Avoiding special cases as much as possible should pay off for us.
Comment #8 by dlang-bot — 2023-07-06T03:29:16Z
@WalterBright created dlang/dmd pull request #15389 "fix Issue 24024 - cannot pass class this to ref class" fixing this issue:
- fix Issue 24024 - cannot pass class this to ref class
https://github.com/dlang/dmd/pull/15389
Comment #9 by dlang-bot — 2023-07-06T07:37:06Z
dlang/dmd pull request #15389 "fix Issue 24024 - cannot pass class this to ref class" was merged into master:
- 7d9679081f79e94793a13829e3adb54809e2da4e by Walter Bright:
fix Issue 24024 - cannot pass class this to ref class
https://github.com/dlang/dmd/pull/15389
Comment #10 by nick — 2023-08-02T18:31:05Z
Given that the fix for this caused issue #24034 (which violates @safe and is marked as a regression) and issue #24035 (which could be marked a regression too AIUI), perhaps it should be reverted.
Comment #11 by dlang-bot — 2023-11-01T19:13:39Z
dlang/dmd pull request #15637 "[stable] Revert "fix Issue 24024 - cannot pass class this to ref class"" was merged into stable:
- 1fed77b1e597280e91823a47310867e8df91f748 by Martin Kinkelin:
Revert "fix Issue 24024 - cannot pass class this to ref class (#15389)"
This reverts commit 2ee383b7908a0e2a72eb14ad3e9ca94c64d58a81.
Conflicts:
compiler/src/dmd/expression.d
https://github.com/dlang/dmd/pull/15637
Comment #12 by dlang-bot — 2023-11-01T22:39:25Z
dlang/dmd pull request #15771 "merge stable" was merged into master:
- 8a8d03d88a7a17082aca132f1be776f945cdda85 by Martin Kinkelin:
[stable] Revert "fix Issue 24024 - cannot pass class this to ref class" (#15637)
* Revert "fix Issue 24024 - cannot pass class this to ref class (#15389)"
This reverts commit 2ee383b7908a0e2a72eb14ad3e9ca94c64d58a81.
Conflicts:
compiler/src/dmd/expression.d
* Revert "Update C++ headers (#15396)"
This reverts commit 3a1e24922d462e5c477fd5753ff46819722310f0.
* Add test case for Issue 24157 - [REG2.105] class `this` as lvalue leads to memory corruption
https://github.com/dlang/dmd/pull/15771
Comment #13 by ibuclaw — 2023-11-08T06:01:27Z
Reverted.
Comment #14 by petar.p.kirov — 2024-01-12T21:52:59Z
Given the issues the (now reverted) dmd PR (https://github.com/dlang/dmd/pull/15389) caused, I'd err on the side of caution and mark this as won't fix.
Just for reference, C# (I tested .NET 8) also rejects treating `this` as an lvalue:
```csharp
C c = new C();
c.mem();
class C
{
public void mem()
{
foo(ref this);
this = new C();
}
static void foo(ref C c)
{
c = null;
}
}
```
Compilation error (line 8, col 11): Cannot use 'this' as a ref or out value because it is read-only
Compilation error (line 9, col 3): Cannot assign to 'this' because it is read-only