Caruso
Caruso

Reputation: 31

Lambda as a function parameter -> accept methods only from particular class

I wish to find solution to force emit(S.() -> S) function to accept as parameters, only methods from generic S class. Current solution accepts all lambda methods which returns S. S is a generic class which has methods to reduce/modify own parameters. I want only those methods to be called in emit. It guarantees that every method passed to emit is "pure function" (all methods in S are pure)

val _uiState = MutableLiveData<S>() 
var state: S
fun emit(reduction: S.() -> S) {
        state = reduction.invoke(state)
        if (_uiState.value != state) {
            _uiState.postValue(state)
        }
    }

Upvotes: 1

Views: 148

Answers (1)

Alexey Romanov
Alexey Romanov

Reputation: 170723

For this, functions simply aren't an appropriate type. I'd declare a type whose values correspond to methods of S, so

class S { 
    fun method1(x: String): S = ...
    fun method2(): S = ...
    ...

    sealed class Transform {
        operator fun invoke(s: S): S = when(this) {
            is Method1 -> s.method1(x)
            is Method2 -> s.method2()
            ...
        }

        class Method1(val x: String) : Transform
        object Method2 : Transform
    }
}

fun emit(reduction: S.Transform) {
    state = reduction.invoke(state)
    if (_uiState.value != state) {
        _uiState.postValue(state)
    }
}

With some effort, Transform can be auto-generated (e.g. using an annotation processor, as you mention in a comment), but it may not be worth it depending on how many classes and methods you need to handle and how often they change.

Upvotes: 2

Related Questions