I read that you shouldn't inline large functions. ...
# announcements
f
I read that you shouldn't inline large functions. Is it better to not use inline here?
Copy code
inline fun <ResultType, RequestType> networkBoundResource(
    crossinline query: () -> Flow<ResultType>,
    crossinline fetch: suspend () -> RequestType,
    crossinline saveFetchResult: suspend (RequestType) -> Unit,
    crossinline onFetchSuccess: () -> Unit = { },
    crossinline onFetchFailed: (Throwable) -> Unit = { },
    crossinline shouldFetch: (ResultType) -> Boolean = { true }
) = flow {
    val data = query().first()

    val flow = if (shouldFetch(data)) {
        emit(Resource.Loading(data))

        try {
            saveFetchResult(fetch())
            onFetchSuccess()
            query().map { Resource.Success(it) }
        } catch (t: Throwable) {
            onFetchFailed(t)
            query().map { Resource.Error(t, it) }
        }
    } else {
        query().map { Resource.Success(it) }
    }
    emitAll(flow)
}
n
Main reason to use inline is for lambdas to get non local control flow, reified type parameters, and reduce overhead for very small functions
If none of those apply why use inline?
Not technically related but with so many arguments you may want to just have an interface; users will still be able to call it inline conveniently with
object
but can also factor our and group together their logic with a class if they prefer
h
the reason for it is inline functions get copied any time they get called, so it can massively increase your jar size if you are zealous in its use. Nir outlines exactly the times where it should be consideredd.
Yeah I agree, not much logic in that function -- an interface makes way more sense.
f
@Nirwell if it should be inline or not is my question
so if I wanna keep that function above (and not turn it into an interface) you would suggest to remove the inline keyword?
as far as I understand,
inline
makes the code more efficient? And the code growth seems negligible to me
h
Not necessarily always. Inlining very small functions is often beneficial and makes code efficient, but inlining can have effects on obviously the executable, but also things like the cache -- both of these attributes is not just about kotlin but any language...otherwise the compiler would just inline everything
f
ok thank you, I'll remove the inline then
h
np, the rules nir listed is good for the basics when thinking, should I inline, as you learn more you will be able to make more nuanced decisions.
n
To be clear wrt to the interface I'm talking about the argument to the function
Copy code
interface NetworkResourceHandler<ResultType, ResourceType> {
    fun query(): Flow<ResultType>
    suspend fun fetch(): RequestType
    suspend fun saveFetchResult(requestType: RequestType)
    fun onFetchSuccess() { }
    fun onFetchFailed(throwable: Throwable) {}
    fun shouldFetch(resultType: ResultType): Boolean { true }
) 
fun <ResultType, RequestType> networkBoundResource(handler: NetworkResourceHandler<ResultType, RequestType>) { ... }
that might be some personal preferences but that is an awful lot of functions, the inline
object
syntax looks just as good as calling with lambdas IMHO, but also having the ability to just write a class that inherits the interface is nice
f
thank you for the tip!
👍 1