Reproducing example:
struct S1 {
int a;
long b;
alias a this;
}
struct S2 {
S1 v;
alias v this;
}
unittest {
import std.stdio;
auto x = S2(S1(1, 12345678));
writeln(x.a, " ", x.b); // prints: 1 12345678
S1 y;
y = x;
writeln(y.a, " ", y.b); // prints: 1 0
y = x.v;
writeln(y.a, " ", y.b); // prints: 1 12345678
}
I think the LHS of assignment should probably not respect `alias this` at all, as assignment is expected to replace the whole value. If it does, it should go thru as few alias-this's as possible.
Comment #1 by andrei — 2019-01-29T18:03:22Z
Eyal, what do you think should be the right behavior? I think we should never allow partial assignment, i.e. do not use any alias this logic on the left hand side.
Comment #2 by bugzilla — 2019-01-29T18:07:39Z
I agree with Andrei. The slicing behavior is certainly surprising, it should be an error.
Comment #3 by eyal — 2019-01-29T19:45:02Z
Agreed. Assignment should assign the whole thing.
Comment #4 by andrei — 2019-01-29T20:04:48Z
Great you guys. I think it's best to qualify this as an wrong-code bug so we don't go through a deprecation cycle. OK?
Comment #5 by uplink.coder — 2019-01-30T00:09:15Z
(In reply to Andrei Alexandrescu from comment #4)
> Great you guys. I think it's best to qualify this as an wrong-code bug so we
> don't go through a deprecation cycle. OK?
What No?
That's changing semantics!
Comparison behaves the same.
I agree that this is annoying.
But for alias-this to work functions and fields which match the alias-this have priority.
Comment #6 by eyal — 2019-01-30T01:32:37Z
Stefan - under what circumstances does prioritizing "alias this" ever help?
Anyway, a compiler error - not changed semantics - as proposed here, should be fine (with the ordinary caveat of __traits(compiles ...)).
Also, currently it may inconsistently choose to assign the outer or inner field in different circumstances, which is clearly the worst of all worlds.
Assignment *always* assigning the whole lvalue is easier to explain and far less error-prone.
Comment #7 by uplink.coder — 2019-01-30T02:02:32Z
Eyal, I guess you could make it such that you error out if alias-this ever conflicts with anything.
Which would be a solution that properly fixes unwanted overload-stealing.
However that'll break a lot of code, then again perhaps that is a good thing.
I'd just ask for a spec change to clearify this.
To answer your question:
I don't remember the usecase anymore, which required alias-this to work the way it does, it might be a misconception on my part.
Comment #8 by razvan.nitu1305 — 2019-02-04T10:22:21Z
Talked to Razvan, and we're thinking of the following minimally disruptive change:
* If the struct has only ONE member of type T && the alias this yields a ref T
pass
* Else
issue a deprecation
This keeps legit cases working and disallows mistakes.
Comment #10 by dfj1esp02 — 2019-02-13T08:34:57Z
AFAIK transparent wrappers rely on LHS alias this for assignment.
I think what shouldn't happen is triggering alias this on both sides of assignment at the same time. Should be fine if only one side uses it.
Comment #11 by eyal — 2019-02-14T05:59:06Z
It's not fine if only LHS side uses it and causes a partial assignment. x = y should assign whole of x. If "alias this" exists in x but it still assigns the whole of x, that's fine.
Comment #12 by dlang-bot — 2019-02-19T15:23:06Z
@RazvanN7 updated dlang/dmd pull request #9323 "Fix Issue 19441 - alias this causes partial assignment" fixing this issue:
- Fix Issue 19441 - alias this causes partial assignment
https://github.com/dlang/dmd/pull/9323
Comment #13 by dlang-bot — 2019-02-26T18:37:59Z
dlang/dmd pull request #9323 "Fix Issue 19441 - alias this causes partial assignment" was merged into master:
- e786795f3f5b059a1e8bfcb09556640ff8c096e1 by RazvanN7:
Fix Issue 19441 - alias this causes partial assignment
https://github.com/dlang/dmd/pull/9323
Comment #14 by johanengelen — 2019-07-21T14:37:07Z
How are things now supposed to work with wrapper structs? (or is that functionality now no longer available?)
```
EntryType arr;
auto getPtr() { return &arr; }
struct EntryType {
//int somethingelse; // add for different error message
bool _state;
alias _state this;
}
struct S1 {
@property auto ref entry() { return *getPtr(); }
alias entry this;
}
void main(){
S1 s1;
s1 = true; // Deprecation: Cannot use `alias this` to partially initialize
// variable `s1` of type `S1`. Use `s1.entry()._state`
}
```
Note that S1 does not store any state. The goal is to use S1 as a transparant wrapper towards some other data structure.
Weka has the kind of code of the testcase, @Eyal how do you think one should implement this after this language change?
Comment #15 by johanengelen — 2019-07-21T14:52:25Z
Answering myself: use opAssign.
Comment #16 by johanengelen — 2019-07-21T15:04:00Z
The code of my testcase should now be (with explicit opAssign):
```
EntryType arr;
auto getPtr() { return &arr; }
struct EntryType {
int somethingelse;
bool _state;
void opAssign(typeof(_state) rhs) {
_state = rhs;
}
alias _state this;
}
struct S1 {
@property auto ref entry() { return *getPtr(); }
void opAssign(bool rhs) {
entry() = rhs;
}
alias entry this;
}
void main(){
S1 s1;
s1 = true;
}
```
Learnings:
- write to `alias this` only allowed when fully overwriting the struct _itself_
- write to only part of struct: use opAssign
- write to other data than struct itself: use opAssign
Comment #17 by dfj1esp02 — 2021-03-02T06:10:21Z
*** Issue 21674 has been marked as a duplicate of this issue. ***