# Make it easy to repeat something until it succeeds, but at most n times

**URL:** <https://discuss.kotlinlang.org/t/make-it-easy-to-repeat-something-until-it-succeeds-but-at-most-n-times/8097>\
**Category:** Language Design\
**Created:** [June 9, 2018, 12:29pm UTC](https://discuss.kotlinlang.org/t/make-it-easy-to-repeat-something-until-it-succeeds-but-at-most-n-times/8097 "2018-06-09T12:29:00Z")\
**Posts on this page:** 14\
**Page:** 1

<div class="post-metadata">

**Author:** ![dcuser](https://avatars.discourse-cdn.com/v4/letter/d/48db29/32.png) [@dcuser](https://discuss.kotlinlang.org/u/dcuser)\
**Post date:** [June 9, 2018, 12:29pm UTC](https://discuss.kotlinlang.org/t/make-it-easy-to-repeat-something-until-it-succeeds-but-at-most-n-times/8097/1 "2018-06-09T12:29:00Z")

</div>

These loops:

```
for (i in 0..2) {
    doSomething()
    if(somethingFailed()) {
        continue
    }
    break
}

```

could maybe be expressed better.

Something like this would be nice:

```
try (maxTries = 3) {
    doSomething()
    if(somethingFailed()) {
        retry
    }
} 

```

And:

```
try (maxTries = 3) {
    doSomething()
} catch(_: BadException) {
    retry
} catch (_: maxTriesExceeded) {
    log("big problem")
}

```

---

<div class="post-metadata">

**Author:** ![Wasabi375](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/wasabi375/32/4741_2.png) [@Wasabi375](https://discuss.kotlinlang.org/u/Wasabi375)\
**Post date:** [June 9, 2018, 12:43pm UTC](https://discuss.kotlinlang.org/t/make-it-easy-to-repeat-something-until-it-succeeds-but-at-most-n-times/8097/2 "2018-06-09T12:43:54Z")

</div>

```kotlin
for(i in 0..2){
	try {
		doSometihng()
		break
	}catch (e: Exception){
		...
	}
}

```

This can easily be done inside of the language already and I don’t think it is used often so I don’t think it is worth extending the standard library for it. Why not just create a simple utility function in your project?

---

<div class="post-metadata">

**Author:** ![pdvrieze](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/pdvrieze/32/1882_2.png) [@pdvrieze](https://discuss.kotlinlang.org/u/pdvrieze)\
**Post date:** [June 9, 2018, 6:28pm UTC](https://discuss.kotlinlang.org/t/make-it-easy-to-repeat-something-until-it-succeeds-but-at-most-n-times/8097/3 "2018-06-09T18:28:49Z")

</div>

Alternatively you can do it as a sequence with takeN and firstOrNull. In some cases you can just use the range as a sequence/list instead of using takeN

---

<div class="post-metadata">

**Author:** ![dcuser](https://avatars.discourse-cdn.com/v4/letter/d/48db29/32.png) [@dcuser](https://discuss.kotlinlang.org/u/dcuser)\
**Post date:** [June 10, 2018, 11:40am UTC](https://discuss.kotlinlang.org/t/make-it-easy-to-repeat-something-until-it-succeeds-but-at-most-n-times/8097/4 "2018-06-10T11:40:07Z")

</div>

Well, if the program is very short, of course it makes no real difference. But I think that it would enhance readability in long programs.

Currently, everyone solves it in another way, I think that a unified solution would be better.

And also, all of the solutions have disadvantages: Like, if you choose Wasabi375’s solution. Some weeks later you want to add logging and log a warning in case it failed all 3 times.  
Of course this is possible but it is more complex than it could be.

---

<div class="post-metadata">

**Author:** ![jstuyts](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/jstuyts/32/2141_2.png) [@jstuyts](https://discuss.kotlinlang.org/u/jstuyts)\
**Post date:** [June 11, 2018, 7:22am UTC](https://discuss.kotlinlang.org/t/make-it-easy-to-repeat-something-until-it-succeeds-but-at-most-n-times/8097/5 "2018-06-11T07:22:28Z")

</div>

A simple `while` statement will do. No jumps using `break` or `continue`, and a simple condition that clearly states when the body will be executed:

```auto
var hasSucceeded = false
var numberOfTriesRemaining = 3
while (!hasSucceeded && numberOfTriesRemaining > 0) {
   numberOfTriesRemaining--
   doSomething()
   hasSucceeded = !somethingFailed()
}

```

This also allows you to check the final result after the loop.

---

<div class="post-metadata">

**Author:** ![arocnies](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/arocnies/32/5143_2.png) [@arocnies](https://discuss.kotlinlang.org/u/arocnies)\
**Post date:** [June 11, 2018, 7:08pm UTC](https://discuss.kotlinlang.org/t/make-it-easy-to-repeat-something-until-it-succeeds-but-at-most-n-times/8097/6 "2018-06-11T19:08:36Z")

</div>

I don’t think this needs to be added to the language. Retry logic could be done with functions:

```run-kotlin
fun main(args: Array<String>) {
//sampleStart
    retry(5) {
        println("Will succeed first attempt\n")
    }
    
    retry(5) {
        throw Exception("Will fail after 5 retry attempts")
    }
//sampleEnd
}

fun <T> retry(numOfRetries: Int, block: () -> T): T {
    var throwable: Throwable? = null
    (1..numOfRetries).forEach { attempt ->
        try {
            return block()
        } catch (e: Throwable) {
            throwable = e
            println("Failed attempt $attempt / $numOfRetries")
        }
    }
    throw throwable!!
}

```

---

<div class="post-metadata">

**Author:** ![stangl0r](https://avatars.discourse-cdn.com/v4/letter/s/58f4c7/32.png) [@stangl0r](https://discuss.kotlinlang.org/u/stangl0r)\
**Post date:** [June 21, 2018, 9:32pm UTC](https://discuss.kotlinlang.org/t/make-it-easy-to-repeat-something-until-it-succeeds-but-at-most-n-times/8097/7 "2018-06-21T21:32:16Z")

</div>

Assuming you don’t have side effects, yes.  
Monads ftw btw.

---

<div class="post-metadata">

**Author:** ![andrew.stone](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/andrew.stone/32/6060_2.png) [@andrew.stone](https://discuss.kotlinlang.org/u/andrew.stone)\
**Post date:** [March 26, 2024, 8:08pm UTC](https://discuss.kotlinlang.org/t/make-it-easy-to-repeat-something-until-it-succeeds-but-at-most-n-times/8097/8 "2024-03-26T20:08:18Z")

</div>

I’m sorry to resurrect this old topic, however, the suggestions provided are awkward so I’d like to explore them. They work sometimes, but there is a very cool Kotlin language design features that do not interact with them well. In particular, its the val/var options and how “try” is an expression not a statement. So in Kotlin you can write this:  
val a = try { … } catch { … }

It feels to me very common to want to return a value out of a try block!

But you cannot do so using the first suggestion, because “for” is not an expression:

```auto
val a = for(i in 0..2) { // doesn't work
	try {
		doSometihng()
		break
	}catch (e: Exception){
		...
	}
}

```

You can use “var” and then set it inside the try and catch, but if the variable is actually a “val” except for this initialization clause, you can’t take advantage of “val”'s benefits. Additionally, you either need to let the var be nullable or init it to a dummy.

What about while loops? Same problem. while loops are statements.

Ok how about wrapping it into a function? Something like this:

```auto
fun<T> retry(count: Int, fn:(Int)->T?):T
{
    for(i in 0..count)
    {
        val tmp = fn(i)
        if (tmp != null) return tmp
    }
    throw RetryExceeded()
}

```

Ok, first problem: awkwardness; we either need to create a new exception to be thrown (as shown) or return null which puts that pesky null back into the code.

Second, there’s this hidden (implied) idea “if you return null, repeat, otherwise return T” in the user code. Here’s an example use:

```auto
val data = retry(5) {
  try
  {
       server.request(req, timeout=1000)
  }
  catch (e: RequestTimeout)
  {
      server.close()
      server = connectToAnotherServer()
      null // ??? weird
  }
}

```

Note that this also hides the real exception (RequestTimeout). Perhaps what we really want to do it replace the null with:  
“if (it \< 5) null else throw e”, so that in the last iteration it throws the real error rather than RetryExceeded()? Awkward.

Ok, let’s propose a statement like “break” and “continue” called “again”, and as the OP suggested, allow an optional count as part of the try opener. The semantics of “try(n)”, “again” are that “again” will execute the try block up to n times (as if there was a counter variable that is incremented at the beginning of the try block), and when that’s over, throw e.

```auto
val data = try(5) {
       server.request(req, timeout=1000)
  }
  catch (e: RequestTimeout)
  {
      server.close()
      server = connectToAnotherServer()
      again
  }

```

Anyway, this proposal is cleaner but certainly not perfect. My intention in posting this is more to observe how useful try-as-an-expression is, and yet its use is defeated by the very common try catch design pattern where you want to make a change and retry.

---

<div class="post-metadata">

**Author:** ![arocnies](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/arocnies/32/5143_2.png) [@arocnies](https://discuss.kotlinlang.org/u/arocnies)\
**Post date:** [April 16, 2024, 4:34pm UTC](https://discuss.kotlinlang.org/t/make-it-easy-to-repeat-something-until-it-succeeds-but-at-most-n-times/8097/9 "2024-04-16T16:34:32Z")

</div>

Interesting idea.  
Try-catch having language level looping mechanics would be interesting. I assume you’d have to watch out for the new ways to get a runtime infinite loop or just require the max iterations int is always passed to the `try`.

Maybe instead, we can just design a better functional version without the need for a language level change.  
Seems like the function implementation has at least these complaints:

1. Returning `null` to signal the retry. - I agree this isn’t always good, especially since I want to be able to return a valid null from a retry.
2. The function hides the real exception or would throw a `RetriesExceeded` exception alone. - Kind of agree this would be annoying. I would want to have just the original exception or a `RetriesExceeded` and the attached `cause` would be the real exception.

I think these can all be solved with a different implementation of the functional one.  
For example, you could get this:

```kotlin
val data = retry(5) {
    try {
        server.request(req, timeout=1000)
    } catch (e: RequestTimeout) {
        server.close()
        server = connectToAnotherServer()
        again()
    }
}

```

Here’s a few other very rough cut (just to show a 5-minute take) of other options-- the main point is that it’s flexible and you can make nearly the exact structure requested by this proposal with functions. The cons listed can be fixed by adjusting the implementation.

> **rough examples**
>
> ```kotlin
> import kotlin.random.Random
> 
> class RetriesExceeded(cause: Throwable): Exception(cause)
> 
> // Retry, catching none, call `again()` to try again. 
> // - Allows flagging for retry without a control jump.
> // - If you didin't like the non-control jump behavior, easy to change via private exception.
> class RetryContext<out R: Any>(private val block: RetryContext<R>.() -> R) {
> var retry: Boolean = false // Could change visibility, or change the again(), to decide how you'd like users to flag for retry.
> fun eval(): R {
> retry = false
> return this.block()
> }
> fun again() {
> retry = true
> }
> }
> fun <R: Any> retry2(count: Int, block: RetryContext<R>.() -> R): R {
> repeat(count) { index ->
> val r = RetryContext(block)
> var value = r.eval()
>         
> while (r.retry && index + 1 != count) {
> r.eval()
> }
>         
> if (index < count) return value
> }
> throw RetriesExceeded(RuntimeException())
> }
> 
> // Retry, catching provided exceptions, throw to try again.
> // - Maybe we don't want to catch all exceptions.
> inline fun <R, reified E: Throwable> retry(count: Int, block: () -> R): R {
> repeat(count) { index ->
> try {
> val value = block()
> return value
> } catch(e: Throwable) {
> if (e !is E) throw e
> else if (index + 1 == count) throw RetriesExceeded(e)
> }
> }
> error("Illegal retry state")
> }
> 
> // Retry, catching all, throw to try again. 
> // - tracks the original exception as the cause, alternative, it may not be desireable to wrap the exception for other use-cases.
> // - easy to add choice of throwing original exception via an arg flag (ie. throwCause = true)
> fun <R> retryExceptions(count: Int, block: () -> R): R {
> repeat(count) { index ->
> try {
> val value = block()
> return value
> } catch(e: Throwable) {
> if (index + 1 == count) throw RetriesExceeded(e)
> }
> }
> error("Illegal retry state")
> }
> 
> fun main() {
> retryExceptions(3) {
> println("Hello World")
> }
>     
> retryExceptions(3) {
> println("Trying 1")
> // 1 / 0 // Fail after reties, showing cause.
> }
>     
> retry2(3) {
> println("Trying 2")
> if (Random.nextBoolean()) again()
> }
>     
> retry<Unit, ArithmeticException>(3) {
> println("Trying 3")
> throw RuntimeException("Does not get retried")
> // 1 / 0 // Get's retried
> }
> }
> 
> ```

* * *

Don’t get me wrong, I do agree that retry functionality being added to a languages’ try block has benefits. It looks fine too. But “any benefit” isn’t enough to overcome the larger debt of adding it to the core language. See the [minus 100 points rule](http://stronglyemergent.com/blog/2013/negative-100-points/) for some of this thinking.

Maybe the alternatives are greatly unsatisfactory?  
or that adding an alternative to the stdlib is unsatisfactory?  
or maybe the language debt is trivial?  
or maybe the benefit applies to a broad and common use-case (or alternatively a narrow but highly impactful use-case)?

A good next step would be to show that the above alternative, with the `again()` function, is unsatisfactory for use-cases where an `again` keyword is satisfactory for the same cases.

EDIT:  
For the comparison, if you implemented the `again()` function to be a jump out of the loop, you can leverage Kotlin’s `Nothing` type. The compiler will warn of unreachable lines and understand that control flow. Since it’s flexible, you could always have both a way to immediately break to trying again and provide an option to flag for retry at the end of the loop.

---

<div class="post-metadata">

**Author:** ![andrew.stone](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/andrew.stone/32/6060_2.png) [@andrew.stone](https://discuss.kotlinlang.org/u/andrew.stone)\
**Post date:** [April 17, 2024, 6:46pm UTC](https://discuss.kotlinlang.org/t/make-it-easy-to-repeat-something-until-it-succeeds-but-at-most-n-times/8097/10 "2024-04-17T18:46:59Z")

</div>

I like it! From a language design perspective, a function classically does not affect its external context, which is why break and continue are not break() and continue(), and modifying global variables deep in some unrelated function is generally considered not good code. So if I was designing Kotlin, I’d still consider adding an “again” keyword to the language (I find myself running into this situation a lot), to keep the language syntax clean.

However, from a practical perspective, I think your implementation will work cleanly for any one who needs it.

---

<div class="post-metadata">

**Author:** ![dalewking](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/dalewking/32/1496_2.png) [@dalewking](https://discuss.kotlinlang.org/u/dalewking)\
**Post date:** [May 3, 2024, 11:26pm UTC](https://discuss.kotlinlang.org/t/make-it-easy-to-repeat-something-until-it-succeeds-but-at-most-n-times/8097/11 "2024-05-03T23:26:31Z")

</div>

This is a good case for using tail recursion

```auto
tailrec fun <T> retry(numberOfTries: Int, block: () -> T): T {
    try {
        return block()
    } catch (e: Throwable) {
        if (numberOfTries > 1)
            return retry(numberOfTries - 1, block)
        else
            throw e
    }
}

```

---

<div class="post-metadata">

**Author:** ![gidds](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/gidds/32/10865_2.png) [@gidds](https://discuss.kotlinlang.org/u/gidds)\
**Post date:** [May 4, 2024, 7:17am UTC](https://discuss.kotlinlang.org/t/make-it-easy-to-repeat-something-until-it-succeeds-but-at-most-n-times/8097/12 "2024-05-04T07:17:15Z")

</div>

If appropriate, you could give a default value for the number of tries, making calls even simpler.

One minor drawback of the tail-recursive version is that it doesn’t track how many attempts have been made so far (only the number remaining), so it can’t log that. You could do that with an additional parameter (defaulting to 0).

---

<div class="post-metadata">

**Author:** ![dalewking](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/dalewking/32/1496_2.png) [@dalewking](https://discuss.kotlinlang.org/u/dalewking)\
**Post date:** [May 4, 2024, 3:22pm UTC](https://discuss.kotlinlang.org/t/make-it-easy-to-repeat-something-until-it-succeeds-but-at-most-n-times/8097/13 "2024-05-04T15:22:05Z")

</div>

I just this week refactored some code that was not retrying on errors but was polling for a job on the server to complete and increasing delay between polls and here is basically what I did:

```auto
    private suspend fun pollJob(jobId: String, maxAttempts: Int) =
        (0..<maxAttempts)
            .asFlow()
            .onEach { delay(it.seconds) }
            .map { getJobResult(jobId) }
            .firstOrNull { it.status != PROCESSING }

```

It returns null if the job never completed.

Thinking how one could make this more reusable i could have done this (with and without suspend)::

```auto
    private fun <T> retry(maxAttempts: Int, getResult: (Int) -> T?) =
        (1..maxAttempts)
            .asSequence()
            .map(getResult)
            .filterNotNull()
            .firstOrNull()

    private suspend fun <T> retry(maxAttempts: Int, getResult: suspend (Int) -> T?) =
        (1..maxAttempts)
            .asFlow()
            .map(getResult)
            .filterNotNull()
            .firstOrNull()

```

Which i could have used like this:

```auto
    retry(maxAttempts = 5) { attempt ->
        delay((attempt - 1).seconds)
        getJobResult(jobId).takeUnless { it.status == PROCESSING }
    }

```

Something like this could be used for the examples in the original post:

```auto
    retry(3) { doSomething().takeUnless { somethingFailed() } }

    retry(3) {
        runCatching { doSomething() }
              .takeUnless { it.exceptionOrNull() is BadException }
              ?.getOrThrow()
    }

```

---

<div class="post-metadata">

**Author:** ![jacekgaw](https://avatars.discourse-cdn.com/v4/letter/j/db5fbb/32.png) [@jacekgaw](https://discuss.kotlinlang.org/u/jacekgaw)\
**Post date:** [November 25, 2025, 12:56pm UTC](https://discuss.kotlinlang.org/t/make-it-easy-to-repeat-something-until-it-succeeds-but-at-most-n-times/8097/14 "2025-11-25T12:56:27Z")

</div>

My version:

```auto
suspend inline fun <T, R> T.repeatUntil(times: Int, delay: Duration, block: () -> R): R {
    var i = 0
    var result: Result<*>

    do {
        result = runCatching(block = block)

        if (result.isSuccess) return result.getOrThrow()

        delay(delay)
    } while (i++ < times)

    throw result.exceptionOrNull() ?: Exception()
}

```
