---
title: 'Değişmezlik ve Kararlılık'
source: 'https://academia.sh/tr/kurslar/compose/degismezlik-ve-kararlilik'
course: 'Jetpack Compose ile Arayüz'
language: tr
updated: '2026-10-21T05:02:37+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Kararlı ve kararsız bir türün farkını platformun bilme ölçütüyle açıklar'
    - 'Yerinde değiştirilen listenin ve yeni liste üreten olayın yönünü ölçer'
    - 'Gözlenen değişikliğin referansın değişmesine bağlı olduğunu modelde gösterir'
    - 'Olayla yeni liste üretmenin yukarı ve aşağı iki hareketten oluştuğunu gösterir'
---

# Değişmezlik ve Kararlılık

Platform bir değerin değişip değişmediğini bilirse yeniden oluşturmada atlama yapabilir. Ders yerinde değiştirilen listeyle yeni liste üreten olayın aynı yöne, yukarı gittiğini ama yalnız birinin gözlendiğini ölçer.

Önceki ders, girdisi değişmeyen bileşen işlevinin atlandığını varsaymıştı. Bu ders o varsayımı açar: platform bir değerin değişip değişmediğini nasıl bilir? Cevap hareketin yönünü değiştirmez ama hareketin görülüp görülmediğini değiştirir. Dersin sorusu yine aynıdır: **bu veri arayüz ağacında hangi yöne gidiyor?** İki ayrı biçimde yukarı gidebilir ve yalnız birinde platform bunu fark eder.

```kotlin
// Direction.kt — bir verinin arayuz agacinda hangi yone gittigini siniflandirir
class Tree(private val parentOf: Map<String, String>) {
    fun contains(node: String): Boolean = node in parentOf.keys || node in parentOf.values
    fun parent(node: String): String? = parentOf[node]
    fun ancestors(node: String): List<String> {
        val chain = mutableListOf<String>()
        var current = parentOf[node]
        while (current != null) {
            chain.add(current)
            current = parentOf[current]
        }
        return chain
    }
}

class Move(val label: String, val from: String, val to: String, tree: Tree) {
    val direction: String = when {
        !tree.contains(from) || !tree.contains(to) -> "dis"
        to in tree.ancestors(from) -> "yukari"
        tree.parent(to) == from -> "asagi"
        from in tree.ancestors(to) -> "derin"
        else -> error("akrabasiz: $from ve $to")
    }

    fun describe() {
        println("$label: kimden=$from | kime=$to -> $direction")
    }
}

fun countDirections(moves: List<Move>) {
    for (name in listOf("asagi", "yukari", "derin", "dis")) {
        println("$name: ${moves.count { it.direction == name }}")
    }
}
```

## Platform Neyi Bilir

Platform belgesine göre bir tür, değişmezse ya da değerinin yeniden oluşturmalar arasında değişip değişmediği platform tarafından bilinebiliyorsa kararlıdır. Platformun değeri bilemediği tür kararsızdır. Belgenin örneği: özellikleri `val` olan bir veri sınıfı değişmezdir; özellikleri `var` olan sürümde özellikleri değişse platform bunu fark etmezdi, çünkü platform yalnız kendi durum nesnelerindeki değişiklikleri izler.

Liste arayüzleri için belge şunu der: standart koleksiyon arayüzleri (`List`, `Set`, `Map`) kararsız sayılır, çünkü altındaki gerçekleme değiştirilebilir olabilir. Güçlü atlama kipi, belgeye göre Kotlin 2.0.20 ve üzerinde varsayılan olarak açıktır. Kip açıkken kararsız parametreler referans eşitliğiyle (`===`) karşılaştırılır ve aynı nesne geçilirse bileşen işlevi atlanır.

```kotlin
// Platform kodu: MutableList ve data class
import androidx.compose.runtime.*

class CartState(val items: MutableList<String>)

@Composable
fun CartRow(state: CartState) {
    Button(onClick = { state.items.add("c") }) {
        Text("Ekle: ${state.items.size}")
    }
}

data class CartItems(val items: List<String>)

@Composable
fun CartList(cart: CartItems, onAdd: (CartItems) -> Unit) {
    Button(onClick = { onAdd(cart.copy(items = cart.items + "c")) }) {
        Text("Ekle: ${cart.items.size}")
    }
}
```

İlk bileşen işlevi listeyi olduğu yerde değiştirir: `state` ve onun listesi aynı nesne kalır. İkincisi yeni bir `CartItems` üretir ve değişikliği sahibine olay olarak verir. Bu parça platform kodudur ve burada çıktı iddia etmiyoruz. Model, platformun bu kuralını kurar; model platformun kendisi değildir.

Model "gözlenen"i basit bir kuralla kurar: değişiklikten önceki ve sonraki liste aynı nesneyse platform fark edemez; farklı nesneyse eder. Bir `Edit`, değişikliği yapanı, listenin sahibini ve önceki ile sonraki listeyi taşır.

```kotlin
// Edits.kt — bir degisikligin yonu ve gozlenip gozlenmedigi
class Edit(
    val label: String,
    val by: String,
    val owner: String,
    before: List<String>,
    val after: List<String>,
    tree: Tree,
) {
    val move = Move(label, by, owner, tree)
    val observed: Boolean = before !== after

    fun report() {
        move.describe()
        println("  gozlenen=$observed | icerik=$after")
    }
}
```

**BI11.** Model gözlenmeyi referans farkıyla kurar. Platformun kararlılığı hangi türlerde nasıl çıkardığı, derleyici ayarının etkisi ve eşitlik karşılaştırmasının maliyeti ölçülmedi.

## Yerinde Değiştirmek

Çocuk, sahibin listesini olduğu yerde değiştirir. Veri çocuktan sahibe gider; sahip `Screen`, değiştiren `CartRow`.

```kotlin
// Main.kt — yerinde degistirme: yon yukari, gozlenen degil
fun main() {
    val tree = Tree(mapOf(
        "Screen" to "App",
        "CartRow" to "Screen",
    ))
    val list = mutableListOf("a", "b")
    val before: List<String> = list
    list.add("c")
    val edit = Edit("degistir", "CartRow", "Screen", before, list, tree)
    edit.report()
}
```

```text
degistir: kimden=CartRow | kime=Screen -> yukari
  gozlenen=false | icerik=[a, b, c]
```

Hareketin yönü yukarıdır, çünkü hedef kaynağın atasıdır. Ama liste aynı nesne kaldığı için `gozlenen=false`: içerik değişti, platform değişikliği öğrenmedi. Ekran eski içerikle kalabilir.

## Olayla Yeni Liste

Çocuk listeyi değiştirmez; sahibine olay verir, sahip yeni liste üretir.

```kotlin
// Main.kt — olayla yeni liste: yon yukari, gozlenen
fun main() {
    val tree = Tree(mapOf(
        "Screen" to "App",
        "CartRow" to "Screen",
    ))
    val before = listOf("a", "b")
    val after = before + "c"
    val edit = Edit("olay", "CartRow", "Screen", before, after, tree)
    edit.report()
}
```

```text
olay: kimden=CartRow | kime=Screen -> yukari
  gozlenen=true | icerik=[a, b, c]
```

Yön aynıdır: yukarı. Liste yeni nesne olduğu için `gozlenen=true`. Dersin yönü budur: yukarı.

Olayın hikâyesi burada bitmez. Sahip yeni listeyi bildiğinde onu aşağı, okuyucuya verir.

```kotlin
// Main.kt — tam akis: bir yukari, bir asagi
fun main() {
    val tree = Tree(mapOf(
        "Screen" to "App",
        "CartRow" to "Screen",
    ))
    val moves = listOf(
        Move("olay", "CartRow", "Screen", tree),
        Move("yeni-liste", "Screen", "CartRow", tree),
    )
    moves.forEach { it.describe() }
    countDirections(moves)
}
```

```text
olay: kimden=CartRow | kime=Screen -> yukari
yeni-liste: kimden=Screen | kime=CartRow -> asagi
asagi: 1
yukari: 1
derin: 0
dis: 0
```

Yerinde değiştirmede yalnız bir hareket vardır ve geri dönüş yoktur. Olayla yeni liste ise iki hareketten oluşur: olay yukarı, yeni liste aşağı. Ders 03'teki akışın aynısıdır. Yukarıdaki iki satır kuralı göstermek için yazılmıştır, ölçüm değildir: ikisinde de uçlar elle yazılmıştır.

Bu ders M31/K01'den farklıdır. O kurs iki değerin eşit sayılıp sayılmayacağını kurdu. Burada eşitlik ölçülmez; ölçülen, hareketin yönü ve değişikliğin görülüp görülmediğidir.

**BI12.** Sahibin yeni listeyi aşağı vermesi modelde bir hareket olarak kurulur. Platformda yeni listenin hangi kapsamlarda yeniden oluşturmaya yol açtığı ölçülmedi.

## Sınırlayıcı Ölçüm

Aynı değiştiren, aynı sahip, aynı içerik. İki değişiklik yöntemi yan yana.

```kotlin
// Main.kt — ayni yon, farkli gozlenme
fun main() {
    val tree = Tree(mapOf(
        "Screen" to "App",
        "CartRow" to "Screen",
    ))
    val inPlace = mutableListOf("a", "b")
    val beforeInPlace: List<String> = inPlace
    inPlace.add("c")
    val copied = listOf("a", "b")
    val a = Edit("yerinde", "CartRow", "Screen", beforeInPlace, inPlace, tree)
    val b = Edit("kopya", "CartRow", "Screen", copied, copied + "c", tree)
    println("yerinde: yon=${a.move.direction} gozlenen=${a.observed}")
    println("kopya: yon=${b.move.direction} gozlenen=${b.observed}")
}
```

```text
yerinde: yon=yukari gozlenen=false
kopya: yon=yukari gozlenen=true
```

İki değişiklik aynı yöne gider. Fark yönde değil, gözlenmededir. Kural yöne baktığı için ikisine aynı cevabı verir; görülüp görülmediği ise listenin nesne olarak değişmesine bağlıdır.

## Özet

- Bu dersin yönü: yukarı. Çocuğun sahibin listesini değiştirmesi de, sahibe olay vermesi de yukarı gider.
- Yerinde değiştirmede içerik değişti ama gözlenen değil: yukarı 1, gözlenen false.
- Olayla yeni liste üretmede aynı yön gözlenen true ile ölçüldü.
- Olayla yeni liste iki hareketle gösterilir: olay yukarı, yeni liste aşağı. Bu gösterim bir ölçüm değildir; uçları elle yazılmıştır.
- Aynı yönün iki yöntemi yan yana ölçüldü: ikisi de yukarı, yalnız kopya gözlenen.

## Sonraki Adım

Bu ders bileşen işlevi modelini kapatır: bileşen işlevi, durum, durumu kaldırma, yeniden oluşturma, yan etkiler ve kararlılık. Sıradaki konu, `Temel Düzenler`, bu modelin üstüne ekrandaki düzeni kurar.
