Bug 19441 – alias this causes partial assignment

Status
RESOLVED
Resolution
FIXED
Severity
enhancement
Priority
P1
Component
dmd
Product
D
Version
D2
Platform
x86_64
OS
Linux
Creation time
2018-11-28T13:25:43Z
Last change time
2021-03-02T06:10:21Z
Keywords
pull
Assigned to
No Owner
Creator
Eyal

Comments

Comment #0 by eyal — 2018-11-28T13:25:43Z
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
Comment #9 by andrei — 2019-02-12T16:14:10Z
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. ***