Which concrete implementation is returned from functions like mutableMapOf, mapOf, setOf, listOf function?

I was reading the documentation
https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/mutable-map-of.html
and some others like setOf, listOf ...Of which creates instances of collections.

Q1.
A question came up, since in the documentation it’s written

fun <K, V> mutableMapOf(): MutableMap<K, V>

Returns an empty new MutableMap.

where MutableMap is an interface,
and it isn’t stated which concrete implementation of it is returned by default.

After a while of searching,
https://kotlinlang.org/docs/reference/collections-overview.html
here the default implementations seem to be stated.
Is there a reason why this is not stated directly in the API’s documentation?

Q2. This is a following question
When using these standard library functions, how could one change this default implementation and return some other implementations of the interfaces instead?
e.g.
when using mapof(), how could I change the behavior such that it returns an HashMap instead of the default implementation LinkedHashMap?

P.S.
Is this also a right way to inspect the concrete implementation? Please correct me if I’m wrong

val map = mutableMapOf<Int, Any?>()
println(map::class.qualifiedName)

Q2 You can’t. All you can do is simply provide your own functions or just call a constructor directly.

Yes and no. If you try to find the implementation during runtime it’s probably the best way. If you just want to figure this out during programming a better solution would be to just download the sources of the standard library and click yourself thorugh the definitions using an IDE.
In my experience the stdlib is extremely well written and you learn a few tricks by reading through it. Also it often saves you going through the documentation in a separate window, eg finding out what implementation is returned by mapfOf just needs to you use “Go to Definition” on it and you find out that it’s a LinkedHasMap.

1 Like

The documentation deliberately avoids specifying the concrete implementation, and for good reasons:

First, because it’s better style to refer only to the interface, where possible. That avoids cluttering your code with unnecessary details, and makes it more flexible, allowing you to change the implementation classes without rewriting everything.

But, more importantly, because it allows them to change the stdlib to return different implementations in future. Some stdlib functions can already return specialised implementations in the case of zero or one element; there’s plenty of scope for more specialised implementations which improve performance, or have true immutability, or reduce memory use, or have other benefits — benefits which wouldn’t be possible if those functions specified the exact implementation class.

So your code should not rely on a particular implementation being returned (unless it’s in the public signature); even if your assumptions are correct now, they may not be in future versions.

And your code shouldn’t refer to concrete implementations without good reason. In general, you shouldn’t need to know what concrete classes those functions return. Or if you do need a particular implementation, then create one explicitly. If, for example, you need a Map with a consistent iteration order, then create a LinkedHashMap directly (and explain why you’re doing so). But in the majority of cases, where you don’t have that need, just trust the stdlib!

5 Likes

Fully agree with all the points. However I think it’s still safe to assume that the implementations returned by those factory functions won’t loose features, eg. it would take an immensly faster map implementation to change it to a map that no longer has a consistent iteration order.
While you shouldn’t make assumptions about the features that aren’t stated in the public signature from a language design point you don’t want to break those assumptions without good reason.