digitalmars.D.learn - finding composed structs
- Dan (24/24) Oct 30 2012 Please help me with any flaws in logic or understanding:
- Tobias Pankrath (4/28) Oct 30 2012 You are correct. But I argue and I think TDPL says the same, that
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (7/30) Oct 30 2012 There is the following discussion currently on the main D forum:
- Dan (23/31) Oct 30 2012 Interesting, thanks! In reading this and (per Tobias' comment)
- Tobias Pankrath (18/26) Oct 30 2012 In the meantime you can use this function template to compare
- Tobias Pankrath (3/20) Oct 30 2012 Beautiful version: http://dpaste.dzfl.pl/2340d73f
- Dan (8/9) Oct 30 2012 Beautiful indeed. Does the same approach work for generating
- Tobias Pankrath (6/16) Oct 30 2012 Dunno, if __traits(allMembers...) enforces any order on its
- Andrei Alexandrescu (3/24) Oct 30 2012 Y u no short circuit?
- Tobias Pankrath (1/4) Oct 30 2012 Left as an exercise to the reader.
- Timon Gehr (2/29) Oct 30 2012 You might want to shortcut after the first failed comparison.
Please help me with any flaws in logic or understanding: For any struct S, '==' means either bitwise comparison or a call to opEquals of S if it exists. If S has no (dynamic arrays, associative arrays, pointers, or class references as members (recursively)) then bitwise compare is equivalent to a deep compare. But if you do have any of those and you want true deep comparison semantics, you must implement a correct opEquals at the first introduction of those members, and carry that forward through all composed structures to S. struct A { int x = 3; } struct B { A a; } struct C { B b; } struct D { C c; } So in this case, D has deep equality semantics for ==. But change A to struct A { string x; } and the deep equality semantics for D disappears. To get it back an opEquals must be correctly implemented in A, B, C, and D. Is this accurate? If true and not an issue, people must not be relying too much on deep equality semantics like this. But how else can you find things? Thanks Dan
Oct 30 2012
On Tuesday, 30 October 2012 at 15:26:22 UTC, Dan wrote:Please help me with any flaws in logic or understanding: For any struct S, '==' means either bitwise comparison or a call to opEquals of S if it exists. If S has no (dynamic arrays, associative arrays, pointers, or class references as members (recursively)) then bitwise compare is equivalent to a deep compare. But if you do have any of those and you want true deep comparison semantics, you must implement a correct opEquals at the first introduction of those members, and carry that forward through all composed structures to S. struct A { int x = 3; } struct B { A a; } struct C { B b; } struct D { C c; } So in this case, D has deep equality semantics for ==. But change A to struct A { string x; } and the deep equality semantics for D disappears. To get it back an opEquals must be correctly implemented in A, B, C, and D. Is this accurate? If true and not an issue, people must not be relying too much on deep equality semantics like this. But how else can you find things? Thanks DanYou are correct. But I argue and I think TDPL says the same, that == should compare all members and is should bitwise compare. However that is currently not the case.
Oct 30 2012
On 10/30/2012 08:26 AM, Dan wrote:Please help me with any flaws in logic or understanding: For any struct S, '==' means either bitwise comparison or a call to opEquals of S if it exists. If S has no (dynamic arrays, associative arrays, pointers, or class references as members (recursively)) then bitwise compare is equivalent to a deep compare. But if you do have any of those and you want true deep comparison semantics, you must implement a correct opEquals at the first introduction of those members, and carry that forward through all composed structures to S. struct A { int x = 3; } struct B { A a; } struct C { B b; } struct D { C c; } So in this case, D has deep equality semantics for ==. But change A to struct A { string x; } and the deep equality semantics for D disappears. To get it back an opEquals must be correctly implemented in A, B, C, and D. Is this accurate? If true and not an issue, people must not be relying too much on deep equality semantics like this. But how else can you find things? Thanks DanThere is the following discussion currently on the main D forum: http://forum.dlang.org/thread/iphhuttpkogmfwpuvfla forum.dlang.org That behavior will be changed: http://forum.dlang.org/thread/iphhuttpkogmfwpuvfla forum.dlang.org?page=4#post-k6a30m:24140h:241:40digitalmars.com Ali
Oct 30 2012
On Tuesday, 30 October 2012 at 16:44:02 UTC, Ali Çehreli wrote:There is the following discussion currently on the main D forum: http://forum.dlang.org/thread/iphhuttpkogmfwpuvfla forum.dlang.org That behavior will be changed: http://forum.dlang.org/thread/iphhuttpkogmfwpuvfla forum.dlang.org?page=4#post-k6a30m:24140h:241:40digitalmars.comInteresting, thanks! In reading this and (per Tobias' comment) revisiting TDPL I think my original statement was incomplete and the situation is not as bad as I thought.For any struct S, '==' means either bitwise comparison or a call to opEquals of S if it exists.From TDPL: Objects of struct type can be compared for equality out of the box with == and ! =. Comparison is carried out member by member and yields false if at least two corresponding members in the compared objects are not equal, and true otherwise. So the issue in my example is not a problem with structs in general, but just a bug related to dynamic arrays only. My fear of having to provide opEquals at each level is unwarranted - the compiler will generate good ones for me (except for dynamic arrays until the bug is fixed). I've convinced myself of this in the following example. http://dpaste.dzfl.pl/14649c64 So until this bug is fixed any time I have any dynamic array, including string in struct S, implement opEquals. When the bug is fixed I can remove them. What I didn't realize is that including an opEquals in A will cause generation of opEquals in B,C,D for free (maybe only if called). If this is still off base please let me know. Thanks Dan
Oct 30 2012
On Tuesday, 30 October 2012 at 19:16:18 UTC, Dan wrote:So until this bug is fixed any time I have any dynamic array, including string in struct S, implement opEquals. When the bug is fixed I can remove them. What I didn't realize is that including an opEquals in A will cause generation of opEquals in B,C,D for free (maybe only if called). If this is still off base please let me know. Thanks DanIn the meantime you can use this function template to compare structs field by field. bool oneStepEqual(T,F)(ref T lhs, ref F rhs) if(is(Unqual!T == Unqual!F) && is(T == struct)) { bool result = true; foreach(mem; __traits(allMembers, T)) { static if(!is(typeof(__traits(getMember, T, mem)) == function)) { result = result && (__traits(getMember, lhs, mem) == __traits(getMember, rhs, mem)); } } return result; }
Oct 30 2012
On Tuesday, 30 October 2012 at 20:16:12 UTC, Tobias Pankrath wrote:In the meantime you can use this function template to compare structs field by field. bool oneStepEqual(T,F)(ref T lhs, ref F rhs) if(is(Unqual!T == Unqual!F) && is(T == struct)) { bool result = true; foreach(mem; __traits(allMembers, T)) { static if(!is(typeof(__traits(getMember, T, mem)) == function)) { result = result && (__traits(getMember, lhs, mem) == __traits(getMember, rhs, mem)); } } return result; }Beautiful version: http://dpaste.dzfl.pl/2340d73f
Oct 30 2012
On Tuesday, 30 October 2012 at 20:17:06 UTC, Tobias Pankrath wrote:Beautiful version: http://dpaste.dzfl.pl/2340d73fBeautiful indeed. Does the same approach work for generating correct versions of opCmp, assuming arbitrary order by field comparison as ordered in struct? Also hashing? Thanks Dan
Oct 30 2012
On Tuesday, 30 October 2012 at 21:02:22 UTC, Dan wrote:On Tuesday, 30 October 2012 at 20:17:06 UTC, Tobias Pankrath wrote:Dunno, if __traits(allMembers...) enforces any order on its result. It looks like DMD does use the definition/declaration order, but that's not in any documentation. The opCmp would depend on this. You could sort the fields by name for a defined order.Beautiful version: http://dpaste.dzfl.pl/2340d73fBeautiful indeed. Does the same approach work for generating correct versions of opCmp, assuming arbitrary order by field comparison as ordered in struct? Also hashing? Thanks Dan
Oct 30 2012
On 10/30/12 4:17 PM, Tobias Pankrath wrote:On Tuesday, 30 October 2012 at 20:16:12 UTC, Tobias Pankrath wrote:Y u no short circuit? AndreiIn the meantime you can use this function template to compare structs field by field. bool oneStepEqual(T,F)(ref T lhs, ref F rhs) if(is(Unqual!T == Unqual!F) && is(T == struct)) { bool result = true; foreach(mem; __traits(allMembers, T)) { static if(!is(typeof(__traits(getMember, T, mem)) == function)) { result = result && (__traits(getMember, lhs, mem) == __traits(getMember, rhs, mem)); } } return result; }Beautiful version: http://dpaste.dzfl.pl/2340d73f
Oct 30 2012
Left as an exercise to the reader.Beautiful version: http://dpaste.dzfl.pl/2340d73fY u no short circuit? Andrei
Oct 30 2012
On 10/30/2012 09:16 PM, Tobias Pankrath wrote:On Tuesday, 30 October 2012 at 19:16:18 UTC, Dan wrote:You might want to shortcut after the first failed comparison.So until this bug is fixed any time I have any dynamic array, including string in struct S, implement opEquals. When the bug is fixed I can remove them. What I didn't realize is that including an opEquals in A will cause generation of opEquals in B,C,D for free (maybe only if called). If this is still off base please let me know. Thanks DanIn the meantime you can use this function template to compare structs field by field. bool oneStepEqual(T,F)(ref T lhs, ref F rhs) if(is(Unqual!T == Unqual!F) && is(T == struct)) { bool result = true; foreach(mem; __traits(allMembers, T)) { static if(!is(typeof(__traits(getMember, T, mem)) == function)) { result = result && (__traits(getMember, lhs, mem) == __traits(getMember, rhs, mem)); } } return result; }
Oct 30 2012