bug icon indicating copy to clipboard operation
bug copied to clipboard

JavaConversions does not honour LinkedHashSet

Open scabug opened this issue 13 years ago • 8 comments

When using JavaConversions to convert from a java LinkedHashSet, the resulting Set is a scala mutable set. There is a scala version of LinkedHashSet, so I would've expected this to be created instead.

This can cause problems if you are expecting the order of the set to remain the same.

Example:

Welcome to Scala version 2.9.0.1 (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_26).
Type in expressions to have them evaluated.
Type :help for more information.

scala> import scala.collection.JavaConversions._
import scala.collection.JavaConversions._

scala> val j = new java.util.LinkedHashSet[String]()
j: java.util.LinkedHashSet[String] = []

scala> j.add("one")
res0: Boolean = true

scala> j.add("two")
res1: Boolean = true

scala> j.add("zebra")
res2: Boolean = true

scala> j.add("12345")
res3: Boolean = true

scala> val s=j.map(s=>s)
s: scala.collection.mutable.Set[String] = Set(zebra, 12345, one, two)

scala> j
res4: java.util.LinkedHashSet[String] = [one, two, zebra, 12345]

scala> s
res5: scala.collection.mutable.Set[String] = Set(zebra, 12345, one, two)

scabug avatar Jul 28 '11 00:07 scabug

Imported From: https://issues.scala-lang.org/browse/SI-4847?orig=1 Reporter: Raymond Barlow (raymanoz) Affected Versions: 2.9.0

scabug avatar Jul 28 '11 00:07 scabug

Channing Walton (channingwalton) said: The issue looks like its in the map operation. This iterates correctly: j.foreach(println _)

scabug avatar Jul 28 '11 21:07 scabug

@JamesIry said (edited on Jan 15, 2013 9:10:23 PM UTC): Also

scala> import scala.collection.JavaConverters._
import scala.collection.JavaConverters._

scala> j.asScala
res17: scala.collection.mutable.Set[String] = Set(one, two, zebra, 12345)

scala> j.asScala map identity
res18: scala.collection.mutable.Set[String] = Set(zebra, 12345, two, one)

scabug avatar Jan 15 '13 20:01 scabug

@JamesIry said: Ultimately it's related to that fact that the static type affects the behavior of map

scala> import scala.collection.mutable.{LinkedHashSet, Set}
import scala.collection.mutable.{LinkedHashSet, Set}

scala> val s1 = LinkedHashSet("one", "two", "zebra", "12345")
s1: scala.collection.mutable.LinkedHashSet[String] = Set(one, two, zebra, 12345)

scala> s1 map identity
res9: scala.collection.mutable.LinkedHashSet[String] = Set(one, two, zebra, 12345)

scala> (s1 : Set[String]) map identity
res10: scala.collection.mutable.Set[String] = Set(zebra, 12345, two, one)

Which means in order to fix this we would need a distinct static type when j.u.LinkedHashSet is converted. That kind of addition to the library wouldn't be forward compatible so per 2.10 policies I have to kick this down the road.

scabug avatar Jan 15 '13 22:01 scabug

Channing Walton (channingwalton) said: Thanks for looking into it James. Scala 2.11.0-M7? very precise!

scabug avatar Jan 15 '13 22:01 scabug

@Ichoran said: Leaf classes like LinkedHashSet are really not easy to mimic with a proxy; it requires a huge amount of boilerplate that gets out of date. So it's not really practical to go both ways since you'd have to override every method in the Java class and hope no new ones got added.

I'm also very skeptical of adding a conversion from Java in. You basically need to add another type to the type hierarchy that requests a LinkedHashSet builder so that when you map, you maintain types. I suppose one could add Java-specific builders, but that should be done comprehensively not as a one-off for this.

So I am not sure that this bug is a bug, or that it should be fixed.

scabug avatar Jan 14 '14 09:01 scabug

@Ichoran said: This might become feasible with built-in proxying in the standard library. Leaving the ticket open on backlog in case we get that. Otherwise, it's too fragile to be a good idea.

scabug avatar Feb 06 '14 21:02 scabug

A similar problem remains with the conversion performed by scala.jdk.CollectionConverters in Scala 2.13.

Because after conversion is mutable.Set, map is in the order returned by mutable.HashSet, which is the default implementation of mutable.Set.

In order to solve this problem, it is considered that the conversion corresponding to the Java collection class implementation should be individually defined(i.e. java.util.LinkedHashSet -> scala.collection.mutable.LinkedHashSet) or documented (the default implementation of the interface is applied).

magnolia-k avatar Aug 12 '19 01:08 magnolia-k