What happens if local functions are declared inside loop

I have a code like below, which declares local functions inside a for-loop.

Are there any problems or differences compared to declaring outside the for-loop?

I know the result printing out is the same. I am asking about something else, for example, memory consumption, performance or the result might be wrong in some cases.

fun main() {
    fizzbuzz(1, 10)
}

fun fizzbuzz(start: Int, end: Int) {
    for (k in start..end) {
      // local functions inside loop?
      fun isFizz(): Boolean = k % 3 == 0
      fun isBuzz(): Boolean = k % 5 == 0

      when {
        isFizz() && isBuzz() -> println("Fizz Buzz")
        isFizz() -> println("Fizz")
        isBuzz() -> println("Buzz")
        else -> println(k)
      }
    } 
}
1 Like

It all depends on what we need to access inside the function. Kotlin compiler is smart, it creates closures only if needed and captures only the data we need.

In your specific case we use k inside the function, so we have to capture it. That means with each iteration we instantiate a new object passing k to it. If we pass k as an argument, the compiler will create a singleton/global function. It doesn’t even matter if it is defined inside or outside the loop.

Theoretically, the latter is a much better option performance-wise as it avoids unnecessary heap allocations. In practice, we can never know without running benchmarks. It is possible the JVM optimizes the first.

2 Likes

I also understood like you explained. Thanks for your confirmation!

This is interesting.


So, the best practice is to avoid local functions inside loop if possible.

I think in general, avoid creating lambdas where you can. Obviously that doesn’t mean you never create lambdas in place, like when using map or forEach, but where it makes sense… create the lambda once, and re-use it. I don’t know how good the compiler is at optimising this stuff, but we as humans can apply a bit of common sense and avoid unnecessary duplication of work.

1 Like

Bear in mind that as well as the Kotlin compiler being quite smart, so is the Java runtime — for example, some JVMs can use escape analysis to convert heap allocations to much cheaper stack allocations. So a function definition or lambda in a loop may not be as expensive as it might seem.

While it’s good not to write inefficient code, it’s generally more important to write clear, understandable, maintainable code. For one thing, developer time is valuable too; it may not be worth spending hours or days of a developer’s time to save milliseconds of runtime.

For another, sometimes the performance is far from obvious (as mentioned above), and what seem like optimisations may have little effect, or even harm performance.

And for a third, it’s generally only a very small part of your program that takes most of the runtime; optimising the rest would have little effect.

For all those reasons, it’s generally not worth trying to optimise your code unless you’ve done performance testing and identified specific performance problems — and even then, you must test your changes to make sure they make a significant improvement.

(In general, algorithms make much more difference than low-level coding issues: for example, replacing a quadratic algorithm with a linear one is likely to make vastly more difference than the sorts of optimisations this page discusses. So get the algorithms right, and code them clearly, but don’t worry about low-level optimisation unless/until you identify issues.)

5 Likes

Completely agree. Thanks for sharing your opinions, @gidds, @Skater901!