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