There is a typo in the flag, should be:
-language:experimental.strictEqualityPatternMatching (with a dot)
below are the number of compiler errors for two of the submodules in a project I work with
| submodule |
LOC |
strict equality |
pattern matching |
errors without flag after fixing errors with flag |
| R |
3000 |
45 |
34 |
0 |
| A |
3700 |
124 |
26 |
7 |
Types of errors that still remain after the pattern matching flag:
def empty: A
extension (value: A) def isEmpty: Boolean = value == empty
Values of types A and A cannot be compared with == or != [25:47]
val btm = bottoms.productElement(i)
if btm == null
Values of types Any and Null cannot be compared with == or !=
enum Permission:
case ALLOW
case PARTIAL
if permission == ALLOW
Values of types rdts.filters.Permission and rdts.filters.Permission cannot be compared with == or !=
(transaction: A) match
case Some =>
Values of types object Some and A cannot be compared with == or !=
(This code is just WTF and an actual bug found by strict equals)
.find(_.proposal == p)
Values of types rdts.protocols.old.simplified.ProposalNum and rdts.protocols.old.simplified.ProposalNum cannot be compared with == or !=
Is strict equality supposed to prevent == between non-generic instances of the same case class? The ProposalNum case class does have a parameter with a CanEquals instance.
if observer != null then
Values of types (reactives.core.Tracing.Data => Unit) | Null and Null cannot be compared with == or !=
tree.asExpr match
case '{ (${ x }: MacroAccess[?]).value }
No given instance of type scala.quoted.Quotes was found.
I found:
MacroLego.this.quotes
But given instance quotes in class MacroLego does not match type scala.quoted.Quotes.
(MacroLego.this.quotes is explicitly typed as scala.quoted.Quotes)
sealed private trait Result[+R]
private object Await extends Result[Nothing]
res match {
case Await =>
Values of types object reactives.locking.Keychains.Retry and reactives.locking.Keychains.Result[reactives.locking.Key[ParRPInterTurn]] cannot be compared with == or !=
I guess the change only works for enums, not sealed hierarchies?
current != Symbol.noSymbol && current != defn.RootPackage && current != defn.RootClass
Values of types quotes.reflect.Symbol and quotes.reflect.Symbol cannot be compared with == or !=
I guess this is more of the “these are the same type” but now in the standard library.
I then went ahead and fixed/worked around the above problems in subproject A by adding CanEquals either to algebraic datatypes, or just importing reflexive CanEquals for local types. This left me with 7 errors that are addressed by strictEqualityPatternMatching.
Fixing those required adding 3 more “derives CanEqual” to some ADT definitions.
So for this project, I think that the primary issue is that it prevents comparisons of values that have the exact same static type as far as I can tell.
The strictEqualityPatternMatching seems to prevent these errors for pattern matching, but any use of == instead of pattern matching (which we do use for all but 3 relevant types) requires the CanEquals instance anyway, and then the added value of the flag is lost.
Addendum. I now also fixed the remaining errors in subproject R. Those were also all either A | Null == Null or comparing two things that have the exact same type (particularly annoying for those in the scala.reflect.Quotes API). And adding the CanEquals instances where possible did also address all additional errors prevented by strictEqualityPatternMatching.
Overall, strict equality still seems half baked, the pattern matching changes feels like it improves usability, for one case. But I would really need most of the cases addressed for strict equality to feel like its worth it.