www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - [Issue 11161] New: If `opEquals` is not defined, compiler should translate struct objects equality to member-wise equality even if there is `alias this`

reply d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=11161

           Summary: If `opEquals` is not defined, compiler should
                    translate struct objects equality to member-wise
                    equality even if there is `alias this`
           Product: D
           Version: D2
          Platform: All
        OS/Version: All
            Status: NEW
          Keywords: wrong-code
          Severity: normal
          Priority: P2
         Component: DMD
        AssignedTo: nobody puremagic.com
        ReportedBy: verylonglogin.reg gmail.com


--- Comment #0 from Denis Shelomovskij <verylonglogin.reg gmail.com> 2013-10-03
11:59:38 MSD ---
---
struct S {
    bool opEquals(ref const S) { return false; } 
}
struct T {
    S s;
    int value;
    alias value this;
}

void main() {
    T t1, t2;
    assert(t1.tupleof != t2.tupleof);
    assert(t1 != t2); // fails
}
---

If this behavior is expected, please write the reasons shortly and change it to
documentation issue unless this feature is documented.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Oct 03 2013
next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=11161


Jonathan M Davis <jmdavisProg gmx.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |jmdavisProg gmx.com


--- Comment #1 from Jonathan M Davis <jmdavisProg gmx.com> 2013-10-03 01:58:45
PDT ---
I would expect that alias this would have zero effect on == save for when
comparing with a value of the type that's being aliased instead of with a value
of the same type.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Oct 03 2013
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=11161


Kenji Hara <k.hara.pg gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Keywords|wrong-code                  |spec
          Component|DMD                         |websites
            Summary|If `opEquals` is not        |Document the default struct
                   |defined, compiler should    |equality comparison and
                   |translate struct objects    |operator overloading
                   |equality to member-wise     |
                   |equality even if there is   |
                   |`alias this`                |


--- Comment #2 from Kenji Hara <k.hara.pg gmail.com> 2013-10-03 02:45:37 PDT ---
(In reply to comment #0)
 ---
 struct S {
     bool opEquals(ref const S) { return false; } 
 }
 struct T {
     S s;
     int value;
     alias value this;
 }
 
 void main() {
     T t1, t2;
     assert(t1.tupleof != t2.tupleof);
     assert(t1 != t2); // fails
 }
 ---
 
 If this behavior is expected, please write the reasons shortly and change it to
 documentation issue unless this feature is documented.
For the expression `t1 != t2`, the semantic analysis is done in the following order: 1. Find opEquals method from the type of operands 2. If 'alias this' declaration exists, compiler tries to resolve equality operation via alias this. -> `t1.value != t2.value` is tested, and succeeds to compile. 3. If any opEquals and comparable 'alias this' is not found, the struct equality comparison is rewritten to their each field comparison. The point is, #1 and #2 are the part of "operator overloading" feature, and it is precedence than the default struct equality operation (== field-wise comparison). Historically Historically: - By bug 3789, the default comparison behavior was changed from bitwise to member-wise. - By bug 10037, the operator overload resolution precedence order was fixed (default member-wise comparison does not hide explicitly defined alias this). Therefore, current behavior is expected. -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Oct 03 2013
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=11161



--- Comment #3 from Kenji Hara <k.hara.pg gmail.com> 2013-10-03 02:53:07 PDT ---
(In reply to comment #1)
 I would expect that alias this would have zero effect on == save for when
 comparing with a value of the type that's being aliased instead of with a value
 of the same type.
'alias this' should be considered for operator overloading. If not, sub-typing by using 'alias this' won't work anymore. -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Oct 03 2013
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=11161



--- Comment #4 from Jonathan M Davis <jmdavisProg gmx.com> 2013-10-03 10:55:48
PDT ---
 'alias this' should be considered for operator overloading. If not, sub-typing
by using 'alias this' won't work anymore. I would expect sub-typing via alias this to only come into effect when the values being compared were of different types. So, struct S { bool opEquals(ref const S) { return false; } } struct T { S s; int value; alias value this; } void main() { S s1; S s2; int i; //Uses built-in opEquals, because the types match auto result1 = s1 == s2; //Uses alias this because it's not comparing with another S auto result2 = s1 == i; } I don't understand why alias this would even come into effect until you're dealing with a type other than S. As I understand it, alias this is for when the original type doesn't work, in which case the conversion is done if that will work instead. And that doesn't apply here. I'd also expect the compiler to always define a default opEquals for structs if you don't define one. And that's what it does when there's no alias this involved. -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Oct 03 2013
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=11161



--- Comment #5 from monarchdodra gmail.com 2013-10-06 01:18:48 PDT ---
(In reply to comment #2)
 For the expression `t1 != t2`, the semantic analysis is done in the following
 order:
 
 1. Find opEquals method from the type of operands
 2. If 'alias this' declaration exists, compiler tries to resolve equality
 operation via alias this. -> `t1.value != t2.value` is tested, and succeeds to
 compile.
I think this is completely bogus. Doing this means an alias this takes precedence over the type that holds it, and it should *never* happen. An alias this should never ever EVER take precedence over the base type. Here are some rebuttals to the above mentioned behavior. #1 alias this is designed to emulate "inheritance" for structs. EG: *extending* a struct. Today, it was mostly hijacked to instead do implicit conversion, where a struct can pass for some other type. The very "standard" scenario of: //---- struct Base { int i; } struct Derived { Base b; alias b this; int j; } void main() { Base b = {0}; Derived d1 = {b, 1}; Derived d2 = {b, 2}; assert(d1 != d2); //This fails } //---- The above assert is going to fail. This is completely unacceptable. Derived is a "subkind" of Base: It's Base plus some more. With the current behavior though, Derived is straight up treated as a Base, and everything that makes it a Derived is forgotten. #2. opAssign doesn't follow this rule. I'm not going to go into more details on this - I think it's obvious that opAssign and opEqual should follow the same set of rules. #3. If a struct has multiple "alias this", then comparison will probably fail spectacualrly. #4. Having a template called "hasElaborateEqual" would be virtually impossible to implement. Indeed, only the type that is resolved by alias this should be taken into account. Because of the above reason, I think that "alias this" most certainly should *not* be considered before checking if "T == T" is legal. Heck, I don't think it should be considered at *all* for "T == T": opAssign doesn't check. -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Oct 06 2013
prev sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=11161


Denis Shelomovskij <verylonglogin.reg gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Severity|normal                      |major


--- Comment #6 from Denis Shelomovskij <verylonglogin.reg gmail.com> 2013-11-05
11:31:21 MSK ---
(In reply to comment #2)
 1. Find opEquals method from the type of operands
 2. If 'alias this' declaration exists, compiler tries to resolve equality
 operation via alias this. -> `t1.value != t2.value` is tested, and succeeds to
 compile.
Just to be clear, currently we have this: --- struct S { int i, j; alias j this; } void main() { S s1 = {0}, s2 = {1}; assert(s1 == s2); // ok, resolved as `s1.j == s2.j` } --- And I'm quite sure it must be clearly documented. Also it should be mentioned one have to add: --- bool opEquals(in typeof(this) other) { return this.tupleof == other.tupleof; } --- if "old" comparison behavior is needed. -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Nov 05 2013