Repository: arkivanov/Decompose
Pull request #184 (2022-08-22 08:32:22)

Update compose-darwin branch


Patch:
diff --git a/decompose/src/commonMain/kotlin/com/arkivanov/decompose/Utils.kt b/decompose/src/commonMain/kotlin/com/arkivanov/decompose/Utils.kt
index 9777ce5d..cea8012f 100644
--- a/decompose/src/commonMain/kotlin/com/arkivanov/decompose/Utils.kt
+++ b/decompose/src/commonMain/kotlin/com/arkivanov/decompose/Utils.kt
@@ -1,5 +1,3 @@
 package com.arkivanov.decompose
 
 internal expect fun Any.ensureNeverFrozen()
-
-internal fun Collection<Any?>.isUnique(): Boolean = toSet().size == size
diff --git a/decompose/src/commonMain/kotlin/com/arkivanov/decompose/router/stack/StackControllerImpl.kt b/decompose/src/commonMain/kotlin/com/arkivanov/decompose/router/stack/StackControllerImpl.kt
index 351c9bc7..65577adb 100644
--- a/decompose/src/commonMain/kotlin/com/arkivanov/decompose/router/stack/StackControllerImpl.kt
+++ b/decompose/src/commonMain/kotlin/com/arkivanov/decompose/router/stack/StackControllerImpl.kt
@@ -1,6 +1,5 @@
 package com.arkivanov.decompose.router.stack
 
-import com.arkivanov.decompose.isUnique
 import com.arkivanov.essenty.lifecycle.destroy
 import com.arkivanov.essenty.lifecycle.pause
 import com.arkivanov.essenty.lifecycle.resume
@@ -17,20 +16,24 @@ internal class StackControllerImpl<C : Any, T : Any>(
         val oldConfigurationStack = oldStack.configurationStack
         val newConfigurationStack = transformer(oldConfigurationStack)
 
-        if (newConfigurationStack === oldConfigurationStack) {
+        if (newConfigurationStack == oldConfigurationStack) {
             return oldStack
         }
 
         check(newConfigurationStack.isNotEmpty()) { "Configuration stack can not be empty" }
-        check(newConfigurationStack.isUnique()) { "Configurations in the stack must be unique" }
+
+        val newConfigurationStackSet = newConfigurationStack.toSet()
+        check(newConfigurationStackSet.size == newConfigurationStack.size) { "Configurations in the stack must be unique" }
+
+        val oldBackStackMap = oldStack.backStack.associateBy { it.configuration }
 
         val newActiveConfiguration = newConfigurationStack.last()
         val newActiveEntry: RouterEntry.Created<C, *>
-        if (newActiveConfiguration === oldStack.active.configuration) {
+        if (newActiveConfiguration == oldStack.active.configuration) {
             newActiveEntry = oldStack.active
         } else {
             newActiveEntry =
-                when (val entry = oldStack.backStack.find { it.configuration === newActiveConfiguration }) {
+                when (val entry = oldStack.backStack.find { it.configuration == newActiveConfiguration }) {
                     is RouterEntry.Created -> entry.copy(savedState = null)
                     is RouterEntry.Destroyed -> routerEntryFactory(entry.configuration, entry.savedState)
                     null -> routerEntryFactory(newActiveConfiguration)
@@ -41,7 +44,7 @@ internal class StackControllerImpl<C : Any, T : Any>(
             oldStack.active.lifecycleRegistry.pause()
             newActiveEntry.lifecycleRegistry.resume()
             oldStack.active.lifecycleRegistry.stop()
-            if (newConfigurationStack.none { it === oldStack.active.configuration }) {
+            if (oldStack.active.configuration !in newConfigurationStackSet) {
                 oldStack.active.instanceKeeperDispatcher.destroy()
                 oldStack.active.lifecycleRegistry.destroy()
             }
@@ -49,19 +52,16 @@ internal class StackControllerImpl<C : Any, T : Any>(
 
         val newBackStackEntries =
             newConfigurationStack.dropLast(1).map { configuration ->
-                if (oldStack.active.configuration === configuration) {
+                if (oldStack.active.configuration == configuration) {
                     oldStack.active.copy(savedState = oldStack.active.stateKeeperDispatcher.save())
                 } else {
-                    oldStack
-                        .backStack
-                        .find { it.configuration === configuration }
-                        ?: RouterEntry.Destroyed(configuration = configuration)
+                    oldBackStackMap[configuration] ?: RouterEntry.Destroyed(configuration = configuration)
                 }
             }
 
         oldStack
             .backStack
-            .filter { entry -> newConfigurationStack.none { it === entry.configuration } }
+            .filterNot { it.configuration in newConfigurationStackSet }
             .destroy()
 
         return RouterStack(active = newActiveEntry, backStack = newBackStackEntries)
diff --git a/decompose/src/commonMain/kotlin/com/arkivanov/decompose/router/stack/StackHolderImpl.kt b/decompose/src/commonMain/kotlin/com/arkivanov/decompose/router/stack/StackHolderImpl.kt
index 4453e47d..e02acb2b 100644
--- a/decompose/src/commonMain/kotlin/com/arkivanov/decompose/router/stack/StackHolderImpl.kt
+++ b/decompose/src/commonMain/kotlin/com/arkivanov/decompose/router/stack/StackHolderImpl.kt
@@ -1,6 +1,5 @@
 package com.arkivanov.decompose.router.stack
 
-import com.arkivanov.decompose.isUnique
 import com.arkivanov.essenty.instancekeeper.InstanceKeeper
 import com.arkivanov.essenty.instancekeeper.InstanceKeeperDispatcher
 import com.arkivanov.essenty.instancekeeper.getOrCreate
@@ -47,7 +46,7 @@ internal class StackHolderImpl<C : Any, T : Any>(
         val initialStack = initialStack()
 
         check(initialStack.isNotEmpty()) { "Initial stack can not be empty" }
-        check(initialStack.isUnique()) { "Configurations in the initial stack must be unique" }
+        check(initialStack.toSet().size == initialStack.size) { "Configurations in the initial stack must be unique" }
 
         return RouterStack(
             active = routerEntryFactory(initialStack.last()),
diff --git a/deps.versions.toml b/deps.versions.toml
index dcb2f600..1157531d 100644
--- a/deps.versions.toml
+++ b/deps.versions.toml
@@ -1,6 +1,6 @@
 [versions]
 
-decompose = "1.0.0-alpha-01-native-compose"
+decompose = "1.0.0-alpha-03-native-compose"
 kotlin = "1.7.0"
 essenty = "0.5.2"
 reaktive = "1.2.1"
diff --git a/docs/extensions/compose.md b/docs/extensions/compose.md
index 30fae4cd..c4116c4c 100644
--- a/docs/extensions/compose.md
+++ b/docs/extensions/compose.md
@@ -285,3 +285,24 @@ fun someAnimator(): StackAnimator =
 ```
 
 Please refer to the predefined animators (`fade`, `slide`, etc.) for implementation examples.
+
+## Compose for iOS and macOS
+
+Compose for iOS and macOS is still work in progress and was not oficially announced. However, Decompose already supports it. The support is also experimental and is not part of the main branch - see [#74](https://github.com/arkivanov/Decompose/issues/74) for more information.
+
+If you want to use Decompose with Compose for iOS/macOS, you have to use special versions of `extensions-compose-jetbrains` module.
+
+=== "Groovy"
+
+    ``` groovy
+    implementation "com.arkivanov.decompose:extensions-compose-jetbrains:<version>-native-compose"
+    ```
+
+=== "Kotlin"
+
+    ``` kotlin
+    implementation("com.arkivanov.decompose:extensions-compose-jetbrains:<version>-native-compose")
+
+### Samples
+
+You can find samples in a separate branch - [compose-darwin/sample/app-darwin-compose](https://github.com/arkivanov/Decompose/tree/compose-darwin/sample/app-darwin-compose).


Test patch:
diff --git a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/stack/StackControllerTest.kt b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/stack/StackControllerTest.kt
index 89be50e5..fcc6875e 100644
--- a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/stack/StackControllerTest.kt
+++ b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/stack/StackControllerTest.kt
@@ -27,23 +27,23 @@ class StackControllerTest {
 
     @Test
     fun GIVEN_empty_back_stack_WHEN_push_THEN_active_entry_is_new() {
-        val newConfig = Config()
+        val newConfig = Config(id = 2)
 
         val newStack =
             controller.navigate(
                 oldStack = RouterStack(
-                    active = activeEntry(configuration = Config()),
+                    active = activeEntry(configuration = Config(id = 1)),
                     backStack = emptyList()
                 ),
                 transformer = { it + newConfig }
             )
 
-        assertSame(newConfig, newStack.active.configuration)
+        assertEquals(newConfig, newStack.active.configuration)
     }
 
     @Test
     fun GIVEN_empty_back_stack_WHEN_push_THEN_back_stack_equals_old() {
-        val oldConfig = Config()
+        val oldConfig = Config(id = 1)
 
         val newStack =
             controller.navigate(
@@ -51,7 +51,7 @@ class StackControllerTest {
                     active = activeEntry(configuration = oldConfig),
                     backStack = emptyList()
                 ),
-                transformer = { it + Config() }
+                transformer = { it + Config(id = 2) }
             )
 
         assertEquals(listOf(oldConfig), newStack.configurationBackStack)
@@ -59,9 +59,9 @@ class StackControllerTest {
 
     @Test
     fun GIVEN_not_empty_back_stack_WHEN_push_THEN_back_stack_equals_old_back_stack_plus_old_active() {
-        val oldConfig1 = Config()
-        val oldConfig2 = Config()
-        val oldConfig3 = Config()
+        val oldConfig1 = Config(id = 1)
+        val oldConfig2 = Config(id = 2)
+        val oldConfig3 = Config(id = 3)
 
         val newStack =
             controller.navigate(
@@ -69,7 +69,7 @@ class StackControllerTest {
                     active = activeEntry(configuration = oldConfig3),
                     backStack = listOf(createdEntry(configuration = oldConfig1), createdEntry(configuration = oldConfig2))
                 ),
-                transformer = { it + Config() }
+                transformer = { it + Config(id = 4) }
             )
 
         assertEquals(listOf(oldConfig1, oldConfig2, oldConfig3), newStack.configurationBackStack)
@@ -79,11 +79,11 @@ class StackControllerTest {
     fun GIVEN_empty_back_stack_WHEN_push_THEN_old_component_not_recreated() {
         val oldStack =
             RouterStack(
-                active = activeEntry(configuration = Config()),
+                active = activeEntry(configuration = Config(id = 1)),
                 backStack = emptyList()
             )
 
-        val newStack = controller.navigate(oldStack = oldStack, transformer = { it + Config() })
+        val newStack = controller.navigate(oldStack = oldStack, transformer = { it + Config(id = 2) })
 
         assertSame(newStack.backStack[0].asCreated().instance, oldStack.active.instance)
     }
@@ -92,11 +92,11 @@ class StackControllerTest {
     fun GIVEN_not_empty_back_stack_WHEN_push_THEN_old_components_not_recreated() {
         val oldStack =
             RouterStack(
-                active = activeEntry(configuration = Config()),
-                backStack = listOf(createdEntry(configuration = Config()), createdEntry(configuration = Config()))
+                active = activeEntry(configuration = Config(id = 3)),
+                backStack = listOf(createdEntry(configuration = Config(id = 1)), createdEntry(configuration = Config(id = 2)))
             )
 
-        val newStack = controller.navigate(oldStack = oldStack, transformer = { it + Config() })
+        val newStack = controller.navigate(oldStack = oldStack, transformer = { it + Config(id = 4) })
 
         assertSame(oldStack.backStack[0].asCreated().instance, newStack.backStack[0].asCreated().instance)
         assertSame(oldStack.backStack[1].asCreated().instance, newStack.backStack[1].asCreated().instance)
@@ -110,10 +110,10 @@ class StackControllerTest {
         val newStack =
             controller.navigate(
                 oldStack = RouterStack(
-                    active = activeEntry(configuration = Config(), stateKeeperDispatcher = stateKeeperDispatcher),
+                    active = activeEntry(configuration = Config(id = 1), stateKeeperDispatcher = stateKeeperDispatcher),
                     backStack = emptyList()
                 ),
-                transformer = { it + Config() }
+                transformer = { it + Config(id = 2) }
             )
 
         assertNotNull(stateKeeperDispatcher.lastSavedState)
@@ -125,10 +125,10 @@ class StackControllerTest {
         val newStack =
             controller.navigate(
                 oldStack = RouterStack(
-                    active = activeEntry(configuration = Config()),
+                    active = activeEntry(configuration = Config(id = 1)),
                     backStack = emptyList()
                 ),
-                transformer = { it + Config() }
+                transformer = { it + Config(id = 2) }
             )
 
         assertSame(Lifecycle.State.RESUMED, newStack.active.lifecycleRegistry.state)
@@ -139,10 +139,10 @@ class StackControllerTest {
         val newStack =
             controller.navigate(
                 oldStack = RouterStack(
-                    active = activeEntry(configuration = Config()),
+                    active = activeEntry(configuration = Config(id = 1)),
                     backStack = emptyList()
                 ),
-                transformer = { it + Config() }
+                transformer = { it + Config(id = 2) }
             )
 
         assertTrue(newStack.active.backHandler.asTest().isStarted)
@@ -153,10 +153,10 @@ class StackControllerTest {
         val newStack =
             controller.navigate(
                 oldStack = RouterStack(
-                    active = activeEntry(configuration = Config()),
+                    active = activeEntry(configuration = Config(id = 1)),
                     backStack = emptyList()
                 ),
-                transformer = { it + Config() }
+                transformer = { it + Config(id = 2) }
             )
 
         assertSame(Lifecycle.State.CREATED, newStack.backStack.first().asCreated().lifecycleRegistry.state)
@@ -167,10 +167,10 @@ class StackControllerTest {
         val newStack =
             controller.navigate(
                 oldStack = RouterStack(
-                    active = activeEntry(configuration = Config()),
+                    active = activeEntry(configuration = Config(id = 1)),
                     backStack = emptyList()
                 ),
-                transformer = { it + Config() }
+                transformer = { it + Config(id = 2) }
             )
 
         assertFalse(newStack.backStack.first().asCreated().backHandler.asTest().isStarted)
@@ -181,30 +181,29 @@ class StackControllerTest {
         val newStack =
             controller.navigate(
                 oldStack = RouterStack(
-                    active = activeEntry(configuration = Config()),
+                    active = activeEntry(configuration = Config(id = 1)),
                     backStack = emptyList()
                 ),
-                transformer = { it + Config() }
+                transformer = { it + Config(id = 2) }
             )
 
-        newStack.backStack
         assertSame(Lifecycle.State.CREATED, (newStack.backStack[0] as RouterEntry.Created).lifecycleRegistry.state)
     }
 
     @Test
     fun GIVEN_back_stack_WHEN_pop_THEN_active_entry_is_back() {
-        val backConfig = Config()
+        val backConfig = Config(id = 1)
 
         val newStack =
             controller.navigate(
                 oldStack = RouterStack(
-                    active = activeEntry(configuration = Config()),
+                    active = activeEntry(configuration = Config(id = 2)),
                     backStack = listOf(createdEntry(configuration = backConfig))
                 ),
                 transformer = { it.dropLast(1) }
             )
 
-        assertSame(backConfig, newStack.active.configuration)
+        assertEquals(backConfig, newStack.active.configuration)
     }
 
     @Test
@@ -212,8 +211,8 @@ class StackControllerTest {
         val newStack =
             controller.navigate(
                 oldStack = RouterStack(
-                    active = activeEntry(configuration = Config()),
-                    backStack = listOf(createdEntry(configuration = Config()))
+                    active = activeEntry(configuration = Config(id = 2)),
+                    backStack = listOf(createdEntry(configuration = Config(id = 1)))
                 ),
                 transformer = { it.dropLast(1) }
             )
@@ -227,8 +226,8 @@ class StackControllerTest {
 
         controller.navigate(
             oldStack = RouterStack(
-                active = activeEntry(configuration = Config(), lifecycleRegistry = lifecycleRegistry),
-                backStack = listOf(createdEntry(configuration = Config()))
+                active = activeEntry(configuration = Config(id = 2), lifecycleRegistry = lifecycleRegistry),
+                backStack = listOf(createdEntry(configuration = Config(id = 1)))
             ),
             transformer = { it.dropLast(1) }
         )
@@ -244,8 +243,8 @@ class StackControllerTest {
 
         controller.navigate(
             oldStack = RouterStack(
-                active = activeEntry(configuration = Config(), instanceKeeperDispatcher = instanceKeeperDispatcher),
-                backStack = listOf(createdEntry(configuration = Config()))
+                active = activeEntry(configuration = Config(id = 2), instanceKeeperDispatcher = instanceKeeperDispatcher),
+                backStack = listOf(createdEntry(configuration = Config(id = 1)))
             ),
             transformer = { it.dropLast(1) }
         )
@@ -258,8 +257,8 @@ class StackControllerTest {
         val newStack =
             controller.navigate(
                 oldStack = RouterStack(
-                    active = activeEntry(configuration = Config()),
-                    backStack = listOf(createdEntry(configuration = Config()))
+                    active = activeEntry(configuration = Config(id = 2)),
+                    backStack = listOf(createdEntry(configuration = Config(id = 1)))
                 ),
                 transformer = { it.dropLast(1) }
             )
@@ -271,8 +270,8 @@ class StackControllerTest {
     fun GIVEN_back_stack_WHEN_pop_THEN_old_components_not_recreated() {
         val oldStack =
             RouterStack(
-                active = activeEntry(configuration = Config()),
-                backStack = listOf(createdEntry(configuration = Config()), createdEntry(configuration = Config()))
+                active = activeEntry(configuration = Config(id = 3)),
+                backStack = listOf(createdEntry(configuration = Config(id = 1)), createdEntry(configuration = Config(id = 2)))
             )
 
         val newStack = controller.navigate(oldStack = oldStack, transformer = { it.dropLast(1) })
@@ -286,8 +285,8 @@ class StackControllerTest {
         val newStack =
             controller.navigate(
                 oldStack = RouterStack(
-                    active = activeEntry(configuration = Config()),
-                    backStack = listOf(createdEntry(configuration = Config(), savedState = TestParcelableContainer()))
+                    active = activeEntry(configuration = Config(id = 2)),
+                    backStack = listOf(createdEntry(configuration = Config(id = 1), savedState = TestParcelableContainer()))
                 ),
                 transformer = { it.dropLast(1) }
             )
@@ -302,8 +301,8 @@ class StackControllerTest {
         val newStack =
             controller.navigate(
                 oldStack = RouterStack(
-                    active = activeEntry(configuration = Config()),
-                    backStack = listOf(destroyedEntry(configuration = Config(), savedState = savedState))
+                    active = activeEntry(configuration = Config(id = 2)),
+                    backStack = listOf(destroyedEntry(configuration = Config(id = 1), savedState = savedState))
                 ),
                 transformer = { it.dropLast(1) }
             )
@@ -316,8 +315,8 @@ class StackControllerTest {
         val newStack =
             controller.navigate(
                 oldStack = RouterStack(
-                    active = activeEntry(configuration = Config()),
-                    backStack = listOf(destroyedEntry(configuration = Config()))
+                    active = activeEntry(configuration = Config(id = 2)),
+                    backStack = listOf(destroyedEntry(configuration = Config(id = 1)))
                 ),
                 transformer = { it.dropLast(1) }
             )
@@ -331,10 +330,10 @@ class StackControllerTest {
 
         controller.navigate(
             oldStack = RouterStack(
-                active = activeEntry(configuration = Config(), lifecycleRegistry = lifecycleRegistry),
-                backStack = listOf(createdEntry(configuration = Config()))
+                active = activeEntry(configuration = Config(id = 2), lifecycleRegistry = lifecycleRegistry),
+                backStack = listOf(createdEntry(configuration = Config(id = 1)))
             ),
-            transformer = { listOf(Config(), Config()) }
+            transformer = { listOf(Config(id = 3), Config(id = 4)) }
         )
 
         assertEquals(Lifecycle.State.DESTROYED, lifecycleRegistry.state)
@@ -346,10 +345,10 @@ class StackControllerTest {
 
         controller.navigate(
             oldStack = RouterStack(
-                active = activeEntry(configuration = Config()),
-                backStack = listOf(createdEntry(configuration = Config(), lifecycleRegistry = lifecycleRegistry))
+                active = activeEntry(configuration = Config(id = 2)),
+                backStack = listOf(createdEntry(configuration = Config(id = 1), lifecycleRegistry = lifecycleRegistry))
             ),
-            transformer = { listOf(Config(), Config()) }
+            transformer = { listOf(Config(id = 3), Config(id = 4)) }
         )
 
         assertEquals(Lifecycle.State.DESTROYED, lifecycleRegistry.state)
@@ -358,13 +357,13 @@ class StackControllerTest {
     @Test
     fun WHEN_navigate_to_different_stack_THEN_new_stack_contains_only_new_configurations() {
         val lifecycleRegistry = LifecycleRegistry().apply { resume() }
-        val newConfigurationStack = listOf(Config(), Config())
+        val newConfigurationStack = listOf(Config(id = 3), Config(id = 4))
 
         val newStack =
             controller.navigate(
                 oldStack = RouterStack(
-                    active = activeEntry(configuration = Config(), lifecycleRegistry = lifecycleRegistry),
-                    backStack = listOf(createdEntry(configuration = Config()))
+                    active = activeEntry(configuration = Config(id = 2), lifecycleRegistry = lifecycleRegistry),
+                    backStack = listOf(createdEntry(configuration = Config(id = 1)))
                 ),
                 transformer = { newConfigurationStack }
             )
@@ -377,10 +376,10 @@ class StackControllerTest {
         val newStack =
             controller.navigate(
                 oldStack = RouterStack(
-                    active = activeEntry(configuration = Config()),
-                    backStack = listOf(createdEntry(configuration = Config()))
+                    active = activeEntry(configuration = Config(id = 2)),
+                    backStack = listOf(createdEntry(configuration = Config(id = 1)))
                 ),
-                transformer = { listOf(Config(), Config()) }
+                transformer = { listOf(Config(id = 3), Config(id = 4)) }
             )
 
         assertEquals(Lifecycle.State.RESUMED, newStack.active.lifecycleRegistry.state)
@@ -391,10 +390,10 @@ class StackControllerTest {
         val newStack =
             controller.navigate(
                 oldStack = RouterStack(
-                    active = activeEntry(configuration = Config()),
-                    backStack = listOf(createdEntry(configuration = Config()))
+                    active = activeEntry(configuration = Config(id = 2)),
+                    backStack = listOf(createdEntry(configuration = Config(id = 1)))
                 ),
-                transformer = { listOf(Config(), Config()) }
+                transformer = { listOf(Config(id = 3), Config(id = 4)) }
             )
 
         assertTrue(newStack.backStack.all { it is RouterEntry.Destroyed })
@@ -402,19 +401,17 @@ class StackControllerTest {
 
     @Test
     fun WHEN_navigate_to_partially_different_stack_with_new_active_component_THEN_new_stack_contains_same_old_configurations_and_new_configurations() {
-        val sameConfig1 = Config()
-        val sameConfig2 = Config()
-        val newConfigurationStack = listOf(Config(), sameConfig1, sameConfig2, Config(), Config())
+        val newConfigurationStack = listOf(Config(id = 6), Config(id = 2), Config(id = 4), Config(id = 7), Config(id = 8))
 
         val newStack =
             controller.navigate(
                 oldStack = RouterStack(
-                    active = activeEntry(configuration = Config()),
+                    active = activeEntry(configuration = Config(id = 5)),
                     backStack = listOf(
-                        createdEntry(configuration = Config()),
-                        createdEntry(configuration = sameConfig1),
-                        createdEntry(configuration = Config()),
-                        createdEntry(configuration = sameConfig2)
+                        createdEntry(configuration = Config(id = 1)),
+                        createdEntry(configuration = Config(id = 2)),
+                        createdEntry(configuration = Config(id = 3)),
+                        createdEntry(configuration = Config(id = 4))
                     )
                 ),
                 transformer = { newConfigurationStack }
@@ -425,46 +422,40 @@ class StackControllerTest {
 
     @Test
     fun WHEN_navigate_to_partially_different_stack_with_new_active_component_THEN_same_old_components_not_recreated() {
-        val sameConfig1 = Config()
-        val sameConfig2 = Config()
-
         val oldStack =
             RouterStack(
-                active = activeEntry(configuration = Config()),
+                active = activeEntry(configuration = Config(id = 5)),
                 backStack = listOf(
-                    createdEntry(configuration = Config()),
-                    createdEntry(configuration = sameConfig1),
-                    createdEntry(configuration = Config()),
-                    createdEntry(configuration = sameConfig2)
+                    createdEntry(configuration = Config(id = 1)),
+                    createdEntry(configuration = Config(id = 2)),
+                    createdEntry(configuration = Config(id = 3)),
+                    createdEntry(configuration = Config(id = 4))
                 )
             )
 
         val newStack =
             controller.navigate(
                 oldStack = oldStack,
-                transformer = { listOf(Config(), sameConfig1, sameConfig2, Config(), Config()) }
+                transformer = { listOf(Config(id = 6), Config(id = 2), Config(id = 4), Config(id = 7), Config(id = 8)) }
             )
 
-        assertSame(oldStack.backStack[1].asCreated().instance, newStack.backStack[1].asCreated().instance)
-        assertSame(oldStack.backStack[3].asCreated().instance, newStack.backStack[2].asCreated().instance)
+        assertEquals(oldStack.backStack[1].asCreated().instance, newStack.backStack[1].asCreated().instance)
+        assertEquals(oldStack.backStack[3].asCreated().instance, newStack.backStack[2].asCreated().instance)
     }
 
     @Test
     fun WHEN_navigate_to_partially_different_stack_with_same_active_component_THEN_new_stack_contains_same_old_configurations_and_new_configurations() {
-        val sameConfig1 = Config()
-        val sameConfig2 = Config()
-        val sameConfig3 = Config()
-        val newConfigurationStack = listOf(Config(), sameConfig1, sameConfig2, Config(), sameConfig3)
+        val newConfigurationStack = listOf(Config(id = 6), Config(id = 2), Config(id = 4), Config(id = 7), Config(id = 5))
 
         val newStack =
             controller.navigate(
                 oldStack = RouterStack(
-                    active = activeEntry(configuration = sameConfig3),
+                    active = activeEntry(configuration = Config(id = 5)),
                     backStack = listOf(
-                        createdEntry(configuration = Config()),
-                        createdEntry(configuration = sameConfig1),
-                        createdEntry(configuration = Config()),
-                        createdEntry(configuration = sameConfig2)
+                        createdEntry(configuration = Config(id = 1)),
+                        createdEntry(configuration = Config(id = 2)),
+                        createdEntry(configuration = Config(id = 3)),
+                        createdEntry(configuration = Config(id = 4))
                     )
                 ),
                 transformer = { newConfigurationStack }
@@ -475,25 +466,21 @@ class StackControllerTest {
 
     @Test
     fun WHEN_navigate_to_partially_different_stack_with_same_active_component_THEN_same_old_components_not_recreated() {
-        val sameConfig1 = Config()
-        val sameConfig2 = Config()
-        val sameConfig3 = Config()
-
         val oldStack =
             RouterStack(
-                active = activeEntry(configuration = sameConfig3),
+                active = activeEntry(configuration = Config(id = 5)),
                 backStack = listOf(
-                    createdEntry(configuration = Config()),
-                    createdEntry(configuration = sameConfig1),
-                    createdEntry(configuration = Config()),
-                    createdEntry(configuration = sameConfig2)
+                    createdEntry(configuration = Config(id = 1)),
+                    createdEntry(configuration = Config(id = 2)),
+                    createdEntry(configuration = Config(id = 3)),
+                    createdEntry(configuration = Config(id = 4))
                 )
             )
 
         val newStack =
             controller.navigate(
                 oldStack = oldStack,
-                transformer = { listOf(Config(), sameConfig1, sameConfig2, Config(), sameConfig3) }
+                transformer = { listOf(Config(id = 6), Config(id = 2), Config(id = 4), Config(id = 7), Config(id = 5)) }
             )
 
         assertSame(oldStack.backStack[1].asCreated().instance, newStack.backStack[1].asCreated().instance)
@@ -502,30 +489,48 @@ class StackControllerTest {
     }
 
     @Test
-    fun WHEN_navigate_to_equal_stack_THEN_stack_not_changed() {
-        val sameConfig1 = Config()
-        val sameConfig2 = Config()
+    fun WHEN_navigate_to_partially_different_stack_with_same_active_component_from_back_stack_THEN_same_old_components_not_recreated() {
+        val oldStack =
+            RouterStack(
+                active = activeEntry(configuration = Config(id = 5)),
+                backStack = listOf(
+                    createdEntry(configuration = Config(id = 1)),
+                    createdEntry(configuration = Config(id = 2)),
+                    createdEntry(configuration = Config(id = 3)),
+                    createdEntry(configuration = Config(id = 4))
+                )
+            )
+
+        val newStack =
+            controller.navigate(
+                oldStack = oldStack,
+                transformer = { listOf(Config(id = 6), Config(id = 2), Config(id = 4), Config(id = 7), Config(id = 3)) }
+            )
 
+        assertSame(oldStack.backStack[1].asCreated().instance, newStack.backStack[1].asCreated().instance)
+        assertSame(oldStack.backStack[3].asCreated().instance, newStack.backStack[2].asCreated().instance)
+        assertSame(oldStack.backStack[2].asCreated().instance, newStack.active.instance)
+    }
+
+    @Test
+    fun WHEN_navigate_to_equal_stack_THEN_stack_not_changed() {
         val oldStack =
             RouterStack(
-                active = activeEntry(configuration = sameConfig1),
-                backStack = listOf(createdEntry(configuration = sameConfig2))
+                active = activeEntry(configuration = Config(id = 2)),
+                backStack = listOf(createdEntry(configuration = Config(id = 1)))
             )
 
-        val newStack = controller.navigate(oldStack = oldStack, transformer = { listOf(sameConfig2, sameConfig1) })
+        val newStack = controller.navigate(oldStack = oldStack, transformer = { listOf(Config(id = 1), Config(id = 2)) })
 
         assertEquals(oldStack, newStack)
     }
 
     @Test
     fun WHEN_navigate_to_same_stack_THEN_stack_not_changed() {
-        val sameConfig1 = Config()
-        val sameConfig2 = Config()
-
         val oldStack =
             RouterStack(
-                active = activeEntry(configuration = sameConfig1),
-                backStack = listOf(createdEntry(configuration = sameConfig2))
+                active = activeEntry(configuration = Config(id = 1)),
+                backStack = listOf(createdEntry(configuration = Config(id = 2)))
             )
 
         val newStack = controller.navigate(oldStack = oldStack, transformer = { it })
@@ -584,7 +589,7 @@ class StackControllerTest {
             )
     }
 
-    private class Config
+    private data class Config(val id: Int)
 
     private class Component