Real World Example

Retry with Callbacks

Network calls in apps like Paytm or IRCTC can fail temporarily. A reusable higher-order retry function takes the work as a lambda, plus optional callbacks for logging.

Example

fun <T> retry(
    times: Int,
    onRetry: (attempt: Int, error: String) -> Unit = { _, _ -> },
    block: (attempt: Int) -> T,
): T {
    var last: Exception? = null
    for (attempt in 1..times) {
        try {
            return block(attempt)
        } catch (e: Exception) {
            last = e
            onRetry(attempt, e.message ?: "unknown")
        }
    }
    throw last!!
}

fun fetchPnrStatus(attempt: Int): String {
    if (attempt < 3) throw RuntimeException("Timeout on attempt $attempt")
    return "PNR 4521: CONFIRMED (B2, 34)"
}

fun main() {
    val status = retry(
        times = 4,
        onRetry = { n, err -> println("Retry $n failed: $err") },
    ) { attempt -> fetchPnrStatus(attempt) }
    println(status)
}

Output

Retry 1 failed: Timeout on attempt 1
Retry 2 failed: Timeout on attempt 2
PNR 4521: CONFIRMED (B2, 34)

Android and Compose Callbacks

Compose components receive events as lambda parameters - the screen decides what happens on click.

@Composable
fun ProductCard(
    product: Product,
    onAddToCart: (Product) -> Unit,
    onClick: () -> Unit = {},
) {
    Card(onClick = onClick) {
        Text(product.name)
        Button(onClick = { onAddToCart(product) }) { Text("Add to cart") }
    }
}

// Caller passes behaviour as lambdas / function references
ProductCard(product, onAddToCart = viewModel::addToCart, onClick = { navController.navigate("product/${product.id}") })