arzhang
arzhang

Reputation: 15

How iterate until the condition is met using kotlin and functional programming?

I'm using an API that returns a text like this: BW3511,HGP,ITP,Canceled,32. I have to continue fetching until I get a response that is not "Canceled".

this code fetches the data:

   val flightResponse = async {
        println("Started fetching Flight info.")
        client.get<String>(FLIGHT_ENDPOINT).also {
                println("Finished fetching Flight info.")
        }
    }

the client.get can only be called within The coroutineScope body, also the flightResponse type is Deferred<String>.

check if it is canceled:

  fun isCanceled(
            flightResponse: String
        ) : Boolean {
            val (_, _, _, status, _) = flightResponse.split(",")
            return status == "Canceled"
        }

how can I repeat client.get<String>(FLIGHT_ENDPOINT) until my condition is met using Functional Programming style?

I tried using takeIf but I have to get at least one result and it cannot be a nullable type.

Upvotes: 0

Views: 817

Answers (1)

broot
broot

Reputation: 28322

As said in the comment by @Jorn, this looks like an overuse of functional style. It can be implemented by a simple loop and this way it will be probably more clear to the reader:

fun getNextNotCancelled() {
    while (true) {
        val response = client.get<String>(FLIGHT_ENDPOINT)
        if (!isCanceled(response)) return response
    }
}

If your real case is more complex, so you have several filters, etc. or for any other reason you really need to do this declaratively, then you need to create some kind of an infinite generator. For classic synchronous code that means sequence and for asynchronous - flow.

Example using a sequence:

generateSequence { client.get<String>(FLIGHT_ENDPOINT) }
    .first { !isCanceled(it) }

Flow:

flow {
    while (true) {
        emit(client.get<String>(FLIGHT_ENDPOINT))
    }
}.first { !isCanceled(it) }

As you said you use coroutines, I assume you would like to go for the latter. And as you can see, it is pretty similar to our initial loop-based approach, only more complicated. Of course, we can create a similar generateFlow() utility function and then it would be shorter.

Upvotes: 2

Related Questions