CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-jetbrains-compose-runtime--runtime-uikitx64

Compose Multiplatform runtime library for iOS UIKit x64 target providing core runtime functionality for declarative UI framework integration.

Pending
Overview
Eval results
Files

snapshot-system.mddocs/

Snapshot System

Low-level snapshot-based state management providing efficient change tracking and transactional state updates. The snapshot system is the foundation for Compose's state management and enables optimizations like structural sharing and conflict resolution.

Capabilities

Snapshot Classes

Core classes for managing snapshots of mutable state.

/**
 * Abstract base class for snapshots representing a consistent view of mutable state
 */
abstract class Snapshot {
    /** Unique identifier for this snapshot */
    abstract val id: Int
    
    /** Whether this snapshot is invalid due to conflicts */
    abstract val invalid: Boolean
    
    /** Set of objects that were read during this snapshot */
    abstract val readSet: Set<Any>
    
    /** Set of objects that were modified during this snapshot */
    abstract val writeSet: Set<Any>
    
    /** Disposes this snapshot and releases resources */
    abstract fun dispose()
    
    companion object {
        /** The global snapshot that all state changes are applied to */
        val global: MutableSnapshot
        
        /** The current snapshot for the current thread */
        val current: Snapshot
        
        /**
         * Takes an immutable snapshot of the current state
         * @param readObserver Optional observer for state reads
         * @return Immutable snapshot
         */
        fun takeSnapshot(readObserver: ((Any) -> Unit)? = null): Snapshot
        
        /**
         * Takes a mutable snapshot for transactional state changes
         * @param readObserver Optional observer for state reads
         * @param writeObserver Optional observer for state writes
         * @return Mutable snapshot for making changes
         */
        fun takeMutableSnapshot(
            readObserver: ((Any) -> Unit)? = null,
            writeObserver: ((Any) -> Unit)? = null
        ): MutableSnapshot
        
        /**
         * Runs a block with the given snapshot as current
         * @param snapshot Snapshot to make current
         * @param block Code to execute with the snapshot
         * @return Result of the block
         */
        fun <T> withSnapshot(snapshot: Snapshot, block: () -> T): T
        
        /**
         * Runs a block with a mutable snapshot
         * @param readObserver Optional observer for state reads
         * @param writeObserver Optional observer for state writes
         * @param block Code to execute in the snapshot
         * @return Result of the block
         */
        fun <T> withMutableSnapshot(
            readObserver: ((Any) -> Unit)? = null,
            writeObserver: ((Any) -> Unit)? = null,
            block: () -> T
        ): T
        
        /**
         * Sends and applies all pending snapshot changes
         */
        fun sendApplyNotifications()
    }
}

/**
 * Mutable snapshot that can be modified and applied
 */
abstract class MutableSnapshot : Snapshot() {
    /** Whether changes have been made to this snapshot */
    abstract val modified: Boolean
    
    /**
     * Applies this snapshot's changes to the global state
     * @return Result indicating success or failure
     */
    abstract fun apply(): SnapshotApplyResult
    
    /**
     * Creates a nested mutable snapshot
     * @param readObserver Optional observer for state reads
     * @param writeObserver Optional observer for state writes
     * @return Nested mutable snapshot
     */
    abstract fun takeNestedMutableSnapshot(
        readObserver: ((Any) -> Unit)? = null,
        writeObserver: ((Any) -> Unit)? = null
    ): MutableSnapshot
    
    /**
     * Creates a nested immutable snapshot
     * @param readObserver Optional observer for state reads
     * @return Nested immutable snapshot
     */
    abstract fun takeNestedSnapshot(readObserver: ((Any) -> Unit)? = null): Snapshot
}

Snapshot Apply Results

Results of applying snapshot changes.

/**
 * Result of applying a snapshot
 */
sealed class SnapshotApplyResult {
    /** Application succeeded */
    object Success : SnapshotApplyResult()
    
    /** Application failed due to conflicts */
    class Failure(val snapshot: Snapshot) : SnapshotApplyResult()
}

Usage Examples:

// Basic snapshot usage
fun snapshotExample() {
    val snapshot = Snapshot.takeMutableSnapshot()
    
    val result = snapshot.apply {
        // Make changes to state within the snapshot
        someState.value = "new value"
        otherState.value = "other new value"
        
        // Apply all changes atomically
        apply()
    }
    
    when (result) {
        is SnapshotApplyResult.Success -> {
            println("Changes applied successfully")
        }
        is SnapshotApplyResult.Failure -> {
            println("Changes failed to apply due to conflicts")
        }
    }
    
    snapshot.dispose()
}

Global Snapshot Operations

Functions for working with the global snapshot state.

/**
 * Runs block with global state write observation
 * @param writeObserver Function called when global state is written
 * @param block Code to execute with observation
 * @return Result of the block
 */
fun <T> Snapshot.Companion.withoutReadObservation(block: () -> T): T

/**
 * Registers a global state write observer
 * @param observer Function called when any global state changes
 * @return Handle to remove the observer
 */
fun Snapshot.Companion.registerGlobalWriteObserver(
    observer: (Any) -> Unit
): ObserverHandle

/**
 * Registers a global apply observer
 * @param observer Function called when snapshots are applied
 * @return Handle to remove the observer  
 */
fun Snapshot.Companion.registerApplyObserver(
    observer: (Set<Any>, Snapshot) -> Unit
): ObserverHandle

/**
 * Handle for removing observers
 */
interface ObserverHandle {
    /** Removes the observer */
    fun dispose()
}

Snapshot Flow Integration

Convert state reads into coroutine Flows that emit when dependencies change.

/**
 * Creates a Flow that emits the result of block whenever observed state changes
 * The flow emits immediately with the current value, then emits again when any
 * state accessed within block changes
 * @param block Function that reads state and produces values
 * @return Flow that emits when any observed state changes
 */
fun <T> snapshotFlow(block: () -> T): Flow<T>

Usage Examples:

@Composable
fun SnapshotFlowExample() {
    var name by remember { mutableStateOf("") }
    var age by remember { mutableStateOf(0) }
    
    // Flow that combines multiple state reads
    val userSummary = remember {
        snapshotFlow { 
            if (name.isNotEmpty() && age > 0) {
                "User: $name, Age: $age"
            } else {
                "Incomplete user data"
            }
        }
    }
    
    LaunchedEffect(Unit) {
        userSummary.collect { summary ->
            logger.log("User summary updated: $summary")
        }
    }
    
    // Create a debounced search flow
    val debouncedSearch = remember {
        snapshotFlow { name }
            .debounce(300)
            .filter { it.length >= 2 }
    }
    
    LaunchedEffect(Unit) {
        debouncedSearch.collect { query ->
            performSearch(query)
        }
    }
}

Advanced Snapshot Operations

Nested Snapshots

fun nestedSnapshotExample() {
    val outerSnapshot = Snapshot.takeMutableSnapshot()
    
    outerSnapshot.apply {
        someState.value = "outer change"
        
        // Create nested snapshot
        val innerSnapshot = takeNestedMutableSnapshot()
        
        innerSnapshot.apply {
            someState.value = "inner change"
            otherState.value = "another change"
            
            // Apply inner changes first
            apply()
        }
        
        // Apply outer changes (includes inner changes)
        apply()
    }
    
    outerSnapshot.dispose()
}

Conflict Resolution

fun conflictResolutionExample() {
    val state = mutableStateOf("initial")
    
    // First snapshot
    val snapshot1 = Snapshot.takeMutableSnapshot()
    snapshot1.apply {
        state.value = "change 1"
    }
    
    // Second snapshot (concurrent modification)
    val snapshot2 = Snapshot.takeMutableSnapshot()
    snapshot2.apply {
        state.value = "change 2"
    }
    
    // Apply first snapshot
    val result1 = snapshot1.apply()
    
    // Apply second snapshot (may conflict)
    val result2 = snapshot2.apply()
    
    when (result2) {
        is SnapshotApplyResult.Success -> {
            println("Second change applied successfully")
        }
        is SnapshotApplyResult.Failure -> {
            println("Conflict detected, manual resolution required")
            // Handle conflict resolution
        }
    }
    
    snapshot1.dispose()
    snapshot2.dispose()
}

State Observation

fun stateObservationExample() {
    val readObserver: (Any) -> Unit = { state ->
        println("State read: $state")
    }
    
    val writeObserver: (Any) -> Unit = { state ->
        println("State written: $state")
    }
    
    val snapshot = Snapshot.takeMutableSnapshot(readObserver, writeObserver)
    
    snapshot.apply {
        // These operations will trigger observers
        val value = someState.value // Triggers readObserver
        someState.value = "new value" // Triggers writeObserver
        
        apply()
    }
    
    snapshot.dispose()
}

Global State Monitoring

fun globalStateMonitoringExample() {
    // Monitor all global state writes
    val writeHandle = Snapshot.registerGlobalWriteObserver { state ->
        println("Global state changed: $state")
    }
    
    // Monitor snapshot applications
    val applyHandle = Snapshot.registerApplyObserver { changedObjects, snapshot ->
        println("Snapshot applied with ${changedObjects.size} changes")
    }
    
    // Perform some state changes
    someGlobalState.value = "changed"
    
    // Clean up observers
    writeHandle.dispose()
    applyHandle.dispose()
}

iOS Platform Integration

Thread Safety

// iOS-specific snapshot handling
fun iosSnapshotExample() {
    // Ensure snapshot operations happen on the main thread
    DispatchQueue.main.async {
        val snapshot = Snapshot.takeMutableSnapshot()
        
        snapshot.apply {
            // Safe to modify state on main thread
            uiState.value = newUIState
            apply()
        }
        
        snapshot.dispose()
    }
}

Integration with UIKit State

@Composable
fun UIKitStateIntegration() {
    var composeState by remember { mutableStateOf("") }
    
    // Create flow that watches Compose state
    val stateFlow = remember {
        snapshotFlow { composeState }
    }
    
    LaunchedEffect(Unit) {
        stateFlow.collect { value ->
            // Update UIKit component when Compose state changes
            DispatchQueue.main.async {
                someUIKitView.text = value
            }
        }
    }
}

Performance Optimization

Batch State Updates

fun batchStateUpdatesExample() {
    // Batch multiple state changes in a single snapshot
    val snapshot = Snapshot.takeMutableSnapshot()
    
    snapshot.apply {
        // All these changes will be applied atomically
        state1.value = "value1"
        state2.value = "value2"
        state3.value = "value3"
        
        apply() // Single recomposition for all changes
    }
    
    snapshot.dispose()
}

Snapshot Recycling

class SnapshotManager {
    private val snapshotPool = mutableListOf<MutableSnapshot>()
    
    fun withPooledSnapshot(block: MutableSnapshot.() -> Unit) {
        val snapshot = snapshotPool.removeFirstOrNull() 
            ?: Snapshot.takeMutableSnapshot()
        
        try {
            snapshot.block()
        } finally {
            if (!snapshot.invalid) {
                snapshotPool.add(snapshot)
            } else {
                snapshot.dispose()
            }
        }
    }
}

Error Handling

Snapshot Exceptions

fun snapshotErrorHandlingExample() {
    val snapshot = Snapshot.takeMutableSnapshot()
    
    try {
        snapshot.apply {
            // Operations that might fail
            riskyStateOperation()
            apply()
        }
    } catch (e: Exception) {
        // Handle errors - snapshot is automatically invalidated
        println("Snapshot operation failed: ${e.message}")
    } finally {
        snapshot.dispose()
    }
}

Performance Considerations

  • Snapshot Disposal: Always dispose snapshots to prevent memory leaks
  • Batch Updates: Use snapshots to batch multiple state changes and reduce recomposition
  • Read Observation: Minimize expensive read observers that are called frequently
  • Nested Snapshots: Use nested snapshots sparingly as they add overhead
  • Conflict Resolution: Design state updates to minimize conflicts between concurrent snapshots
  • Flow Creation: Cache snapshotFlow instances to avoid recreating flows unnecessarily

Install with Tessl CLI

npx tessl i tessl/maven-org-jetbrains-compose-runtime--runtime-uikitx64

docs

composition-lifecycle.md

composition-local.md

effects.md

index.md

ios-integration.md

snapshot-system.md

state-management.md

tile.json