szehon-ho commented on code in PR #58002:
URL: https://github.com/apache/spark/pull/58002#discussion_r3807138010


##########
sql/catalyst/src/main/java/org/apache/spark/sql/connector/catalog/functions/BoundFunction.java:
##########
@@ -100,4 +135,49 @@ default String canonicalName() {
     // bugs if not replaced before release.
     return UUID.randomUUID().toString();
   }
+
+  /**
+   * Implementations SHOULD override {@link Object#equals(Object)} and {@link 
Object#hashCode()}.
+   * <p>
+   * Spark binds a function afresh every time it converts a partitioning or 
ordering reported by a
+   * source, so two reports of the same transform -- from two scans of the 
same table, say -- hold
+   * two bound instances. Spark compares the partition transform expressions 
built from them with
+   * ordinary expression equality, which reaches this method. With the 
inherited identity comparison
+   * the two are never equal, and Spark cannot deduplicate the expressions, 
reuse a scan that
+   * reports them, or recognize two subplans as the same. That costs 
optimizations only: results
+   * are unaffected either way.
+   * <p>
+   * Compare whatever state affects behaviour. {@link #canonicalName()} on its 
own is not
+   * necessarily enough: it answers a narrower question and is allowed to be 
coarse, so two
+   * functions can share one and still differ in {@link #inputTypes()}, {@link 
#resultType()},
+   * {@link #isResultNullable()}, {@link #isDeterministic()}, or a {@link 
ReducibleFunction}'s
+   * reducers. Comparing the name IS sufficient for an implementation whose 
names already encode
+   * everything that distinguishes its functions -- one name per argument 
type, say. Only the
+   * implementation knows which of its state matters, which is why Spark 
cannot derive this
+   * comparison itself. Note that a coarse name does not have to carry the 
whole identity: Spark
+   * compares the transform's arguments separately.
+   * <p>
+   * This is the FINER of the two comparisons, so two functions that compare 
equal must also return
+   * the same {@link #canonicalName()}; an implementation overriding this 
method should override
+   * that one too, rather than leave it at its default.
+   * <p>
+   * Two functions that can produce DIFFERENT values must NOT compare equal. 
Being too coarse is the
+   * direction that costs more than optimizations, and it is not confined to 
partition transforms: a
+   * {@link ScalarFunction} or an {@link AggregateFunction} is held by the 
expression Spark builds
+   * for an ordinary call to it, so the same {@code equals} decides whether 
two such calls are the
+   * same expression, and Spark may then evaluate one where the query asked 
for the other.
+   * <p>
+   * Whatever is compared must be stable across {@code bind} calls, and {@code 
hashCode} must agree
+   * with {@code equals}, since Spark puts these expressions in hash-based 
collections.
+   */
+  @Override
+  boolean equals(Object other);

Review Comment:
   its definitely correct but its a bit long and difficult to parse, if a 
connector is just trying to implement a function.  (from the point of view of 
someone not so experienced in Spark)
   
   Can this work:
   ```
   /**
    * Implementations SHOULD override {@link Object#equals(Object)} and
    * {@link Object#hashCode()}.
    * <p>
    * Without a stable {@code equals}/{@code hashCode}, Spark can miss
    * optimizations such as:
    * <ul>
    *   <li>keeping a union's keyed partitioning</li>
    *   <li>retaining a reported ordering that matches the partitioning</li>
    *   <li>reusing identical bucketed scans</li>
    *   <li>recognizing two identical subplans</li>
    * </ul>
    * Missed matches cost performance only, never correctness.
    * <p>
    * Compare whatever state affects behaviour, and keep it stable across
    * {@code bind} calls. {@link #canonicalName()} alone is not always enough.
    * Two functions that can produce different values must not compare equal.
    * {@code hashCode} must agree with {@code equals}.
    * <p>
    * If this method is overridden, {@link #canonicalName()} should be 
overridden
    * as well so equal functions share the same name.
    */
   @Override
   boolean equals(Object other);
   /**
    * Must agree with {@link #equals(Object)}. See that method.
    */
   @Override
   int hashCode();
   ```



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to