Very poor performance of immutable maps

mapOf is convenience method which does not have determined behavior. It means that the implementation could change in future and you should not use it for performance-sensitive code.

The complexity, say, for the hash map depends on the nature of keys you pass (number of hash conflicts).

Against complexity in the docs (yet): You document about the internals of the function, which means that you get breaking changes a lot faster.
Pro performance-improvement by using ImmutableMaps throughout the std, when they are stable.

That doesn’t make sense to me. Performance characteristics can be (non-functional) requirements, and therefore related properties of functions certainly have to documented. How else would you choose between HashSet and TreeMap?

To put it differently, I like to have it in the docs, but I also want them to decrease the complexity.
If the complexity is defined, a change to complexity means a breaking change, so I don’t like them to do it yet.
Does this make sense?

I understand your position, but I disagree. A breaking change is a breaking change, even if you didn’t write down the property. If you care about more than plausible deniability.

It does, but the documentation could have “at most … complexity” guarantees.

1 Like

@david.given: David, thank you very much ! Your post saved us a lot of time and energy. We had to re-design the data structures after reading this discussion.

The use case: there is a frequently changed map in a muti-threaded environment. There is a single component which updates the map and there are many components (threads) which get a copy when they need.
Apparantly this use case does not work with the standard Kotlin map.

Any suggestion is welcome !

(I agree that it must be explicitly mentioned in the docs because it confuses everyone having experience with functional languages)

If I understand well, other threads “make a copy” while a thread is updating the map, and this is not possible.

You can share an Immutable map in a @Volatile property.
Otherwise you can use a mutable map guarded by a ReadWriteLock.

No. There is an actor which reads messages from a channel and updates the immutable map. Users (in many threads) have a reference to the actor and just get the map.

So is a @Volatile property ok?

If the map is already immutable you do not need a Mutex.

Can you explain?

I am not sure it should be in this topic.
As far as I understand this topic, the standard Kotlin immutable map should not be updated (not values should not be added because the performance is not optimal).
This is very different from Erlang or Scala.
Which means that Kotlin enforces to use mutable maps if they are frequently changed and they are not small.

There is no standard kotlin immutable map unless you are using library @fvasco linked which is still in alpha stage. Kotlin only has readonly maps/lists/etc. There is no guarantee that they are immutable. Therefor the plus operator needs to create a copy.
You basically have 2 options. Either you can use MutableMap and design your program that way or you will need to use a library that provides real immutable maps.
Using a readonly map as if it’s immutable can’t give you the performance of a real immutable map.

1 Like

As we appear to have lost context and it’s easy to talk past each other: many languages have modifiable immutable/persistent data structures, where modifying the structure returns a pointer to a new instance of the structure while old pointers remain valid (pointing at the old copy of the data). This is traditionally how functional languages handle things. Internally they’re implemented in a variety of ways but you can normally expect O(1) mutations. They’re also frequently (but not always, it depends on the implementation) thread safe, which makes them incredibly useful because pointers can be shared between threads without needing to worry about read locks.

(Java people call these immutable data structures because of Guava’s ImmutableCollection API. Other languages frequently call these persistent. This is completely distinct from on-disk persistence. Names are hard.)

The problem here is that Kotlin looks like it’s got these, but the performance characteristics are very different to what people expect — as they’re backed by traditional non-immutable data structures, adding an item to a collection causes a complete new copy of the collection to be made, which is O(n). This is surprising.

I don’t think wer are totaly talking past each other. I understand your point and I know kotlin might look like it has persistent/immutable data structures, but as I and a few others here pointed out, the default data structures in kotlin aren’t immutable.
This is not perfectly communicated in the documentation and should be changed. But as mention above the kotlin team is working on providing a library for immutable data structures, so this is an issue that will hopefully be resolved in the future.

I understand that the new library’s coming (which is great, BTW) — mainly, as the topic seems to have come to life again, I was hoping to short circuit a repeat of the previous 50 messages in this already overlong thread!

1 Like

I guess this is another topic that should be closed :wink: @Alexey.Belkov?
If there are any new information it could be reopend or for any new questions probably a new topic.