Kotlin Flow: Why the function combine() can only take maximum 5 flows in parameters

Viewed 994

I notice the combine() function can only take maximum 5 flows in parameters

public fun <T1, T2, T3, T4, T5, R> combine(
    flow: Flow<T1>,
    flow2: Flow<T2>,
    flow3: Flow<T3>,
    flow4: Flow<T4>,
    flow5: Flow<T5>,
    transform: suspend (T1, T2, T3, T4, T5) -> R
): Flow<R> = combineUnsafe(flow, flow2, flow3, flow4, flow5) { args: Array<*> ->
    transform(
        args[0] as T1,
        args[1] as T2,
        args[2] as T3,
        args[3] as T4,
        args[4] as T5
    )
}

Is there any particular reason behind this? (or maybe not?)

If I define a combine() taking 6 parameters in my local file, e.g.

private fun <T1, T2, T3, T4, T5, T6, R> combine(
    flow: Flow<T1>,
    flow2: Flow<T2>,
    flow3: Flow<T3>,
    flow4: Flow<T4>,
    flow5: Flow<T5>,
    flow6: Flow<T6>,
    transform: suspend (T1, T2, T3, T4, T5, T6) -> R
): Flow<R> = combine(flow, flow2, flow3, flow4, flow5, flow6) { args: Array<*> ->
    transform(
        args[0] as T1,
        args[1] as T2,
        args[2] as T3,
        args[3] as T4,
        args[4] as T5,
        args[5] as T6
    )
}

Could this have any potential issues?

Thank you!

3 Answers

I guess type-safe combine extensions (for 2-5 flows) is just a syntax sugar for common combine(vararg flows). So there is no penalty for implementation combine for 6+ flows.

Implementation combine taking 6 flows without any cost.

inline fun <T1, T2, T3, T4, T5, T6, R> combine(
    flow: Flow<T1>,
    flow2: Flow<T2>,
    flow3: Flow<T3>,
    flow4: Flow<T4>,
    flow5: Flow<T5>,
    flow6: Flow<T6>,
    crossinline transform: suspend (T1, T2, T3, T4, T5, T6) -> R
): Flow<R> {
    return kotlinx.coroutines.flow.combine(flow, flow2, flow3, flow4, flow5, flow6) { args: Array<*> ->
        @Suppress("UNCHECKED_CAST")
        transform(
            args[0] as T1,
            args[1] as T2,
            args[2] as T3,
            args[3] as T4,
            args[4] as T5,
            args[5] as T6,
        )
    }
}

This is original approach in implementation combine: enter image description here

You can using the base combine function in kotlin lib:

   public inline fun <reified T, R> combine(
        vararg flows: Flow<T>,
        crossinline transform: suspend (Array<T>) -> R
    ): Flow<R> = flow {
        combineInternal(flows, { arrayOfNulls(flows.size) }, { emit(transform(it)) })
    }

Use cast if combining different types of flow, like:

val myDataModel= combine(
    firstParamBooleanFlow,
    secondParamBooleanFlow,
    thirdParamStringFlow,
    fourthParamStringFlow,
    fifthParamIntFlow,
    sixthParamIntFlow
){array ->
    DataModel( 
        isTrue = array[0] as Boolean && array[1] as Boolean,
        title = "${array[2]} - ${array[3]}",
        count = array[4] as Int + array[5]  as Int
        )
}

You can combine them like this:

fun <T1, T2, T3, T4, T5, T6, R> combine(
    flow: Flow<T1>,
    flow2: Flow<T2>,
    flow3: Flow<T3>,
    flow4: Flow<T4>,
    flow5: Flow<T5>,
    flow6: Flow<T6>,
    transform: suspend (T1, T2, T3, T4, T5, T6) -> R
): Flow<R> = combine(
    combine(flow, flow2, flow3, ::Triple),
    combine(flow4, flow5, flow6, ::Triple)
) { t1, t2 ->
    transform(
        t1.first,
        t1.second,
        t1.third,
        t2.first,
        t2.second,
        t2.third
    )
}
Related