Android/Kotlin

Kotlin에서의 함수 컬러링이란? suspend와 composable 함수

배준형 2024. 10. 15. 20:39

사진: UnsplashRobert Katzki

 

 

Compose에 대해 공부를 하다 보니 함수 컬러링이란 개념에 대해 알게 되었습니다. 이번 게시글에서는 함수 컬러링에 대해 알아보고자 합니다.


 

 

 

함수의 색상


겉으로 표시되고 있지는 않지만 모든 함수에는 색상이 존재합니다. 우리는 특정 조건을 통해 함수의 색상을 지정할 수 있습니다.

 

아래와 같이 빨간색과 파란색 함수가 존재한다고 가정해 보겠습니다.

fun red() {
}

fun blue() {   
}

 

 

이런 여러가지의 함수들에 존재하는 단 하나의 규칙은 '파란색 함수는 어디에서든 호출할 수 있지만, 빨간색 함수는 빨간색 함수 안에서만 호출할 수 있다.` 다는 것입니다.

fun red2() {
    red()
    blue()
}

fun blue2() {
    red() // x 호출 불가능
    blue()
}

 

이 규칙으로 파란색 함수에서 빨간색 함수를 호출할 수 없게 됩니다.

 

 

 

suspend 함수의 색상


규칙 하나를 추가하기만 했는데도 파란색 함수에 비해 빨간색 함수는 매우 호출하기 어려워졌습니다.

 

이런 불편함을 야기하는 빨간색 함수의 가장 흔한 예는 바로 코루틴의 suspend 함수입니다. 

suspend fun red() {
}

fun blue() {
}

 

 

코루틴에서는 그 기능을 수행하기 위해서는 `continuation`이라는 파라미터가 필요합니다. `continuation` 파라미터는 개발자가 이를 직접 넣어주는 것이 아니라 컴파일 과정에서 생성되게 하는데, 이를 위해 Kotlin에서는 `suspend`라는 키워드를 사용하여 함수를 색칠해 컴파일러가 판단할 수 있게 하는데, 이 과정을 바로 함수 컬러링이라 합니다.

 

 

 

Composable 함수의 색상


Compose 또한 함수를 @Composable로 표시하여 색칠합니다. Composable 함수는 반드시 Compose 환경에서만 호출되어야 합니다.

@Composable
fun Greeting(name: String) {
    Text(text = "Hello, $name!")
}

 

 

코루틴과 마찬가지로 Compose는 UI를 그리기 위해서 Compose 런타임에서 사용하는 특별한 파라미터인 `Composer`를 전달받습니다. 그렇기 때문에 Compose 또한 함수 컬러링이 필요합니다.

 

 

 

함수 컬러링 쉽게 설명하기


함수 컬러링은 쉽게 말하자면 하나의 코드 파일 안에 여러 종류의 Context가 섞여 있을 때 생기는 문제나 이를 다루는 방법을 말합니다. 여기서 Context는 코드가 실행되거나 처리되는 방식의 차이라고 볼 수 있습니다.

 

예를 들어, 어떤 함수가 일반 코드에서 바로 실행되지 않고, 코루틴 환경에서만 실행되어야 할 때, 그 함수에 suspend 같은 표시를 붙여 특별히 구분합니다. 이처럼 서로 다른 "세계"에 속한 코드를 쉽게 구분할 수 있도록 색을 칠하듯 표시하는 것을 함수 컬러링이라고 부를 수 있습니다.

 

 

 

함수 컬러링의 핵심


함수 컬러링은 결국 코드를 다른 세계에서 실행되는 코드들을 명확히 구분하고, 컴파일러가 오류를 알려줄 수 있게 하기 위한 과정입니다.

 

함수 컬러링의 기본 규칙인 “빨간색 함수는 빨간색 함수 안에서만 호출할 수 있다”는 suspend와 @Composable 함수에 그대로 적용됩니다.

 

즉, suspend 함수는 코루틴 Context에서만, @Composable 함수는 Compose Context에서만 호출 가능합니다.

 

그럼 suspend나 Compose가 아닌 함수에서는 어떻게 이런 함수들을 호출해야 할까요?  바로 Context 전환을 통해야 합니다.

 

suspend 함수 호출 방법: 일반 함수 → 코루틴 Context로 전환

일반 함수에서 suspend 함수를 호출하기 위해서는 코루틴 빌더를 사용해서 Context를 전환해야 합니다. 코루틴 빌더로는 `launch`, `async` 또는 `runBlocking` 등이 존재합니다.

suspend fun fetchData(): String {
    delay(1000L)  // 비동기 처리
    return "Hello, Coroutine!"
}

fun main() {
    // 코루틴을 시작해 suspend 함수 호출
    runBlocking {
        val data = fetchData()
        println(data)
    }
}

 

 

@Composable 함수 호출 방법: 일반 함수 → Compose Context로 전환

일반 함수에서 @Composable 함수를 호출할 수 없기에 `setContent`를 사용하여 Compose Context로 전환합니다.

@Composable
fun Greeting(name: String) {
    Text(text = "Hello, $name!")
}

fun main() {
    // Compose 환경으로 전환
    setContent {
        Greeting(name = "Alice")
    }
}

 

 

inline 연산자로 비슷한 효과 만들기

`inline` 함수는 컴파일 시점의 해당 함수의 본문이 호출된 위치에 직접 삽입되므로 Compose 런타임의 Context 내에서 실행될 수 있습니다.

@Composable
fun SpeakerList(speakers: List<Speaker>) {
  Column {
    speakers.forEach {
      Speaker(it)
    }
  } 
}

 

 

 

 

Reference

 

What Color is Your Function? – journal.stuffwithstuff.com

I don’t know about you, but nothing gets me going in the morning quite like a good old fashioned programming language rant. It stirs the blood to see someone skewer one of those “blub” languages the plebians use, muddling through their day with it be

journal.stuffwithstuff.com

 

KEEP/notes/code-coloring.md at master · Kotlin/KEEP

Kotlin Evolution and Enhancement Process. Contribute to Kotlin/KEEP development by creating an account on GitHub.

github.com