[ 
https://issues.apache.org/jira/browse/LUCENE-1188?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Chandan Raj Rupakheti updated LUCENE-1188:
------------------------------------------

    Description: 
I would like to talk about the implementation of equals and hashCode method  in 
org.apache.lucene.search.* package. 

Example One:

org.apache.lucene.search.spans.SpanTermQuery (Super Class)
        <- org.apache.lucene.search.payloads.BoostingTermQuery (Sub Class)

Observation:

* BoostingTermQuery defines equals but inherits hashCode from SpanTermQuery. 
Definition of equals is a code clone of SpanTermQuery with a change in class 
name. 

Intention:

I believe the intention of equals redefinition in BoostingTermQuery is not to 
make the objects of SpanTermQuery and BoostingTermQuery comparable. ie. 
spanTermQuery.equals(boostingTermQuery) == false && 
boostingTermQuery.equals(spanTermQuery) == false.


Problem:

With current implementation, the intention might not be respected as a result 
of symmetric property violation of equals contract i.e.
spanTermQuery.equals(boostingTermQuery) == true (can be) && 
boostingTermQuery.equals(spanTermQuery) == false. (always)
(Note: Provided their state variables are equal)

Solution:

Change implementation of equals in SpanTermQuery from:

{code:title=SpanTermQuery.java|borderStyle=solid}
  public boolean equals(Object o) {
    if (!(o instanceof SpanTermQuery))
      return false;
    SpanTermQuery other = (SpanTermQuery)o;
    return (this.getBoost() == other.getBoost())
      && this.term.equals(other.term);
  }
{code}

To:
{code:title=SpanTermQuery.java|borderStyle=solid}
  public boolean equals(Object o) {
        if(o == this) return true;
        if(o == null || o.getClass() != this.getClass()) return false;
//    if (!(o instanceof SpanTermQuery))
//      return false;
    SpanTermQuery other = (SpanTermQuery)o;
    return (this.getBoost() == other.getBoost())
      && this.term.equals(other.term);
  }
{code}

Advantage:

* BoostingTermQuery.equals and BoostingTermQuery.hashCode is not needed while 
still preserving the same intention as before.
 
* Any further subclassing that does not add new state variables in the extended 
classes of SpanTermQuery, does not have to redefine equals and hashCode. 

* Even if a new state variable is added in a subclass, the symmetric property 
of equals contract will still be respected irrespective of implementation (i.e. 
instanceof / getClass) of equals and hashCode in the subclasses.


Example Two:


org.apache.lucene.search.CachingWrapperFilter (Super Class)
        <- org.apache.lucene.search.CachingWrapperFilterHelper (Sub Class)

Observation:
Same as Example One.

Problem:
Same as Example one.

Solution:
Change equals in CachingWrapperFilter from:
{code:title=CachingWrapperFilter.java|borderStyle=solid}
  public boolean equals(Object o) {
    if (!(o instanceof CachingWrapperFilter)) return false;
    return this.filter.equals(((CachingWrapperFilter)o).filter);
  }
{code}

To:
{code:title=CachingWrapperFilter.java|borderStyle=solid}
  public boolean equals(Object o) {
//    if (!(o instanceof CachingWrapperFilter)) return false;
    if(o == this) return true;
    if(o == null || o.getClass() != this.getClass()) return false;
    return this.filter.equals(((CachingWrapperFilter)o).filter);
  }
{code}

Advantage:
Same as Example One. Here, CachingWrapperFilterHelper.equals and 
CachingWrapperFilterHelper.hashCode is not needed.


Example Three:

org.apache.lucene.search.MultiTermQuery (Abstract Parent)
        <- org.apache.lucene.search.FuzzyQuery (Concrete Sub)
        <- org.apache.lucene.search.WildcardQuery (Concrete Sub)

Observation (Not a problem):

* WildcardQuery defines equals but inherits hashCode from MultiTermQuery.
Definition of equals contains just super.equals invocation. 

* FuzzyQuery has few state variables added that are referenced in its equals 
and hashCode.
Intention:

I believe the intention here is not to make objects of FuzzyQuery and 
WildcardQuery comparable. ie. fuzzyQuery.equals(wildCardQuery) == false && 
wildCardQuery.equals(fuzzyQuery) == false.

Proposed Implementation:
How about changing the implementation of equals in MultiTermQuery from:

{code:title=MultiTermQuery.java|borderStyle=solid}
    public boolean equals(Object o) {
      if (this == o) return true;
      if (!(o instanceof MultiTermQuery)) return false;

      final MultiTermQuery multiTermQuery = (MultiTermQuery) o;

      if (!term.equals(multiTermQuery.term)) return false;

      return getBoost() == multiTermQuery.getBoost();
    }
{code}

To:
{code:title=MultiTermQuery.java|borderStyle=solid}
    public boolean equals(Object o) {
      if (this == o) return true;
//      if (!(o instanceof MultiTermQuery)) return false;
      if(o == null || o.getClass() != this.getClass()) return false;

      final MultiTermQuery multiTermQuery = (MultiTermQuery) o;

      if (!term.equals(multiTermQuery.term)) return false;

      return getBoost() == multiTermQuery.getBoost();
    }
{code}

Advantage:

Same as above. Here, WildcardQuery.equals is not needed as it does not define 
any new state. (FuzzyQuery.equals is still needed because FuzzyQuery defines 
new state.) 


  was:
I would like to talk about the implementation of equals and hashCode method  in 
org.apache.lucene.search.* package. 

Example One:

org.apache.lucene.search.spans.SpanTermQuery (Super Class)
        <- org.apache.lucene.search.payloads.BoostingTermQuery (Sub Class)

Observation:

* BoostingTermQuery defines equals but inherits hashCode from SpanTermQuery. 
Definition of equals is a code clone of SpanTermQuery with a change in class 
name. 

Intention:

I believe the intention of equals redefinition in BoostingTermQuery is not to 
make the objects of SpanTermQuery and BoostingTermQuery comparable. ie. 
spanTermQuery.equals(boostingTermQuery) == false && 
boostingTermQuery.equals(spanTermQuery) == false.


Problem:

With current implementation, the intention might not be respected as a result 
of symmetric property violation of equals contract i.e.
spanTermQuery.equals(boostingTermQuery) == true (can be) && 
boostingTermQuery.equals(spanTermQuery) == false. (always)
(Note: Provided their state variables are equal)

Solution:

Change implementation of equals in SpanTermQuery from:

{code:title=SpanTermQuery.java|borderStyle=solid}
  public boolean equals(Object o) {
    if (!(o instanceof SpanTermQuery))
      return false;
    SpanTermQuery other = (SpanTermQuery)o;
    return (this.getBoost() == other.getBoost())
      && this.term.equals(other.term);
  }
{code}

To:
{code:title=SpanTermQuery.java|borderStyle=solid}
  public boolean equals(Object o) {
        if(o == this) return true;
        if(o == null || o.getClass() != this.getClass()) return false;
//    if (!(o instanceof SpanTermQuery))
//      return false;
    SpanTermQuery other = (SpanTermQuery)o;
    return (this.getBoost() == other.getBoost())
      && this.term.equals(other.term);
  }
{code}

Advantage:

* Do not have to redefine equals and hashCode in BoostingTermQuery while 
preserving the same intention as before.
 
* Any further subclassing that does not add new state variables in the extended 
classes of SpanTermQuery, does not have to redefine equals and hashCode. 

* Even if a new state variable is added in a subclass, the symmetric property 
of equals contract will still be respected irrespective of implementation (i.e. 
instanceof / getClass) of equals and hashCode in the subclasses.


Example Two:


org.apache.lucene.search.CachingWrapperFilter (Super Class)
        <- org.apache.lucene.search.CachingWrapperFilterHelper (Sub Class)

Observation:
Same as Example One.

Problem:
Same as Example one.

Solution:
Change equals in CachingWrapperFilter from:
{code:title=CachingWrapperFilter.java|borderStyle=solid}
  public boolean equals(Object o) {
    if (!(o instanceof CachingWrapperFilter)) return false;
    return this.filter.equals(((CachingWrapperFilter)o).filter);
  }
{code}

To:
{code:title=CachingWrapperFilter.java|borderStyle=solid}
  public boolean equals(Object o) {
//    if (!(o instanceof CachingWrapperFilter)) return false;
    if(o == this) return true;
    if(o == null || o.getClass() != this.getClass()) return false;
    return this.filter.equals(((CachingWrapperFilter)o).filter);
  }
{code}

Advantage:
Same as Example One.


Example Three:

org.apache.lucene.search.MultiTermQuery (Abstract Parent)
        <- org.apache.lucene.search.FuzzyQuery (Concrete Sub)
        <- org.apache.lucene.search.WildcardQuery (Concrete Sub)

Observation (Not a problem):

* WildcardQuery defines equals but inherits hashCode from MultiTermQuery.
Definition of equals contains just super.equals invocation. 

* FuzzyQuery has few state variables added that are referenced in its equals 
and hashCode.
Intention:

I believe the intention here is not to make objects of FuzzyQuery and 
WildcardQuery comparable. ie. fuzzyQuery.equals(wildCardQuery) == false && 
wildCardQuery.equals(fuzzyQuery) == false.

Proposed Implementation:
How about changing the implementation of equals in MultiTermQuery from:

{code:title=MultiTermQuery.java|borderStyle=solid}
    public boolean equals(Object o) {
      if (this == o) return true;
      if (!(o instanceof MultiTermQuery)) return false;

      final MultiTermQuery multiTermQuery = (MultiTermQuery) o;

      if (!term.equals(multiTermQuery.term)) return false;

      return getBoost() == multiTermQuery.getBoost();
    }
{code}

To:
{code:title=MultiTermQuery.java|borderStyle=solid}
    public boolean equals(Object o) {
      if (this == o) return true;
//      if (!(o instanceof MultiTermQuery)) return false;
      if(o == null || o.getClass() != this.getClass()) return false;

      final MultiTermQuery multiTermQuery = (MultiTermQuery) o;

      if (!term.equals(multiTermQuery.term)) return false;

      return getBoost() == multiTermQuery.getBoost();
    }
{code}

Advantage:

Same as above.



Updated the advantage of the proposed solution to make it more clear.

> equals and hashCode implementation in org.apache.lucene.search.* package
> ------------------------------------------------------------------------
>
>                 Key: LUCENE-1188
>                 URL: https://issues.apache.org/jira/browse/LUCENE-1188
>             Project: Lucene - Java
>          Issue Type: Improvement
>          Components: Search
>    Affects Versions: 2.2, 2.3, 2.3.1
>         Environment: All
>            Reporter: Chandan Raj Rupakheti
>             Fix For: 2.2, 2.3, 2.3.1
>
>
> I would like to talk about the implementation of equals and hashCode method  
> in org.apache.lucene.search.* package. 
> Example One:
> org.apache.lucene.search.spans.SpanTermQuery (Super Class)
>       <- org.apache.lucene.search.payloads.BoostingTermQuery (Sub Class)
> Observation:
> * BoostingTermQuery defines equals but inherits hashCode from SpanTermQuery. 
> Definition of equals is a code clone of SpanTermQuery with a change in class 
> name. 
> Intention:
> I believe the intention of equals redefinition in BoostingTermQuery is not to 
> make the objects of SpanTermQuery and BoostingTermQuery comparable. ie. 
> spanTermQuery.equals(boostingTermQuery) == false && 
> boostingTermQuery.equals(spanTermQuery) == false.
> Problem:
> With current implementation, the intention might not be respected as a result 
> of symmetric property violation of equals contract i.e.
> spanTermQuery.equals(boostingTermQuery) == true (can be) && 
> boostingTermQuery.equals(spanTermQuery) == false. (always)
> (Note: Provided their state variables are equal)
> Solution:
> Change implementation of equals in SpanTermQuery from:
> {code:title=SpanTermQuery.java|borderStyle=solid}
>   public boolean equals(Object o) {
>     if (!(o instanceof SpanTermQuery))
>       return false;
>     SpanTermQuery other = (SpanTermQuery)o;
>     return (this.getBoost() == other.getBoost())
>       && this.term.equals(other.term);
>   }
> {code}
> To:
> {code:title=SpanTermQuery.java|borderStyle=solid}
>   public boolean equals(Object o) {
>       if(o == this) return true;
>       if(o == null || o.getClass() != this.getClass()) return false;
> //    if (!(o instanceof SpanTermQuery))
> //      return false;
>     SpanTermQuery other = (SpanTermQuery)o;
>     return (this.getBoost() == other.getBoost())
>       && this.term.equals(other.term);
>   }
> {code}
> Advantage:
> * BoostingTermQuery.equals and BoostingTermQuery.hashCode is not needed while 
> still preserving the same intention as before.
>  
> * Any further subclassing that does not add new state variables in the 
> extended classes of SpanTermQuery, does not have to redefine equals and 
> hashCode. 
> * Even if a new state variable is added in a subclass, the symmetric property 
> of equals contract will still be respected irrespective of implementation 
> (i.e. instanceof / getClass) of equals and hashCode in the subclasses.
> Example Two:
> org.apache.lucene.search.CachingWrapperFilter (Super Class)
>       <- org.apache.lucene.search.CachingWrapperFilterHelper (Sub Class)
> Observation:
> Same as Example One.
> Problem:
> Same as Example one.
> Solution:
> Change equals in CachingWrapperFilter from:
> {code:title=CachingWrapperFilter.java|borderStyle=solid}
>   public boolean equals(Object o) {
>     if (!(o instanceof CachingWrapperFilter)) return false;
>     return this.filter.equals(((CachingWrapperFilter)o).filter);
>   }
> {code}
> To:
> {code:title=CachingWrapperFilter.java|borderStyle=solid}
>   public boolean equals(Object o) {
> //    if (!(o instanceof CachingWrapperFilter)) return false;
>     if(o == this) return true;
>     if(o == null || o.getClass() != this.getClass()) return false;
>     return this.filter.equals(((CachingWrapperFilter)o).filter);
>   }
> {code}
> Advantage:
> Same as Example One. Here, CachingWrapperFilterHelper.equals and 
> CachingWrapperFilterHelper.hashCode is not needed.
> Example Three:
> org.apache.lucene.search.MultiTermQuery (Abstract Parent)
>       <- org.apache.lucene.search.FuzzyQuery (Concrete Sub)
>       <- org.apache.lucene.search.WildcardQuery (Concrete Sub)
> Observation (Not a problem):
> * WildcardQuery defines equals but inherits hashCode from MultiTermQuery.
> Definition of equals contains just super.equals invocation. 
> * FuzzyQuery has few state variables added that are referenced in its equals 
> and hashCode.
> Intention:
> I believe the intention here is not to make objects of FuzzyQuery and 
> WildcardQuery comparable. ie. fuzzyQuery.equals(wildCardQuery) == false && 
> wildCardQuery.equals(fuzzyQuery) == false.
> Proposed Implementation:
> How about changing the implementation of equals in MultiTermQuery from:
> {code:title=MultiTermQuery.java|borderStyle=solid}
>     public boolean equals(Object o) {
>       if (this == o) return true;
>       if (!(o instanceof MultiTermQuery)) return false;
>       final MultiTermQuery multiTermQuery = (MultiTermQuery) o;
>       if (!term.equals(multiTermQuery.term)) return false;
>       return getBoost() == multiTermQuery.getBoost();
>     }
> {code}
> To:
> {code:title=MultiTermQuery.java|borderStyle=solid}
>     public boolean equals(Object o) {
>       if (this == o) return true;
> //      if (!(o instanceof MultiTermQuery)) return false;
>       if(o == null || o.getClass() != this.getClass()) return false;
>       final MultiTermQuery multiTermQuery = (MultiTermQuery) o;
>       if (!term.equals(multiTermQuery.term)) return false;
>       return getBoost() == multiTermQuery.getBoost();
>     }
> {code}
> Advantage:
> Same as above. Here, WildcardQuery.equals is not needed as it does not define 
> any new state. (FuzzyQuery.equals is still needed because FuzzyQuery defines 
> new state.) 

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.


---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to