Jump to page: 1 2
Thread overview
finding composed structs
Oct 30, 2012
Dan
Oct 30, 2012
Tobias Pankrath
Oct 30, 2012
Ali Çehreli
Oct 30, 2012
Dan
Oct 30, 2012
Tobias Pankrath
Oct 30, 2012
Tobias Pankrath
Oct 30, 2012
Dan
Oct 30, 2012
Tobias Pankrath
Oct 30, 2012
Tobias Pankrath
Oct 30, 2012
Timon Gehr
October 30, 2012
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
October 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
> 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.
October 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
> Dan

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.com

Ali

October 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.com
>

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

October 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
October 30, 2012
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
October 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:
>
>>
>> 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
October 30, 2012
>> Beautiful version: http://dpaste.dzfl.pl/2340d73f
>
> Y u no short circuit?
>
> Andrei

Left as an exercise to the reader.
October 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:
>>
>> 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.
« First   ‹ Prev
1 2