## 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?
• Timon Gehr (2/29) Oct 30 2012 You might want to shortcut after the first failed comparison.
"Dan" <dbdavidson yahoo.com> writes:
```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
"Tobias Pankrath" <tobias pankrath.net> writes:
```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
Dan

You 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
=?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
```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
Dan

There is the following discussion currently on the main D forum:

That behavior will be changed:

Ali
```
Oct 30 2012
"Dan" <dbdavidson yahoo.com> writes:
```On Tuesday, 30 October 2012 at 16:44:02 UTC, Ali Ã‡ehreli wrote:
There is the following discussion currently on the main D forum:

That behavior will be changed:

Interesting, 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
"Tobias Pankrath" <tobias pankrath.net> writes:
```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
Dan

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;
}
```
Oct 30 2012
"Tobias Pankrath" <tobias pankrath.net> writes:
```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
"Dan" <dbdavidson yahoo.com> writes:
```On Tuesday, 30 October 2012 at 20:17:06 UTC, Tobias Pankrath
wrote:
Beautiful version: http://dpaste.dzfl.pl/2340d73f

Beautiful 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
"Tobias Pankrath" <tobias pankrath.net> writes:
```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:
Beautiful version: http://dpaste.dzfl.pl/2340d73f

Beautiful 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

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.
```
Oct 30 2012
Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
```On 10/30/12 4:17 PM, Tobias Pankrath wrote:
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

Y u no short circuit?

Andrei
```
Oct 30 2012
"Tobias Pankrath" <tobias pankrath.net> writes:
``` Beautiful version: http://dpaste.dzfl.pl/2340d73f

Y u no short circuit?

Andrei

Left as an exercise to the reader.
```
Oct 30 2012
Timon Gehr <timon.gehr gmx.ch> writes:
```On 10/30/2012 09:16 PM, Tobias Pankrath wrote:
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
Dan

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;
}

You might want to shortcut after the first failed comparison.
```
Oct 30 2012