Home > Net >  What is the different between method A call method B many times vs method B call itself many times (
What is the different between method A call method B many times vs method B call itself many times (

Time:11-15

Approach #1: Recursion

// Recursion
suspend fun findAndHandleFile(fileName: String, timeoutMs: Long, startTiming: Long, intervalMs: Long = 3000) {
    val file = findWithFileName(fileName)
    if (file != null) {
        handleFile(file)
    } else {
        val passedTime = System.currentTimeMillis() - startTiming
        if (passedTime < timeoutMs) {
            delay(internalMs)
            findAndHandleFile(fileName, timeoutMs, startTiming)
        }
    }    
}

Approach #2:

suspend fun findAndHandleFile(fileName: String, timeoutMs: Long, startTiming: Long, intervalMs: Long = 3000) {
    val file = findFile(fileName, timeoutMs, startTiming, 3000)
    if (file != null) {
        handleFile(file)
    }
}
suspend fun findFile(fileName: String, timeoutMs: Long, startTiming: Long, intervalMs: Long = 3000): File? {
    var file = findWithFileName(fileName)
    while(file == null && System.currentTimeMillis() < startTiming   timeoutMs) {
        delay(intervalMs)
        file = findWithFileName(fileName)
    }
}

Currently, I use Approach #1 and still not see any problem with it (don't cause StackOverflowError)

  • It works well during an hour

I want to refactor from Approach #1 to Approach #2, but still not clearly sure what it is benefit from it.

My question for above approaches when running it on Android app:

  • is Approach #2 more effective than Approach #1? what are they?

Hope receiving sharing from people. Thanks

CodePudding user response:

Your approach (#1) is not recursion. The point of recursion is not to call the same function from it self, it's solving the same problem but with less complexity repeatedly until you reach your base state. For example, recursion with the mathematical operand - !.

5! can be written either as:

int total=1;
for(int i=1; i<num;i  )
    total*=i;

or it can be written, recursively, like so:

private int recursive(int n)
     if(n == 0)
          return 1;
     else
          return n*(recursive(n-1));

What you are using is a delay mechanism to call your self if your operation failed. That's general use with no relation to recursion.

CodePudding user response:

Recursion carries the risk of increased memory use and risk of a stack overflow, unless you are using tail recursion. In Kotlin, for reasons I'm not sure of, you have to explicitly mark the function with the tailrec keyword to take advantage of tail recursion. I think your function is a candidate.

However, the point of using recursion is to make code simpler and easier to follow. Usually that means you are breaking a problem down into a smaller version of itself. Using it for a timed loop just makes your code more complicated, so this is not a good use for recursion.

Your code could be rewritten like this, and I think the logic is easier to understand:

suspend fun findAndHandleFile(fileName: String, timeoutMs: Long, startTiming: Long, intervalMs: Long = 3000) {
    while (System.currentTimeMillis() < startTiming   timeoutMs) {
        val file = findWithFileName(fileName)
        if (file != null) {
            handleFile(file)
            break
        }
        delay(intervalMs)
    }
}

Also, you could take advantage of withTimeoutOrNull and a flow to make it (in my opinion) even easier to follow the logic:

suspend fun findAndHandleFile(fileName: String, timeoutMs: Long, intervalMs: Long = 3000) {
    val fileMonitor = flow<File?> {
        while(true) {
            emit(findWithFileName(fileName))
            delay(intervalMs)
        }
    }
    withTimeoutOrNull(timeoutMs) {
        handleFile(fileMonitor.filterNotNull().first())
    }
}
  • Related