2

Given

val xs1 = Set(3, 2, 1, 4, 5, 6, 7)
val ys1 = Set(7, 2, 1, 4, 5, 6, 3)

xs1 and ys1 both result in scala.collection.immutable.Set[Int] = Set(5, 1, 6, 2, 7, 3, 4)

but smaller sets bellow

val xt1 = Set(1, 2, 3)
val yt1 = Set(3, 2, 1)

produce

xt1: scala.collection.immutable.Set[Int] = Set(1, 2, 3)
yt1: scala.collection.immutable.Set[Int] = Set(3, 2, 1)

Why are former not ordered whilst latter seem to be ordered?

Mario Galic
  • 47,285
  • 6
  • 56
  • 98
zhang-yuan
  • 418
  • 7
  • 18
  • 2
    **Set** is a trait, there are many implementations for it. Usually, for more than 4 o 5 elements you will get a `HashSet` but for 0 to 4 or 5 elements _(I really do not remember)_ there are optimized classes like `EmptySet`, `Set1`, etc. That is way they preserve the order, but that may change. Sets are not guarantee to preserve it _(but also are not guarantee to do not do it)_. – Luis Miguel Mejía Suárez Sep 14 '19 at 15:25

1 Answers1

5

Difference in behaviour is due to optimisations for Sets of up to 4 elements

The default implementation of an immutable set uses a representation that adapts to the number of elements of the set. An empty set is represented by just a singleton object. Sets of sizes up to four are represented by a single object that stores all elements as fields. Beyond that size, immutable sets are implemented as Compressed Hash-Array Mapped Prefix-tree.

similarly explained by Ben James:

Set is also a companion object* with an apply** method. When you call Set(...), you're calling this factory method and getting a return value which is some kind of Set. It might be a HashSet, but could be some other implementation. According to 2, the default implementation for an immutable set has special representation for empty set and sets size up to 4. Immutable sets size 5 and above and mutable sets all use hashSet.

Since size of Set(3, 2, 1, 4, 5, 6, 7) is greater than 4, then its concrete implementation is HashSet

Set(3, 2, 1, 4, 5, 6, 7).getClass
class scala.collection.immutable.HashSet

which does not guarantee insertion order. On the other hand, concrete implementation of Set(1, 2, 3) is dedicated class Set3

Set(1,2,3).getClass
class scala.collection.immutable.Set$Set3

which stores the three elements in corresponding three fields

final class Set3[A] private[collection] (elem1: A, elem2: A, elem3: A) extends AbstractSet[A] ...
Mario Galic
  • 47,285
  • 6
  • 56
  • 98