코트린 suspend method는 suspend method 안에서 부를 수 있다.
이는 코틀린 코드를 자바 코드로 바꾸어 보면 이유를 유추해 볼 수 있다.
suspend fun a() {
b()
}
suspend fun b() {
}
위 코드를 자바 코드로 바꾸어 보면
@Nullable
public static final Object a(@NotNull Continuation $completion) {
Object var10000 = b($completion);
return var10000 == IntrinsicsKt.getCOROUTINE_SUSPENDED() ? var10000 : Unit.INSTANCE;
}
@Nullable
public static final Object b(@NotNull Continuation $completion) {
return Unit.INSTANCE;
}
이렇듯 Continuation에서 context를 통해 코틀린 런타임이 필요로 하는
정보를 전달하면서 전파해 나아가는 방식이다.
그렇다면 컴포저블은 어떤 형태를 띄고 있을 것인가
@Composable
fun a() {
b()
}
@Composable
fun b() {
}
를 바꾸어 보면 다음과 같다.
fun a($composer: Composer<*>) {
$composer.start(123)
b($composer)
$composer.end()
}
fun b($composer) {
'''
}
컴포저블도 마찬가지로 composer를 앞으로 전파해 나아가는
위에서 확인한 suspend와 마찬가지의 형태를 띄고 있다.
따라서, Composable도 Composable내부에서만 사용가능한 것이다.
그런데, 아래와 같은 코드는 어떻게 가능한 것인가?
@Composable
fun a(bs: MutableList<Int>) {
bs.forEach {
b()
}
}
@Composable
fun b() {
}
이렇듯 forEach의 람다에 컴포저블을 불러도 에러 메세지를 보이지 않는다.
이것은 forEach를 볼 필요가 있다.
public inline fun <T> Iterable<T>.forEach(action: (T) -> Unit): Unit {
for (element in this) action(element)
}
그렇다 다른 Collection 함수들처럼 inline으로 정의가 되어있다.
inline은 컴파일러가 호출 함수의 코드를 직접 복사에서 붙여 넣기 때문에
위의 b컴포저블은 사실상 a컴포저블에서 불리게 된 것이다.
이렇듯 컴포저블에서 코틀린 로직의 사용이 필요할 때는 inline method를 사용함으로서 해결할 수 있다.