Jump to page: 1 2
Thread overview
How do I obtain the default hash of a user-defined struct
Apr 02, 2014
dnspies
Apr 02, 2014
FreeSlave
Apr 02, 2014
dnspies
Apr 02, 2014
FreeSlave
Apr 03, 2014
dnspies
Apr 03, 2014
dnspies
Apr 03, 2014
bearophile
Apr 03, 2014
dnspies
Apr 03, 2014
bearophile
Apr 03, 2014
bearophile
Apr 04, 2014
dnspies
Apr 04, 2014
H. S. Teoh
Apr 04, 2014
bearophile
April 02, 2014
How can I get the default-hash of a struct I've defined (to be used as part of the hash for some containing type)?
April 02, 2014
On Wednesday, 2 April 2014 at 20:14:31 UTC, dnspies wrote:
> How can I get the default-hash of a struct I've defined (to be used as part of the hash for some containing type)?

UserDefined userDefined;
writeln(typeid(UserDefined).getHash(&userDefined));

Probably there is a better way. I don't like to call typeid for this purpose.
April 02, 2014
Thanks,
Actually I'm realizing there's a lot I'm unclear about when it comes to default comparison, equality, hashing, etc.

If my struct contains a dynamic array, are the contents of the array compared by default, or just the pointers/lengths?

Also, when two arrays are compared for content, are their pointers compared first in case they happen to be the same so the deep comparison can be shortcut?
Also, how do I obtain the default hash of a dynamic array ('s contents)?  Is there one?  I assume there must be since associative arrays can take string as a key-type.

To make a struct a valid key type, do I need to implement both opCmp and opEquals or just one or the other.  It says on the page about Associative Arrays: "The implementation may use either opEquals or opCmp or both."  Does that mean it uses whichever one is user-defined (or both if they're both user-defined)?  Or does it mean the user is responsible for defining both?

Also, it says "Care should be taken so that the results of opEquals and opCmp are consistent with each other when the struct/union objects are the same or not.", certainly this means that if a.opEquals(b), then a.opCmp(b) should be 0, but does the converse have to be true?

Is there somewhere I can find information about default operator implementations and consistency?
April 02, 2014
Contents of struct are compared field by field using comparison for the type of each field. Dynamic arrays are compared by contents. If you want to compare them by pointer use .ptr property.

opEquals and opCmp are not about hashing, I believe. They are just operators to help when dealing with chaining when different objects have same hash (since hash may be not unique)
April 03, 2014
On Wednesday, 2 April 2014 at 22:07:36 UTC, FreeSlave wrote:
> Contents of struct are compared field by field using comparison for the type of each field. Dynamic arrays are compared by contents. If you want to compare them by pointer use .ptr property.
>
> opEquals and opCmp are not about hashing, I believe. They are just operators to help when dealing with chaining when different objects have same hash (since hash may be not unique)

Thanks, I'll post the other questions in separate threads.
April 03, 2014
On Wednesday, 2 April 2014 at 20:39:47 UTC, FreeSlave wrote:
> On Wednesday, 2 April 2014 at 20:14:31 UTC, dnspies wrote:
>> How can I get the default-hash of a struct I've defined (to be used as part of the hash for some containing type)?
>
> UserDefined userDefined;
> writeln(typeid(UserDefined).getHash(&userDefined));
>
> Probably there is a better way. I don't like to call typeid for this purpose.

This doesn't work.  It prints two different hashes for equal objects.  I meant how do I get the default hash which is used by an associative array.

import std.stdio;

struct my_struct {
	int[] arr;
}

void main() {
	my_struct s1;
	s1.arr = [1,2,3];
	my_struct s2;
	s2.arr = [1,2,3];
	writeln(s1 == s2);
	writeln(typeid(my_struct).getHash(&s1));
	writeln(typeid(my_struct).getHash(&s2));
}

true
626617119
2124658624

April 03, 2014
dnspies:

> This doesn't work.  It prints two different hashes for equal objects.  I meant how do I get the default hash which is used by an associative array.
>
> import std.stdio;
>
> struct my_struct {
> 	int[] arr;
> }
>
> void main() {
> 	my_struct s1;
> 	s1.arr = [1,2,3];
> 	my_struct s2;
> 	s2.arr = [1,2,3];
> 	writeln(s1 == s2);
> 	writeln(typeid(my_struct).getHash(&s1));
> 	writeln(typeid(my_struct).getHash(&s2));
> }
>
> true
> 626617119
> 2124658624

Take a look at the output of this program:

import std.stdio;

struct MyStruct {
     int[] arr;
}

void main() {
     MyStruct s1;
     s1.arr = [1,2,3];
     MyStruct s2;
     s2.arr = [1,2,3];
     writeln(s1 == s2);
     writeln(typeid(MyStruct).getHash(&s1));
     writeln(typeid(MyStruct).getHash(&s2));

     int[MyStruct] aa;
     aa[s1] = 10;
     aa[s2] = 20;
     writeln(aa);
}


I have filed this big problem four years ago or more.

Workarounds: define (carefully!) the three hash protocol methods, or use a tuple.

Bye,
bearophile
April 03, 2014
On Thursday, 3 April 2014 at 21:42:18 UTC, bearophile wrote:
> dnspies:
>
>> This doesn't work.  It prints two different hashes for equal objects.  I meant how do I get the default hash which is used by an associative array.
>>
>> import std.stdio;
>>
>> struct my_struct {
>> 	int[] arr;
>> }
>>
>> void main() {
>> 	my_struct s1;
>> 	s1.arr = [1,2,3];
>> 	my_struct s2;
>> 	s2.arr = [1,2,3];
>> 	writeln(s1 == s2);
>> 	writeln(typeid(my_struct).getHash(&s1));
>> 	writeln(typeid(my_struct).getHash(&s2));
>> }
>>
>> true
>> 626617119
>> 2124658624
>
> Take a look at the output of this program:
>
> import std.stdio;
>
> struct MyStruct {
>      int[] arr;
> }
>
> void main() {
>      MyStruct s1;
>      s1.arr = [1,2,3];
>      MyStruct s2;
>      s2.arr = [1,2,3];
>      writeln(s1 == s2);
>      writeln(typeid(MyStruct).getHash(&s1));
>      writeln(typeid(MyStruct).getHash(&s2));
>
>      int[MyStruct] aa;
>      aa[s1] = 10;
>      aa[s2] = 20;
>      writeln(aa);
> }
>
>
> I have filed this big problem four years ago or more.
>
> Workarounds: define (carefully!) the three hash protocol methods, or use a tuple.
>
> Bye,
> bearophile

Oh so the problem isn't that that ISN'T the default hash used by an AA.  It's worse.  The problem is that that IS the default hash used by an AA.

When you say "use a tuple", do you mean that the hash implementation for Tuples is defined recursively and based on its members' hashes?  There doesn't seem to be an opHash for Tuples AFAICT.  If not, could you provide an example?

Also, if this problem isn't going to be fixed any time soon, shouldn't it be documented directly on the AA page somewhere?  It's just the sort of surprise that I would have no hope of figuring out when trying to debug my program.  (I put this wrapped_string into my AA, but when I try to fetch it again, it's disappeared!!??)

What's worse, there's no link provided to TypeInfo.getHash, instead it just says "If the KeyType is a struct or union type, a default mechanism is used to compute the hash and comparisons of it based on the binary data within the struct value" which sounds as though they're saying "don't worry, we've handled everything" which is the opposite of true.
April 03, 2014
On Thu, 03 Apr 2014 17:42:16 -0400, bearophile <bearophileHUGS@lycos.com> wrote:


> I have filed this big problem four years ago or more.

Bug report?

-Steve
April 03, 2014
Steven Schveighoffer:

> Bug report?

I don't remember, sorry, it's an ancient problem. Probably one of my top three D problems :-)

Bye,
bearophile
« First   ‹ Prev
1 2