When you look into the API Documentation into the details of the map-Method you will find, that it has a second, implicit parameter of type CanBuildFrom
.
An instance of CanBuildFrom
from defines how a certain collection is build when mapping over some other collection and a certain element type is provided.
In the case where you get a Map as result, you are mapping over a Map and are providing binary tuples. So the compiler searches for a CanBuildFrom
-instance, that can handle that.
To find such an instance, the compiler looks in different places, e.g. the current scope, the class a method is invoked on and its companion object.
In this case it will find an implicit field called canBuildFrom
in the companion object of Map
that is suitable and can be used to build a Map
as result. So it tries to infer the result type to Map
and as this succeeds uses this instance.
In the case, where you provide single values or triples instead, the instance found in the companion of Map
does not have the required type, so it continues searching up the inheritance tree. It finds it in the companion object of Iterable
. The instance their allows to build an Iterable
of an arbitrary element type. So the compiler uses that.
So why do you get a List
? Because that happens to be the implementation used there, the type system only guarantees you an Iterable
.
If you want to get an Iterable
instead of a Map
you can provide a CanBuildFrom
instance explicitly (only if you call map and flatMap directly) or just force the return type. There you will also notice that you won't be able to request a List
even though you get one.
This wont work:
val l: List[Int] = Map(1->2).map(x=>3)
This however will:
val l: Iterable[Int] = Map(1->2).map(x=>3)