Equals and HashCode Builder

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
25 messages Options
12
Reply | Threaded
Open this post in threaded view
|

Equals and HashCode Builder

Vitor Medina Cruz
Reply | Threaded
Open this post in threaded view
|

Re: Equals and HashCode Builder

Stephane Ducasse-3
Not that I know. 
Because it can be a little project.
Now what is the key point to encapsulate this computation?

On Mon, Oct 2, 2017 at 12:51 AM, Vitor Medina Cruz <[hidden email]> wrote:

Livre de vírus. www.avg.com.

Reply | Threaded
Open this post in threaded view
|

Re: Equals and HashCode Builder

EstebanLM
in java, because this is a pain to do it each time. 
for us, maybe for the same… even if is a lot easier.

Esteban

On 2 Oct 2017, at 09:42, Stephane Ducasse <[hidden email]> wrote:

Not that I know. 
Because it can be a little project.
Now what is the key point to encapsulate this computation?

On Mon, Oct 2, 2017 at 12:51 AM, Vitor Medina Cruz <[hidden email]> wrote:

Livre de vírus. www.avg.com.
<a href="x-msg://32/#m_7375944706768832526_DAB4FAD8-2DD7-40BB-A1B8-4E2AA1F9FDF2" width="1" height="1" class="">


Reply | Threaded
Open this post in threaded view
|

Re: Equals and HashCode Builder

Denis Kudriashov
In reply to this post by Vitor Medina Cruz
Hi.

I just use RBGenerateEqualHashRefactoring for this:

r := RBGenerateEqualHashRefactoring className: MyClass variables: #(vars which should be used in equal and hash).
r execute

But it is a bit different.
Reply | Threaded
Open this post in threaded view
|

Re: Equals and HashCode Builder

Jose San Leandro
In reply to this post by EstebanLM
Hi,

I wrote a generator for that. Probably it makes no sense to publish it as a standalone project. I tend to think code generation fits better in other languages.
I can paste the relevant code here if needed.

2017-10-02 9:44 GMT+02:00 Esteban Lorenzano <[hidden email]>:
in java, because this is a pain to do it each time. 
for us, maybe for the same… even if is a lot easier.

Esteban


On 2 Oct 2017, at 09:42, Stephane Ducasse <[hidden email]> wrote:

Not that I know. 
Because it can be a little project.
Now what is the key point to encapsulate this computation?

On Mon, Oct 2, 2017 at 12:51 AM, Vitor Medina Cruz <[hidden email]> wrote:

Livre de vírus. www.avg.com.



Reply | Threaded
Open this post in threaded view
|

Re: Equals and HashCode Builder

Stephane Ducasse-3
Publish it in a package and let us have a look.


On Mon, Oct 2, 2017 at 9:53 AM, Jose San Leandro <[hidden email]> wrote:
Hi,

I wrote a generator for that. Probably it makes no sense to publish it as a standalone project. I tend to think code generation fits better in other languages.
I can paste the relevant code here if needed.

2017-10-02 9:44 GMT+02:00 Esteban Lorenzano <[hidden email]>:
in java, because this is a pain to do it each time. 
for us, maybe for the same… even if is a lot easier.

Esteban


On 2 Oct 2017, at 09:42, Stephane Ducasse <[hidden email]> wrote:

Not that I know. 
Because it can be a little project.
Now what is the key point to encapsulate this computation?

On Mon, Oct 2, 2017 at 12:51 AM, Vitor Medina Cruz <[hidden email]> wrote:

Livre de vírus. www.avg.com.




Reply | Threaded
Open this post in threaded view
|

Re: Equals and HashCode Builder

Vitor Medina Cruz
in java, because this is a pain to do it each time.
for us, maybe for the same… even if is a lot easier.

Yeah, and it is boring to implement that every time, especially because it is tricky to get it right sometimes. Another interesting thing I use in Java to test my equals and hash implementation is the http://jqno.nl/equalsverifier/

I just use RBGenerateEqualHashRefactoring for this:

Oh! That is nice, I will give a deeper look at it, I think this may do the job. Thanks!




On Mon, Oct 2, 2017 at 10:09 AM, Stephane Ducasse <[hidden email]> wrote:
Publish it in a package and let us have a look.


On Mon, Oct 2, 2017 at 9:53 AM, Jose San Leandro <[hidden email]> wrote:
Hi,

I wrote a generator for that. Probably it makes no sense to publish it as a standalone project. I tend to think code generation fits better in other languages.
I can paste the relevant code here if needed.

2017-10-02 9:44 GMT+02:00 Esteban Lorenzano <[hidden email]>:
in java, because this is a pain to do it each time. 
for us, maybe for the same… even if is a lot easier.

Esteban


On 2 Oct 2017, at 09:42, Stephane Ducasse <[hidden email]> wrote:

Not that I know. 
Because it can be a little project.
Now what is the key point to encapsulate this computation?

On Mon, Oct 2, 2017 at 12:51 AM, Vitor Medina Cruz <[hidden email]> wrote:

Livre de vírus. www.avg.com.





Reply | Threaded
Open this post in threaded view
|

Re: Equals and HashCode Builder

Sean P. DeNigris
Administrator
In reply to this post by Denis Kudriashov
Denis Kudriashov wrote
> I just use RBGenerateEqualHashRefactoring for this:
>
> r := RBGenerateEqualHashRefactoring className: MyClass variables: #(vars
> which should be used in equal and hash).
> r execute

That is sooooo cool! I shudder to think how many times I implemented just
that by hand!!

Two questions/comments about the generated code:
1. #=
        ...
        self class = anObject class "should compare #species instead?"
                ifFalse: [ ^ false ].
        ...
Typically, I've seen #species instead of #class in the guard statement.
Should we change it to that?


2. #hash
        ^ var1 hash bitXor: (var2 hash bitXor: var3 hash)
Is this implementation always safe? It's what I usually hand roll based on
what I've seen, but Andres Valloud wrote a whole (large) book on hashing, so
I've always wondered if I was missing something…



-----
Cheers,
Sean
--
Sent from: http://forum.world.st/Pharo-Smalltalk-Users-f1310670.html

Cheers,
Sean
Reply | Threaded
Open this post in threaded view
|

Re: Equals and HashCode Builder

Sean P. DeNigris
Administrator
In reply to this post by Denis Kudriashov
Denis Kudriashov wrote
> I just use RBGenerateEqualHashRefactoring for this:

I added your answer to the Pharo wiki. Is this available through the UI? If
not, maybe it should be!



-----
Cheers,
Sean
--
Sent from: http://forum.world.st/Pharo-Smalltalk-Users-f1310670.html

Cheers,
Sean
Reply | Threaded
Open this post in threaded view
|

Re: Equals and HashCode Builder

Denis Kudriashov
In reply to this post by Sean P. DeNigris
Hi Sean.

I did not know about quality of generated hash function. 
But if I remember correctly the same code is generated for java using Eclipse or Idea. So it should be good enough.

2017-10-02 16:37 GMT+02:00 Sean P. DeNigris <[hidden email]>:
Denis Kudriashov wrote
> I just use RBGenerateEqualHashRefactoring for this:
>
> r := RBGenerateEqualHashRefactoring className: MyClass variables: #(vars
> which should be used in equal and hash).
> r execute

That is sooooo cool! I shudder to think how many times I implemented just
that by hand!!

Two questions/comments about the generated code:
1. #=
        ...
        self class = anObject class "should compare #species instead?"
                ifFalse: [ ^ false ].
        ...
Typically, I've seen #species instead of #class in the guard statement.
Should we change it to that?


2. #hash
        ^ var1 hash bitXor: (var2 hash bitXor: var3 hash)
Is this implementation always safe? It's what I usually hand roll based on
what I've seen, but Andres Valloud wrote a whole (large) book on hashing, so
I've always wondered if I was missing something…



-----
Cheers,
Sean
--
Sent from: http://forum.world.st/Pharo-Smalltalk-Users-f1310670.html


Reply | Threaded
Open this post in threaded view
|

Re: Equals and HashCode Builder

Denis Kudriashov
In reply to this post by Sean P. DeNigris
2017-10-02 16:41 GMT+02:00 Sean P. DeNigris <[hidden email]>:
Denis Kudriashov wrote
> I just use RBGenerateEqualHashRefactoring for this:

I added your answer to the Pharo wiki. Is this available through the UI? If
not, maybe it should be!


As I know it not exists
 

Reply | Threaded
Open this post in threaded view
|

Re: Equals and HashCode Builder

Vitor Medina Cruz
I think it should have an option to generate with species (which I think should be the default). Also It would be nice if it could implement the solution for pitfall #4 described in http://www.artima.com/lejava/articles/equality.html

On Mon, Oct 2, 2017 at 11:45 AM, Denis Kudriashov <[hidden email]> wrote:
2017-10-02 16:41 GMT+02:00 Sean P. DeNigris <[hidden email]>:
Denis Kudriashov wrote
> I just use RBGenerateEqualHashRefactoring for this:

I added your answer to the Pharo wiki. Is this available through the UI? If
not, maybe it should be!


As I know it not exists
 


Reply | Threaded
Open this post in threaded view
|

Re: Equals and HashCode Builder

Denis Kudriashov
In reply to this post by Sean P. DeNigris

2017-10-02 16:37 GMT+02:00 Sean P. DeNigris <[hidden email]>:

Two questions/comments about the generated code:
1. #=
        ...
        self class = anObject class "should compare #species instead?"
                ifFalse: [ ^ false ].
        ...
Typically, I've seen #species instead of #class in the guard statement.
Should we change it to that?

I doubt that it is important for domain classes. Because I never saw the user of #species which is not a kind of Collection. And for collections this refactoring is not valid anyway.
 


2. #hash
        ^ var1 hash bitXor: (var2 hash bitXor: var3 hash)
Is this implementation always safe? It's what I usually hand roll based on
what I've seen, but Andres Valloud wrote a whole (large) book on hashing, so
I've always wondered if I was missing something…



-----
Cheers,
Sean
--
Sent from: http://forum.world.st/Pharo-Smalltalk-Users-f1310670.html


Reply | Threaded
Open this post in threaded view
|

Re: Equals and HashCode Builder

Vitor Medina Cruz
I am sorry, not species, but #isKindOf istead of #= to compare classes.

On Mon, Oct 2, 2017 at 11:57 AM, Denis Kudriashov <[hidden email]> wrote:

2017-10-02 16:37 GMT+02:00 Sean P. DeNigris <[hidden email]>:

Two questions/comments about the generated code:
1. #=
        ...
        self class = anObject class "should compare #species instead?"
                ifFalse: [ ^ false ].
        ...
Typically, I've seen #species instead of #class in the guard statement.
Should we change it to that?

I doubt that it is important for domain classes. Because I never saw the user of #species which is not a kind of Collection. And for collections this refactoring is not valid anyway.
 


2. #hash
        ^ var1 hash bitXor: (var2 hash bitXor: var3 hash)
Is this implementation always safe? It's what I usually hand roll based on
what I've seen, but Andres Valloud wrote a whole (large) book on hashing, so
I've always wondered if I was missing something…



-----
Cheers,
Sean
--
Sent from: http://forum.world.st/Pharo-Smalltalk-Users-f1310670.html



Reply | Threaded
Open this post in threaded view
|

Re: Equals and HashCode Builder

Denis Kudriashov

2017-10-02 17:13 GMT+02:00 Vitor Medina Cruz <[hidden email]>:
I am sorry, not species, but #isKindOf istead of #= to compare classes.

It is bad idea. #= should be transitive. How you will generate it with isKindOf: logic? You need to know common parent.

Also I not remember cases where I was needed two instances of different classes to be equal.
And I can imaging the problems which it will lead to.
 

On Mon, Oct 2, 2017 at 11:57 AM, Denis Kudriashov <[hidden email]> wrote:

2017-10-02 16:37 GMT+02:00 Sean P. DeNigris <[hidden email]>:

Two questions/comments about the generated code:
1. #=
        ...
        self class = anObject class "should compare #species instead?"
                ifFalse: [ ^ false ].
        ...
Typically, I've seen #species instead of #class in the guard statement.
Should we change it to that?

I doubt that it is important for domain classes. Because I never saw the user of #species which is not a kind of Collection. And for collections this refactoring is not valid anyway.
 


2. #hash
        ^ var1 hash bitXor: (var2 hash bitXor: var3 hash)
Is this implementation always safe? It's what I usually hand roll based on
what I've seen, but Andres Valloud wrote a whole (large) book on hashing, so
I've always wondered if I was missing something…



-----
Cheers,
Sean
--
Sent from: http://forum.world.st/Pharo-Smalltalk-Users-f1310670.html




Reply | Threaded
Open this post in threaded view
|

Re: Equals and HashCode Builder

Andrew P. Black
In reply to this post by Sean P. DeNigris

> On 2 Oct 2017, at 16:37 , Sean P. DeNigris <[hidden email]> wrote:
>
> 2. #hash
> ^ var1 hash bitXor: (var2 hash bitXor: var3 hash)
> Is this implementation always safe? It's what I usually hand roll based on
> what I've seen, but Andres Valloud wrote a whole (large) book on hashing, so
> I've always wondered if I was missing something…

If you read Andres book (which is hard, because he won’t make it available online), you will learn that it’s better to
take the order of the instance variables into account.  #bitXor: is commutative, so it of course ignores order.

In other words, if you have a Point with x and y fields, then 3@9 and 9@3 will have the same hash.

For this reason, it’s better to multiply successive fields by a constant (e.g. shifting left by 2) before XORing them into the hash.  But then, for objects with lots of fields, the later ones are lot completely, because they are multiplied by a number so large that they are out of the range of the hash.

One can avoid this by using a circular shift to implement the multiply.

All of this was, I thought, implemented in a #hashCombine: method, but I can’t find it in my image.  Maybe some other Smalltalk ...



Reply | Threaded
Open this post in threaded view
|

Re: Equals and HashCode Builder

Vitor Medina Cruz
Denis,

That can be done with an canEqual implementation as described by http://www.artima.com/lejava/articles/equality.html.

For this reason, it’s better to multiply successive fields by a constant (e.g. shifting left by 2) before XORing them into the hash.  But then, for objects with lots of fields, the later ones are lot completely, because they are multiplied by a number so large that they are out of the range of the hash.

I think this exactly what HasCodeBuidler does, however I saw no special treatment for hashes made of many fields....



On Mon, Oct 2, 2017 at 12:38 PM, Prof. Andrew P. Black <[hidden email]> wrote:

> On 2 Oct 2017, at 16:37 , Sean P. DeNigris <[hidden email]> wrote:
>
> 2. #hash
>       ^ var1 hash bitXor: (var2 hash bitXor: var3 hash)
> Is this implementation always safe? It's what I usually hand roll based on
> what I've seen, but Andres Valloud wrote a whole (large) book on hashing, so
> I've always wondered if I was missing something…

If you read Andres book (which is hard, because he won’t make it available online), you will learn that it’s better to
take the order of the instance variables into account.  #bitXor: is commutative, so it of course ignores order.

In other words, if you have a Point with x and y fields, then 3@9 and 9@3 will have the same hash.

For this reason, it’s better to multiply successive fields by a constant (e.g. shifting left by 2) before XORing them into the hash.  But then, for objects with lots of fields, the later ones are lot completely, because they are multiplied by a number so large that they are out of the range of the hash.

One can avoid this by using a circular shift to implement the multiply.

All of this was, I thought, implemented in a #hashCombine: method, but I can’t find it in my image.  Maybe some other Smalltalk ...




Reply | Threaded
Open this post in threaded view
|

Re: Equals and HashCode Builder

Denis Kudriashov
In reply to this post by Denis Kudriashov

2017-10-02 17:30 GMT+02:00 Denis Kudriashov <[hidden email]>:

2017-10-02 17:13 GMT+02:00 Vitor Medina Cruz <[hidden email]>:
I am sorry, not species, but #isKindOf istead of #= to compare classes.

It is bad idea. #= should be transitive.

Oh, I used wrong word, shame on me :). I tried to say commutative.
 
How you will generate it with isKindOf: logic? You need to know common parent.

Also I not remember cases where I was needed two instances of different classes to be equal.
And I can imaging the problems which it will lead to.
 

On Mon, Oct 2, 2017 at 11:57 AM, Denis Kudriashov <[hidden email]> wrote:

2017-10-02 16:37 GMT+02:00 Sean P. DeNigris <[hidden email]>:

Two questions/comments about the generated code:
1. #=
        ...
        self class = anObject class "should compare #species instead?"
                ifFalse: [ ^ false ].
        ...
Typically, I've seen #species instead of #class in the guard statement.
Should we change it to that?

I doubt that it is important for domain classes. Because I never saw the user of #species which is not a kind of Collection. And for collections this refactoring is not valid anyway.
 


2. #hash
        ^ var1 hash bitXor: (var2 hash bitXor: var3 hash)
Is this implementation always safe? It's what I usually hand roll based on
what I've seen, but Andres Valloud wrote a whole (large) book on hashing, so
I've always wondered if I was missing something…



-----
Cheers,
Sean
--
Sent from: http://forum.world.st/Pharo-Smalltalk-Users-f1310670.html





Reply | Threaded
Open this post in threaded view
|

Re: Equals and HashCode Builder

Vitor Medina Cruz
Yes, canEqual implementation also make #= be commutative.

On Tue, Oct 3, 2017 at 11:11 AM, Denis Kudriashov <[hidden email]> wrote:

2017-10-02 17:30 GMT+02:00 Denis Kudriashov <[hidden email]>:

2017-10-02 17:13 GMT+02:00 Vitor Medina Cruz <[hidden email]>:
I am sorry, not species, but #isKindOf istead of #= to compare classes.

It is bad idea. #= should be transitive.

Oh, I used wrong word, shame on me :). I tried to say commutative.
 
How you will generate it with isKindOf: logic? You need to know common parent.

Also I not remember cases where I was needed two instances of different classes to be equal.
And I can imaging the problems which it will lead to.
 

On Mon, Oct 2, 2017 at 11:57 AM, Denis Kudriashov <[hidden email]> wrote:

2017-10-02 16:37 GMT+02:00 Sean P. DeNigris <[hidden email]>:

Two questions/comments about the generated code:
1. #=
        ...
        self class = anObject class "should compare #species instead?"
                ifFalse: [ ^ false ].
        ...
Typically, I've seen #species instead of #class in the guard statement.
Should we change it to that?

I doubt that it is important for domain classes. Because I never saw the user of #species which is not a kind of Collection. And for collections this refactoring is not valid anyway.
 


2. #hash
        ^ var1 hash bitXor: (var2 hash bitXor: var3 hash)
Is this implementation always safe? It's what I usually hand roll based on
what I've seen, but Andres Valloud wrote a whole (large) book on hashing, so
I've always wondered if I was missing something…



-----
Cheers,
Sean
--
Sent from: http://forum.world.st/Pharo-Smalltalk-Users-f1310670.html






Reply | Threaded
Open this post in threaded view
|

Re: Equals and HashCode Builder

Stephane Ducasse-3
Noury also proposed a trait to avoid to systematically have to implement hash.
Vitor why don't you take it as a small project to propose a solution for Pharo.

On Thu, Oct 5, 2017 at 6:34 PM, Vitor Medina Cruz <[hidden email]> wrote:

> Yes, canEqual implementation also make #= be commutative.
>
> On Tue, Oct 3, 2017 at 11:11 AM, Denis Kudriashov <[hidden email]>
> wrote:
>>
>>
>> 2017-10-02 17:30 GMT+02:00 Denis Kudriashov <[hidden email]>:
>>>
>>>
>>> 2017-10-02 17:13 GMT+02:00 Vitor Medina Cruz <[hidden email]>:
>>>>
>>>> I am sorry, not species, but #isKindOf istead of #= to compare classes.
>>>
>>>
>>> It is bad idea. #= should be transitive.
>>
>>
>> Oh, I used wrong word, shame on me :). I tried to say commutative.
>>
>>>
>>> How you will generate it with isKindOf: logic? You need to know common
>>> parent.
>>>
>>> Also I not remember cases where I was needed two instances of different
>>> classes to be equal.
>>> And I can imaging the problems which it will lead to.
>>>
>>>>
>>>>
>>>> On Mon, Oct 2, 2017 at 11:57 AM, Denis Kudriashov <[hidden email]>
>>>> wrote:
>>>>>
>>>>>
>>>>> 2017-10-02 16:37 GMT+02:00 Sean P. DeNigris <[hidden email]>:
>>>>>>
>>>>>>
>>>>>> Two questions/comments about the generated code:
>>>>>> 1. #=
>>>>>>         ...
>>>>>>         self class = anObject class "should compare #species instead?"
>>>>>>                 ifFalse: [ ^ false ].
>>>>>>         ...
>>>>>> Typically, I've seen #species instead of #class in the guard
>>>>>> statement.
>>>>>> Should we change it to that?
>>>>>
>>>>>
>>>>> I doubt that it is important for domain classes. Because I never saw
>>>>> the user of #species which is not a kind of Collection. And for collections
>>>>> this refactoring is not valid anyway.
>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>> 2. #hash
>>>>>>         ^ var1 hash bitXor: (var2 hash bitXor: var3 hash)
>>>>>> Is this implementation always safe? It's what I usually hand roll
>>>>>> based on
>>>>>> what I've seen, but Andres Valloud wrote a whole (large) book on
>>>>>> hashing, so
>>>>>> I've always wondered if I was missing something…
>>>>>>
>>>>>>
>>>>>>
>>>>>> -----
>>>>>> Cheers,
>>>>>> Sean
>>>>>> --
>>>>>> Sent from: http://forum.world.st/Pharo-Smalltalk-Users-f1310670.html
>>>>>>
>>>>>
>>>>
>>>
>>
>

12