• 목록 (128)
    • Android (62)
    • Back-End (2)
    • Java (3)
    • Kotlin (16)
    • CS (7)
    • 개발 서적 (12)
    • 문제 풀이 (26)

최근 글

티스토리

전체 방문자
오늘
어제
hELLO · Designed By 정상우.
MJ_94

한 우물만 파는 기술 블로그

Android

[Android] Compose 컴파일러 - (7)

2024. 11. 21. 12:26

디폴트 매개변수

Compile 타임에 각 Composable 함수에 $default라는 메타데이터가 매개변수로 추가된다.

Composes는 Composable 함수에서 각 매개변수의 인덱스를 비트마스킹 기법으로 매핑하는 $default 매개변수를 통하여 디폴트 값을 가진 매개변수를 나타낸다.

이는 위에서 살펴본 $changed 매개변수와 동일한 방식으로 수행된다.

디폴트 값을 가지는 n개의 매개변수당 $default 매개변수를 하나씩 가지는데, $default 매개변수는 Composable 함수의 각 입력 매개변수에 대해 호출자 쪽에서 값을 제공하는지의 여부를 제공하고, 최종적으로 디폴트 값을 사용해야 할지, 호출자 쪽에서 넘겨주는 값을 사용해야 할지 결정한다.

아래의 코드에서는 $default 비트마스크 매개변수가 주입되기 전과 후의 Composable 함수의 형태와 디폴트 매개변수 값을 읽고 사용하는 사례를 명확하게 보여준다.

//Before compiler
@Composable
fun A(x: Int = 0) {
	f(x)
}

//After compiler
@Composable
fun A(x: Int, $changed: Int, $default: Int) {
	val x = if ($default and 0b1 != 0) 0 else x
	f(x)
}

$changed 매개변수의 사례와 마찬가지로 비트의 조작이 수행되며, 디폴트 값에 대한 비교는 단순히 $default 매개변수를 사용한 비트마스킹을 통해 확인하고, x에 대해 전달된 값을 디폴트 값(0)으로 설정하거나 원본 값을 유지한다.

컨트롤 플로우 그룹 생성

Compose Compiler는 각 Composable 함수의 본문에 그룹을 삽입하며, 그 그룹의 유형은 아래와 같다.

  • 교체 가능한 그룹
  • 이동 가능한 그룹
  • 재시작 가능한 그룹

Composable 함수는 Runtime시에 그룹을 생성하며, 생성된 그룹은 현 상태에 대한 정보를 보존한다.

이를 통해 composition은 그룹에 교체가 필요할 때 Composable의 정체성을 유지하고 데이터를 이동시킬 때, 또는 recomposition 중에 함수를 재시작할 때 쓰여진 데이터를 어떻게 처리해야 할지 알 수 있다.

또한 그룹은 Composable 함수의 호출 위치에 대한 정보를 가지고 있으므로 이를 통해 앞서 살펴봤던 위치 기억법을 가능하게 한다.

교체 가능한 그룹

Composable 람다식의 본문에 $composer, $key, Composable 람다식의 실체와 같은 값을 매개변수로 받는 Composable 팩토리 함수 호출을 삽입함으로써 Composable 람다식이 자동으로 감싸진다는 걸 배웠었다.

아래의 코드는 방금 언급한 팩토리 함수가 어떻게 생겼는지 보여준다.

fun composableLamda(
	composer: Composer,
	key: Int,
	tracked: Boolean,
	block: Any
) : ComposableLamda {
	composer.startReplaceableGroup(key)

	val slot = composer.rememberedValue()
	val result = if (slot === Composer.Empty) {
		val value = ComposableLamdaImpl(key, tracked)
			composer.updateRememberedValue(value)
				value
			} else {
				slot as ComposableLamdaImpl
		}
		
	result.update(block)
	composable.endReplceableGroup()
	return result
}

위 팩토리 함수는 Composable 람다식을 위해 호출되며 동작 방식은 먼저 key로 교체 가능한 그룹을 시작하고, 중간에 모든 텍스트 범위를 감싸고, 마지막으로 그룹을 닫는다.

이는 시작과 끝 호출 사이에서 composition을 관련성 있는 정보로 업데이트하는 것으로 우리가 래핑하는 람다식이다.

지금까지는 Composable 람다식이지만, 다른 Composable 함수의 호출 또한 동일하게 처리된다. 이어지는 아래의 코드는 @NonRestartableComposable 어노테이션으로 재시작이 불가능하다고 마킹된 Composable 함수의 코드가 어떻게 변화되는지 보여준다.

// Before Compiler
@NonRestartableComposable
@Composable
fun Foo(x: Int) {
	Wat()
}

//After Compiler
@NonRestartableComposable
@Composable
fun Foo(x: Int, %composer: Composer?, %changed: Int) {
	%composer.startReplaceableGroup(<>)
	Wat(%composer, 0)
	%composer.endReplaceableGroup()
}

위 Composable 함수 또한 composition에 저장하기 위한 교체 가능한 그룹을 생성한다.

그룹은 일종의 트리와 같으며 각 그룹은 원하는만큼의 그룹을 자식으로 가질 수 있다. 위의 예시에서 Wat() 함수 또한 Composable 함수라면, Compiler는 해당 함수에 대해서도 그룹을 삽입한다.

저작자표시 비영리 변경금지 (새창열림)

'Android' 카테고리의 다른 글

[Android] Compose 런타임 - (1)  (0) 2024.11.25
[Android] Compose 컴파일러 - (8)  (0) 2024.11.22
[Android] Compose 컴파일러 - (6)  (0) 2024.11.20
[Android] Compose 컴파일러 - (5)  (0) 2024.11.19
[Android] Compose 컴파일러 - (4)  (0) 2024.11.18
    'Android' 카테고리의 다른 글
    • [Android] Compose 런타임 - (1)
    • [Android] Compose 컴파일러 - (8)
    • [Android] Compose 컴파일러 - (6)
    • [Android] Compose 컴파일러 - (5)
    MJ_94
    MJ_94
    안드로이드, 개발 관련 기술 블로그

    티스토리툴바