Skip to content
Kotlin Multiplatform State Library
Branch: master
Clone or download
Latest commit 2fd4a84 May 15, 2019
Type Name Latest commit message Commit time
Failed to load latest commit information.
.idea Object pool Feb 24, 2019
DummyIos Updated tests Oct 22, 2018
Sample Reformat Feb 13, 2019
gradle Merge Windows May 15, 2019
memtest Object pool Feb 24, 2019
stately Merge Windows May 15, 2019
LICENSE.txt Apply copyright and license Oct 24, 2018 Added clear methods and memory leak tests Feb 15, 2019
build.gradle Added clear methods and memory leak tests Feb 15, 2019 Merge Windows May 15, 2019
gradlew import Oct 11, 2018
gradlew.bat import Oct 11, 2018 Fixed bug adding first entry in linked list with Node Nov 25, 2018
settings.gradle Added clear methods and memory leak tests Feb 15, 2019


Stately is a state utility library to facilitate the Native side of Kotlin Multiplatform.

The library consists of some useful expect/actual definitions, as well as a set of multithreaded collection classes that will allow multithreaded mutation in Kotlin/Native.

Kotlin/Native has a fairly different model of concurrency than what JVM developers are used to. This includes very different rules around sharing state. These rules are intended to reduce the likelihood of concurrency related issues.

One of the rules is that shared state is immutable. While generally a good idea, some shared state mutability is also pretty useful. Kotlin/Native provides a set of Atomics to allow for some state to be changed in a safe way. Stately provides a set of collection classes that use Atomics under the hood to function, as well as some multiplatform definitions to make using Atomics and Kotlin/Native related state management simpler.

The documentation here is about the structure, or the what of the library. A follow on blog post will talk a bit more about the why.


Build status

This a pretty early version. Expect changes in the near future.


Kotlin/Native provides some annotations to support state characteristics. These do not have common kotlin analogs, which makes multiplatform code somewhat more difficult to define. Stately defines expect/actual parallels which have no impact on JVM or JS.


Place on top level var or object to make it available as thread local. See ThreadLocal.


Top level var will default to main thread only. To share it as an immutable, add this annotation. See SharedImmutable.



Multiplatform definition for Kotlin/Native 'freeze'.


Call on any object to find out if it's frozen.


Will return true on non-native platforms. On native, will return true if frozen. Usually you're trying to figure out if an instance can be shared among threads. Because the rules are different, the answer is always "true" on JVM and JS. This method makes that logic simpler.

isNative (val)

Simple way to find out if we're in a native context.


Converts an Iterator to a List. This is an extension function that works on any Iterator. Mostly useful for testing.


Important note for all collections!!!

AtomicReference can leak memory in Kotlin Native. To avoid leaking memory, you should call clear() on any collection when done using it.

Copy On Write List

A MutableList that updates a stable copy on each edit. When you get an iterator, that iterator remains stable regardless of operations happening on the list. The JVM version is actually The Native version updates a frozen ArrayList internally by copying and replacing on edits.

val list:MutableList<SampleData> = frozenCopyOnWriteList<SampleData>()

Shared Linked List

Rather than copying the full list on each edit, this structure uses atomic references in the nodes to allow modification that is reasonably performant relative to the Copy On Write list in situations that may have larger lists and/or frequent updates.

It's important to note, performance is OK relative to copying the list on each edit. The list locks aggressively to achieve consistency. There are lockless algorithms for linked lists that may be explored in the future.

There are two versions.


Iterators reflect changes to the underlying list. If values are added/removed while iterating, your iterator will see them.

val list:MutableList<SampleData> = frozenLinkedList<SampleData>()


Iterators are stable. Calling iterator creates an internal copy of the list which the iterator uses. Underlying changes to the source list are NOT reflected in the iterator. This will trigger a lock and copy on calling iterator, which may be a performance consideration with large lists.

Similar to CopyOnWriteList, and likely to perform better in general cases. It is a linked list, however, so indexed access requires a scan.

val list:MutableList<SampleData> = frozenLinkedList<SampleData>(stableIterator = true)

Hash Map

A standard hash map architected as a simple Java-like implementation. Optionally pass in initial capacity and load factor. Will grow as needed. This also locks on most operations, so from a performance perspective I would expect it to fall pretty far behind the standard single threaded implementation, but from an order of operations perspective, it should be similar.

One note. In Java 8 (not sure about kotlin native), in buckets, after length 8, a tree is used instead of a linked list. Worst case performance then flattens out to lgN (ish). Java 7, and our implementation, do not, so expect worst case to be N. Try to use good hashes.

val sharedMap:MutableMap<String, SampleData> = frozenHashMap<String, SampleData>()

LRU Cache

Hash map and linked list combined into an LRU cache implementation.

You can supply a callback to be notified when an entry is removed.

val lruRemovedCount = AtomicInt(0)
val lruCache = frozenLruCache<String, SampleData>(5) {

Note that the lambda for onRemove is optional. However, since it is multithreaded, be aware that anything in there will be frozen.


See the Sample App for usage.


Copyright 2018 Touchlab, Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
See the License for the specific language governing permissions and
limitations under the License.
You can’t perform that action at this time.