Holes in structs and opEquals

Fawzi Mohamed fmohamed at mac.com
Sun Mar 7 06:30:14 PST 2010


On 2010-03-07 15:09:53 +0100, bearophile <bearophileHUGS at lycos.com> said:

> This comes from a small thread that is going on in digitalmars.D.learn.
> 
> This program asserts:
> 
> 
> import std.c.string;
> struct S { // 16 bytes, with a hole
>     ushort s;
>     double d;
> }
> void main() {
>     S s1, s2;
>     memset(&s1, ubyte.min, S.sizeof);
>     memset(&s2, ubyte.max, S.sizeof);
>     s1.s = s2.s = 0;
>     s1.d = s2.d = 0;
>     assert(s1 == s2);
> }
> 
> 
> But a correctly implemented opEquals (and opCmp) among structs has to 
> ignore the contents of the holes, because they can be filled with 
> anything, for example if the structs where not initialized (with =void).
> 
> A correct opEquals has to work recursively (so if the struct contains a 
> string, it has to control the string equality too).
> 
> And a built-in recursive opCmp/opHash for structs is about as useful as 
> having a correct opEquals.
> 
> A correct opEquals can be a little slower, but correctness come first. 
> In the uncommon situations where I really need max speed and I don't 
> care of correctness I can use a memcmp(&s1, &s2, S.sizeof). (And the 
> compiler is free to use just memcmp when a struct has no holes and 
> doesn't contain references, associative arrays and dynamic arrays).
> 
> Correctness of basic struct operators is not an optional feature, like 
> properties or even enums. If the opEquals among structs is wrong then 
> it's better to not have it at all.

one could argue that the unsafe operation is memset.
The compiler always initializes a struct, so that what you describe 
should never happen in a safe program.
Still as you say the following example that might indeed considered a bug:

S s1=void,s2=void;
s1.s=0; s1.d=0;
s2.s=0; s2.d=0;
assert(s1 == s2);

here the assert might fail depending on the previous content of the memory.
I am not sure of what is the best solution, I am not sure that defining 
a special comparison operation by default for each struct is the 
correct solution (it can be quite some bloat), please note that a user 
defined comparison function will not have these problems.
Still I agree that traking down a bug due to this might be very ugly...




More information about the Digitalmars-d mailing list