Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Java wrappers need not be case classes #10104

Merged
merged 1 commit into from Aug 10, 2022

Conversation

som-snytt
Copy link
Contributor

@som-snytt som-snytt commented Aug 5, 2022

Inspired by scala/scala3#15764 (comment) to consider whether the wrapper classes ought to be case classes, as they have been since early days.

The hierarchy is complex (because collections).

ConcurrentMapWrapper overrode the underlying case class field in MutableMapWrapper, to narrow the result type. Now it provides underlyingConcurrentMap as a convenience.

Arguably, the pattern matches are easier to read.

It would be nice to backport universal apply and compile library with -Xsource:3.

Mima may disagree and require persuading.

@scala-jenkins scala-jenkins added this to the 2.13.10 milestone Aug 5, 2022
@som-snytt
Copy link
Contributor Author

Mima may disagree and require persuading.

[error]   - library/mimaReportBinaryIssues failed: java.lang.RuntimeException: Failed binary compatibility check against org.scala-lang:scala-library:2.13.8! Found 186 potential problems (filtered 7)

Only 186 issues. That includes all the junk case class synthetic methods. Maybe it's possible to quarantine the internal package.

@som-snytt som-snytt force-pushed the topic/decasify-converters branch 2 times, most recently from 685fe35 to 976bd56 Compare August 8, 2022 13:40
Copy link
Member

@lrytz lrytz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 (for the record, the changed classes are private[collection])

@lrytz lrytz merged commit f199a1f into scala:2.13.x Aug 10, 2022
@lrytz lrytz modified the milestones: 2.13.10, 2.13.9 Aug 10, 2022
@SethTisue SethTisue added internal not resulting in user-visible changes (build changes, tests, internal cleanups) library:collections PRs involving changes to the standard collection library labels Aug 10, 2022
@som-snytt som-snytt deleted the topic/decasify-converters branch August 10, 2022 17:21
@kasparito
Copy link

This change causes lots of problems in a large code base that I am working on. When scala.collection.convert.JavaCollectionWrappers.IterableWrapper was a case class, equals was defined as comparing the wrapped iterables. Now it is not:

scala> import scala.jdk.CollectionConverters.IterableHasAsJava
import scala.jdk.CollectionConverters.IterableHasAsJava

scala> Nil.asJavaCollection == Nil.asJavaCollection
val res0: Boolean = false

scala> Set("foo").asJavaCollection == Set("foo").asJavaCollection
val res1: Boolean = false

@SethTisue
Copy link
Member

@scala/collections wdyt? is this something we should consider reverting?

on the one hand, as a behavior change it seems like fair game for a minor version. (recall that Scala 2 versions are epoch.major.minor, not major.minor.patch

on the other hand, if the change isn't that high-value, then maybe the disruption isn't worth it

on the other other hand, it seems unlikely we'll be doing 2.13.11 in less than 3-4 months, at which point I'm not sure the possible disruption of changing it back is worth it — we might have felt differently if the report had come in during the brief 2.13.10 window

would anyone like to make a specific, evidence-supported argument that this wasn't a fair-game change...?

@SethTisue
Copy link
Member

note that https://docs.oracle.com/javase/8/docs/api/java/util/Collection.html#equals-java.lang.Object- says:

the simplest course of action is to rely on Object's implementation, but the implementor may wish to implement a "value comparison" in place of the default "reference comparison." (The List and Set interfaces mandate such value comparisons.)

@som-snytt
Copy link
Contributor Author

som-snytt commented Oct 31, 2022

@kasparito Sorry for the trouble. Universal methods FTW. "Nothing is internal API."

The motivation was unexpected member overrides in the internal classes; case classiness was taken as a convenience for construction. Reliance on equals and hashCode didn't come up.

Maybe hashCode not so much because of mutability.

I think the expectation that it just works is justified not unreasonable.

Also compare scala/bug#10663 where the asJava side has a contract that is not lax.

@som-snytt
Copy link
Contributor Author

I took a look, and it mostly just works. However, AbstractCollection doesn't do structural equality:

scala> def f = new java.util.AbstractCollection[Int] {
     | def size = 3; def iterator = Iterator(1,2,3).asJava }
def f: java.util.AbstractCollection[Int]

scala> f == f
val res0: Boolean = false

The other adapters extend the specific base classes which do implement the expected equals.

Probably it's harmless to remain compatible with the previous behavior for IterableWrapper.

I'll open a ticket to track the change.

@SethTisue
Copy link
Member

SethTisue commented Nov 4, 2022

resolved by #10205

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
internal not resulting in user-visible changes (build changes, tests, internal cleanups) library:collections PRs involving changes to the standard collection library
Projects
None yet
5 participants