scala / bug

Scala 2 bug reports only. Please, no questions — proper bug reports only.
https://scala-lang.org
232 stars 21 forks source link

JavaConversions does not honour LinkedHashSet #4847

Open scabug opened 13 years ago

scabug commented 13 years ago

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 commented 13 years ago

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

scabug commented 13 years ago

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

scabug commented 11 years ago

@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 commented 11 years ago

@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 commented 11 years ago

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

scabug commented 10 years ago

@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 commented 10 years ago

@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.

magnolia-k commented 5 years ago

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).