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

JConcurrentMapWrapper does not override default updateWith implementation #12586

Closed
igabaydulin opened this issue May 4, 2022 · 5 comments · Fixed by scala/scala#10027
Closed

Comments

@igabaydulin
Copy link

igabaydulin commented May 4, 2022

Reproduction steps

Scala version: 2.13.8

Java's ConcurrentMap#compute default implementation and Scala's concurrent.Map#updateWith default implementation have the same logic and the supplied function may be invoked multiple times in both cases.

Java's ConcurrentHashMap extends ConcurrentMap and overrides compute implementation. It gives improved performance and guarantees that supplied function is invoked only once.

We can wrap ConcurrentHashMap into concurrent.Map

{
  import scala.jdk.CollectionConverters._
  val map: concurrent.Map[String, Int] = new ConcurrentHashMap[String, Int]().asScala
}

It will create an instance of JConcurrentMapWrapper which extends concurrent.Map, but it does not override updateWith default implementation using compute method of wrapped ConcurrentHashMap. Implementing overridden updateWith should be quite simple:

override def updateWith(key: K)(remappingFunction: Option[V] => Option[V]): Option[V] =
  Option(underlying.compute(key, (_: K, v: V) => remappingFunction(Option(v)).getOrElse(null.asInstanceOf[V])))
@SethTisue
Copy link
Member

@scala/collections ?

@som-snytt
Copy link

The recent tweak says it is OK to add an override to the wrapper.

The suggested fix looks reasonable.

As with the recent tweak, the interface is so fat that it's difficult to correlate the delegated methods without a spreadsheet.

I'm not especially familiar with either side, but I would expect that if someone has to wrap their beloved Java Map asScala, they might know they want to use underlying.m so what must they invoke on the wrapper? I just took a few minutes to look, but it's not obvious that updateWith is the final loose end.

Possibly the delegate belongs on JMapWrapperLike, but I will desist now before 🤯 happens.

@som-snytt
Copy link

I pushed that PR.

@som-snytt
Copy link

som-snytt commented May 5, 2022

JMapWrapperLike was not correct for the concurrent mix-in, but it seems it should delegate for all wrapped maps. The other API that could be delegated is default value. (I just wanted to contribute the desired behavior requested here.)

@SethTisue SethTisue added this to the 2.13.9 milestone Jun 3, 2022
@SethTisue
Copy link
Member

(There is now some discussion on the PR (scala/scala#10027) about what the right fix is.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants