You cannot rely on the type of collection that will be returned by the map operations. If you need a mutable map, replace toMap() with toMutableMap(). Note that this will return a copy.
Okay, maybe this is clearer: You cannot rely on the actual type that is being returned. The only thing that is guaranteed to work is the declared return type of the function.
The reason you may get different implementations as the final result, is because your start situation is different: an empty map versus a map with at least 1 element.
Yes, I talk about how it actually works, because it was designed to work this way. So, it is not possible to make random changes to the design because it does not fit your particular scenario. In this case, the design choice was to let the collection operators always return immutable collections.
Why is operating on immutable collections a good thing? Because the operators can then return optimized implementations of the collections, and these optimized collections may have very specific implementations for the operators that get called upon them. This (can) result in more efficient code in terms of memory and/or speed.
It is something you will have to live with. If you want to do it more efficiently, or you are forced to work with types that the standard functions do not return, you can either do it inefficiently by creating copies or you write code to do it in the way that you need.
For example, this is efficient and works with HashMap:
val sourceMap = HashMap<String, String>()
// Do whatever you want here: Leave it empty, fill it to the brim, etc.
val destinationMap = HashMap<String, SomeObject>()
sourceMap.keys.forEach { key ->
destinationMap.put(key, doSomeWorkReturningSomeObjectToAssociateWith(key))
}
If the function signature of toMap() states it will return a Map, you cannot assume it will return a HashMap. You can only assume it will return a Map. As it happens, the current implementation sometimes returns a HashMap, but it’s wrong to rely on it.
If you need a MutableMap, you should use toMudatbleMap() instead. There is rarely a reason to depend on a particular implementation rather than on an interface.
But if you absolutely need it to be a HashMap, you can create one and then collect the values into it like this: .mapTo(HashMap<String, SomeObject>()) or mapValuesTo(HashMap<String, SomeObject>())`.
What you want coersion or automatic conversion. That is not part of the Kotlin language.
The reason why the program may want to return different types is because doing so may be more efficient in various ways. The whole point of the use of interfaces is that the using program cannot rely on the specific return type so the implementation can choose the best. Of course nothing stops you from creating your own toHashMap extension function that explicitly returns a hashmap.