var set = TreeSet(5,4,3,2,1)
println(set)
val diffSet: TreeSet[Int] = set
// if I change above code to val diffSet: Set[Int] = set
// the result is
Set
does not guarantee ordering. Even if the underlying class is a TreeSet
, if the expected result is a Set
you'll loose the ordering in the first transformation you do.
If you want ordering, do not use Set
. I suggest, say, SortedSet
.
You can do:
scala> for (i <-genSet.view; x = i + 1) println(x)
2
3
4
5
6
Although, it's the type of trick that when you look at it after a few months, you may wonder why you added .view
...
map
version winds up unsortedThe map
method (called with a function that we'll call func
) takes an implicit CanBuildFrom
parameter that takes into account the type of the collection that map
is being called on, in addition to the type that func
returns to choose an appropriate return type. This is used to make Map.map[Int]
or BitSet.map[String]
do the right thing (return general purpose lists) while Map.map[(String,Int)]
or BitSet.map[Int]
also do the right thing (return a Map
and a BitSet
) respectively.
The CanBuildFrom
is chosen at compile time, so it must be chosen based on the static type of the set that you call map
on (the type the compiler knows about at compile time). The static type of set
is TreeSet
, but the static type of diffset
is Set
. The dynamic type of both (at runtime) is TreeSet
.
When you call map
on set
(a TreeSet
), the compiler chooses immutable.this.SortedSet.canBuildFrom[Int](math.this.Ordering.Int)
as the CanBuildFrom
.
When you call map
on diffset
(a Set
), the compiler chooses immutable.this.Set.canBuildFrom[Int]
as the CanBuildFrom
.
for
version winds up unsortedThe loop
for (i <- genSet; x = i + 1) {
println(x)
}
desugars into
genSet.map(((i) => {
val x = i.$plus(1);
scala.Tuple2(i, x)
})).foreach(((x$1) => x$1: @scala.unchecked match {
case scala.Tuple2((i @ _), (x @ _)) => println(x)
}))
The desugared version includes a map
function which will use the unsorted CanBuildFrom
as I explained above.
On the other hand, the loop
for (i <- genSet) {
val x = i + 1
println(x)
}
desugars into
genSet.foreach(((i) => {
val x = i.$plus(1);
println(x)
}))
Which doesn't use a CanBuildFrom
at all, since no new collection is being returned.
Change the sig of genSet
to return a SortedSet
def genSet:SortedSet[Int] = {
TreeSet(5, 4, 3, 2, 1)
}
This is probably some sort of bug. I would have expected your code to work too.
I think map
is the culprit. This results in the same behavior:
for (i <- genSet.map(_ + 1)) { println(i) }
And for(i <- genSet; x = i + 1)
equates to for(x <- genSet.map({i => i + 1}))