Display warning on equals comparing non-references#8120
Display warning on equals comparing non-references#8120dwijnand merged 1 commit intoscala:2.13.xfrom
equals comparing non-references#8120Conversation
998619a to
b1cf03a
Compare
|
Is this within expectations? 🤔 --- a/test/files/neg/checksensible.check
+++ b/test/files/neg/checksensible.check
@@ -112,6 +112,9 @@ checksensible.scala:111: warning: comparing values of types AnyVal and Int using
checksensible.scala:114: warning: comparing values of types A and Int using `equals` is unsafe due to cooperative equality; use `==` instead
def foo[A](a: A) = a.equals(1)
^
+checksensible.scala:118: warning: comparing values of types Int and Int using `equals` is unsafe due to cooperative equality; use `==` instead
+ 1 equals 1
+ ^
error: No warnings can be incurred under -Werror.
-38 warnings found
+39 warnings found
one error found
diff --git a/test/files/neg/checksensible.scala b/test/files/neg/checksensible.scala
index 7542509e55..37dfc0f2fc 100644
--- a/test/files/neg/checksensible.scala
+++ b/test/files/neg/checksensible.scala
@@ -114,4 +114,6 @@ class AnyEqualsTest {
def foo[A](a: A) = a.equals(1)
// ok
def bar[A <: AnyRef](a: A) = a.equals(1)
+
+ 1 equals 1
}
|
|
I'm not sure I like this. There are a lot of places where calling |
Nope. I need to filter out |
b1cf03a to
db58db9
Compare
Could you share some examples? Something like the following? def foo[A](a: A) = a.equals(1)In a normal application either written in Scala or Scala.JS, is the benefit worth the confusion of |
|
If we're keeping cooperative equality maybe this warning should be opt-out-able, including globally opt-out-able for codebases where it's throughout. |
|
It's mostly necessary to implement Java-like contracts. Here are the changes I need to apply to the Scala.js codebase to accommodate this PR: |
|
This one is particularly representative: if (self.asInstanceOf[AnyRef] eq null) that.asInstanceOf[AnyRef] eq null
- else self.equals(that)
+ else self.asInstanceOf[AnyRef].equals(that)Perhaps we should have a method that looks less like a cast and more like "ok, convert this to a reference value, boxing if necessary". Say it's called |
|
Can we move this one forward? It seems very rare that one would actually have to call |
|
Are there something I can do to improve this PR, or is warning a wrong-headed approach? |
|
@eed3si9n should we close this, as there's no obvious path forward? |
|
@lrytz I find that symbolic operator final def ==(that: Any): Boolean = this equals thatand If we're saying it's a shorthand to force boxing, that's even more surprising, and |
|
I'm supportive of the warning, but it's a complicated topic, so I'd really like to get more input, for example from @sjrd (again), @Ichoran, @NthPortal, @som-snytt, @retronym. Random idea: would it make sense to have |
|
I find the referenced bug particularly compelling. I think having the warning helps make a sharp edge a little bit safer. I think it is a reasonable warning, unless someone brings up a use case where the warned-about behaviour is correct and Scala-like. Sébastien is in a fairly unique position of having to conform to Java's behaviour, which is not cooperatively equal; however, if one were to design similar APIs (e.g. like that of |
If we keep the collaborative equality, then I think that makes sense. I'd rather see |
db58db9 to
1d6121b
Compare
|
Rebased against 2.13.x. |
|
@sjrd given we have configurable warnings now, are you more warm to this idea? Personally I like the look of it, and I agree that if a standard library maintainer can shoot their own foot, this warning should exist. |
|
I'm not sure |
|
I'm inclined to merge this, if you could give it a rebase pls, Eugene. |
Ref scala/bug#11551 Ref https://twitter.com/not_xuwei_k/status/1135374786593468416 This extends sensible check to `equals`, to warn against using it as opposed to `==`.
1d6121b to
ec80eb4
Compare
|
Rebased against 2.13.x. |
Would I be able to blanket-ignore all such warnings in the entire codebase, without adding any |
|
@sjrd yes. at the very least by doing Edit: |
| val actual = underlyingClass(other.tpe) | ||
| def typesString = normalizeAll(qual.tpe.widen)+" and "+normalizeAll(other.tpe.widen) | ||
| def nonSensiblyEquals() = { | ||
| reporter.warning(pos, s"comparing values of types $typesString using `${name.decode}` is unsafe due to cooperative equality; use `==` instead") |
There was a problem hiding this comment.
This should call refchecksWarning, going directly do reporter.warning bypasses the Wconf infrastructure. Any takers?
➜ sandbox git:(2.13.x) qs '-Wconf:msg=statement:e,msg=equality:e'
Welcome to Scala 2.13.4-20201009-113655-8fbebaa (Java HotSpot(TM) 64-Bit GraalVM EE 19.2.1, Java 1.8.0_231).
Type in expressions for evaluation. Or try :help.
scala> def f = { 1; 2 }
^
error: a pure expression does nothing in statement position; multiline expressions might require enclosing parentheses
scala> def g = 1L equals 1
^
warning: comparing values of types Long and Int using `equals` is unsafe due to cooperative equality; use `==` instead
def g: Boolean
There was a problem hiding this comment.
I just noticed this myself, trying to fix up the warning for #9235
There was a problem hiding this comment.
@lrytz if all it is is changing that one line, I'll take a stab
There was a problem hiding this comment.
Likely build/quick/bin/scala or perhaps $(git root 2>/dev/null)/build/quick/bin/scala
There was a problem hiding this comment.
$(git root 2>/dev/null)/build/quick/bin/scala
If only I was that smart. Though git root doesn't seem to be a built-in. Adopted, thank you.
equals comparing non-references
|
PR adjusting the wording a bit: #9320 |
Sorry to dig up an old PR, but where can I find documentation for the I'm trying to find the earliest version of Scala that supports it. |
|
@nchammas re: version, I think you would need to go digging (either in the source code, or just by trying the different versions) to determine that. |
|
and we don't have fine-grained documentation covering individual warning categories. the usual best available source of information, besides the source code, is the PR description of the PR that added that warning in the first place. (usually such PRs are linked from the Scala release notes.) |
### What changes were proposed in this pull request? This is a backport of fcc5dbc / #45036 with a tweak so that it works on Scala 2.12. ### Why are the changes needed? This is a correctness bug fix. The original fix against `master` suppresses a warning category that doesn't exist on certain versions of Scala 2.13 and 2.12, and the exact versions are [not documented anywhere][1]. To be safe, this backport simply suppresses all warnings instead of just `other-non-cooperative-equals`. It would be interesting to see if `-Wconf:nowarn` complains, since the warning about non-cooperative equals itself is also not thrown on all versions of Scala, but I don't think that's a priority. [1]: scala/scala#8120 (comment) ### Does this PR introduce _any_ user-facing change? Yes. ### How was this patch tested? CI + added tests. ### Was this patch authored or co-authored using generative AI tooling? No. Closes #45296 from nchammas/SPARK-45599-OpenHashSet. Authored-by: Nicholas Chammas <nicholas.chammas@gmail.com> Signed-off-by: Dongjoon Hyun <dhyun@apple.com>
Ref scala/bug#11551
Ref https://twitter.com/not_xuwei_k/status/1135374786593468416
Scala 2.13.1 or Dotty allows you to write the following expression:
or generically as:
problem
This looks seemingly innocuous but it's actually not "safe" because of cooperative equality.
what this changes
This PR extends "sensible check" to
equals, to warn against using it as opposed to==:/cc @xuwei-k