DaveAKing / guava-libraries

Automatically exported from code.google.com/p/guava-libraries
Apache License 2.0
0 stars 0 forks source link

Providing a base object to minimize Object method implementation #1663

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
I've seen several issues concerning self-describing and equality 
implementation; and also, I find myself implementing a base object for these 
concerns. I was curious as to whether anyone would appreciate a guava standard 
base object that minimizes implementing standard object methods and also 
provides subtle conveniences (that don't deviate too far from the core standard 
methods):

  Base nonNull();

I recall one issue in particular in which the commenter checked for null by 
calling [o.getClass()]; he couldn't provide a message to the exception, but 
didn't have to import anything; how often is a message passed to 
NullPointerException? It's quick; and this returns "this". Consider overriding 
to change return type for method chaining.

  String toString();
  StringBuilder toStringBuilder([int|CharSequence]?);
  <A extends Appendable> A appendTo(A);
  void describeTo(Appendable); // minimal override

http://code.google.com/p/guava-libraries/issues/detail?id=1512&colspec=ID%20Type
%20Status%20Package%20Summary

Use cases were brought up in that issue concerning describing large data; 
implementations extending a base object that supports self-describing can 
benefit appending to a visiting appendable.

  boolean equals(Object);
  boolean equalsLogically(Object);
  boolean canEqual(Base o); 
  Class<?> comparisonClass(); // minimal override
  boolean doesEqual(Base o); // minimal override

http://code.google.com/p/guava-libraries/issues/detail?id=1499&colspec=ID%20Type
%20Status%20Package%20Summary

That (specialized) issue is generalized by this one; This allows [with, 
arguably, many methods] for defining default equals implementations that can be 
overridden with little effort and maintain symmetry and transitivity. I'd 
suspect that having only to override [comparisonClass &| doesEqual] could 
reduce repeat code.

  int hashCode()
  BigInteger hashBig()
  BigInteger comparisonClass()
  BigInteger hashBigSansComparisonClass()

I'll mention hashing for completeness; I'm assuming there's already something 
in mind concerning hashing and hash codes, but it would be nice to have it 
implemented on a base object. I'll only add that, if #comparisonClass() affects 
#equals, then it should also affect #hashCode. Again, there are definitely 
better ways to minimize hashing.

The following the some example of implementation:

class Base {

  [protected|public] Base() {}

  /* Intentionally, a method for checking for null references.
  */
  public Base nonNull() {return this;}

  public String toString() {
    return toStringBuilder().toString();
  }

  /** Convenient
  */
  public StringBuilder toStringBuilder([int|CharSequence]? arg) {
    return appendTo(new StringBuilder(arg));
  }

  /*
    @throws UncheckedIOException
    if an IOException (cause) is thrown

    @return
    the specified appendable [method chaining if wanted]
  */
  public <A extends Appendable> A appendTo(A a) {
    try {
      describeTo(a);
      return a;
    }
    catch (IOException x) {
      throw new UncheckedIOException(x);
    }
  }

  /*
    Override this to self-describe to appendable.

    @throws UncheckedIOException
  */
  [protected|public] void describeTo(Appendable a) throws IOException {
    a.append(super.toString());
  }

  public boolean equals(Object o) {
    return o==this || o!=null && equalsLogically(o);
  }

  /* Override by returning false to assert referential equality
  */
  [protected|public] boolean equalsLogically(@NonNull Object o) {
    if (!(o instanceof Base))
      return false;
    final Base b = (Base)o;
    return canEqual(b) && b.canEqual(this) && doesEqual(b);
  }

  /** Used for mutual possibility of equality; override (rarely)
    if type checking does not suffice in testing mutual
    possibility.
  */
  protected boolean canEqual(Base o) {
    final Class<?> clas = comparisonClass();
    return clas!=null && clas.isInstance(o);
  }

  /** Override to narrow what types suffice for
    possibly being equal.

    As of now, makes default #equals return false
  */
  protected Class<?> comparisonClass() {
    return null;
  }

  /** Override to implement equality test; note that
    by default, null and type check has been done.

    As of now, makes default #equals return false
  */
  protected boolean doesEqual(@NonNull Base o) {
    return false;
  }

  public int hashCode() {
    return hashBig().hashCode();
  }

  /** Is BigInteger too much?
  */
  [protected|public] BigInteger hashBig() {
    final int shift = 64;
    return hashBigSansComparisonClass().leftShift(shift)
        .or(BigInteger.valueOf(Objects.hashCode(comparisonClass())));
  }

  /**
    Override to implement hash behavior; at this point,
    comparison class need not be considered when implementing
    this operation.
  */
  protected BigInteger hashBigSansComparisonClass() {
    return BigInteger.valueOf(System.identityHashCode(this));
  }

}

// per Java 8
class UncheckedIOException extends RuntimeException {
  public UncheckedIOException(String msg, IOException x) {
    super(msg,x);
  }
  public UncheckedIOException(IOException x) {
    super(x);
  }
}

Original issue reported on code.google.com by jysjys1...@gmail.com on 10 Feb 2014 at 10:11

GoogleCodeExporter commented 9 years ago
[deleted comment]
GoogleCodeExporter commented 9 years ago
Minor corrections:

  /** Is BigInteger too much?
  */
  [protected|public] BigInteger hashBig() {
    final int shift = _32_;
    return hashBigSansComparisonClass().leftShift(shift)
        .or(BigInteger.valueOf(Objects.hashCode(comparisonClass())));
  }

  /*
    Override this to self-describe to appendable.

    @throws _IOException_
  */
  [protected|public] void describeTo(Appendable a) throws IOException {...}

Original comment by jysjys1...@gmail.com on 10 Feb 2014 at 10:18

GoogleCodeExporter commented 9 years ago
Sometimes there is little say other than... no.

I suggest you take *one* real-world problem that you're trying to solve, and 
post to Stack Overflow asking for help on the best way to solve it.  If that 
way involves a feature that could be in Guava, then file a feature request for 
just that.  Repeat if necessary.  As it stands, this issue just looks like a 
long list of solutions looking for problems.

Re: "minimize Object method implementation", you may want to see AutoValue 
(http://goo.gl/Ter394).

Original comment by kevinb@google.com on 10 Feb 2014 at 6:19

GoogleCodeExporter commented 9 years ago
This issue has been migrated to GitHub.

It can be found at https://github.com/google/guava/issues/<issue id>

Original comment by cgdecker@google.com on 1 Nov 2014 at 4:10

GoogleCodeExporter commented 9 years ago

Original comment by cgdecker@google.com on 3 Nov 2014 at 9:07