Repository: InsertKoinIO/koin
File: projects/core/koin-core/src/commonMain/kotlin/org/koin/core/module/Module.kt (Kotlin)

Code before:
    scopeQualifier: Qualifier = rootScopeQualifier,
): FactoryInstanceFactory<T> {
    val def = _createDefinition(Kind.Factory, qualifier, definition, scopeQualifier = scopeQualifier)
    return FactoryInstanceFactory(def)
}

@KoinInternalApi
inline fun <reified T> _scopedInstanceFactory(
    qualifier: Qualifier? = null,
    noinline definition: Definition<T>,
    scopeQualifier: Qualifier,
): ScopedInstanceFactory<T> {
    val def = _createDefinition(Kind.Scoped, qualifier, definition, scopeQualifier = scopeQualifier)
    return ScopedInstanceFactory(def)
}

/**
 * Help write list of Modules
 */
operator fun List<Module>.plus(module: Module): List<Module> = this + listOf(module)

/**
 * Run through the module list to flatten all modules & submodules
 */
@OptIn(KoinInternalApi::class)
fun flatten(modules: List<Module>): Set<Module> {    
    val flatten = HashSet<Module>()
    val stack = ArrayDeque<Module>(modules)

    while (stack.isNotEmpty()) {
        val current = stack.removeLast()
        flatten.add(current)
        current.includedModules.forEach {
            if (it !in flatten) {
                stack.addLast(it)
            }
        }
    }

    return flatten
}


Review comment (suggestion):
That is nice and it is very similar to the original `flatten` function I wrote when introducing the `includes` feature [here](https://github.com/InsertKoinIO/koin/pull/1210/files#diff-e772f920a0a8f0cef44eb951fbb66027f8ee3b191a8cd91bc25b5f188ffaf837R338-R357) (for context).

I would consider add a comment explaining why we are doing that way and linking to both PRs for context.

Code after:
    scopeQualifier: Qualifier = rootScopeQualifier,
): FactoryInstanceFactory<T> {
    val def = _createDefinition(Kind.Factory, qualifier, definition, scopeQualifier = scopeQualifier)
    return FactoryInstanceFactory(def)
}

@KoinInternalApi
inline fun <reified T> _scopedInstanceFactory(
    qualifier: Qualifier? = null,
    noinline definition: Definition<T>,
    scopeQualifier: Qualifier,
): ScopedInstanceFactory<T> {
    val def = _createDefinition(Kind.Scoped, qualifier, definition, scopeQualifier = scopeQualifier)
    return ScopedInstanceFactory(def)
}

/**
 * Help write list of Modules
 */
operator fun List<Module>.plus(module: Module): List<Module> = this + listOf(module)

/**
 * Run through the module list to flatten all modules & submodules
 */
@OptIn(KoinInternalApi::class)
fun flatten(modules: List<Module>): Set<Module> {
    // This is actually a DFS traversal of the module graph,
    // but we're using a stack instead of recursion to avoid stack overflows and performance overhead.

    val flatten = HashSet<Module>()
    val stack = ArrayDeque(modules)

    while (stack.isNotEmpty()) {
        val current = stack.removeLast()

        // If the module is already in the set, that means we've already visited it, so we can skip it.
        if (!flatten.add(current)) {
            continue
        }

        // Add all the included modules to the stack if they haven't been visited yet.
        for (module in current.includedModules) {
            if (module !in flatten) {
                stack += module
            }
        }
    }

    return flatten
}