안드로이드 코틀린 언어 학습 노트 목차

DSL·연산자 오버로딩·중위 함수 — 읽기 좋은 코드를 만드는 문법

코틀린은 코드를 자연어처럼 읽히게 하는 문법을 갖췄다 — 연산자 오버로딩(+·[]를 내 타입에), 중위 함수(1 to 2), 그리고 수신자가 있는 람다로 만드는 DSL(도메인 특화 언어). Jetpack Compose의 UI 선언, Gradle Kotlin DSL, Coroutine 빌더가 모두 이 문법들의 산물이다. (출처: Kotlin Docs — Operator overloading / Type-safe builders / Kotlin in Action 2e Ch 13.)

연산자 오버로딩 — 기호를 내 타입에

operator 키워드를 붙인 약속된 이름의 함수연산자를 내 타입에 정의한다.

data class Vec(val x: Int, val y: Int) {
    operator fun plus(o: Vec) = Vec(x + o.x, y + o.y)   // a + b
    operator fun get(i: Int) = if (i == 0) x else y      // a[0]
    operator fun compareTo(o: Vec) = ... // a < b
}
Vec(1,2) + Vec(3,4)        // Vec(4,6)  — plus 호출
vec[0]                      // get(0)

주요 매핑 — plus/minus/times(+ - *), get/set([]), invoke(obj()), contains(in), compareTo(< > <= >=), rangeTo(..), inc/dec(++ --). 남용하면 오히려 헷갈리니의미가 직관적일 때만(벡터·행렬·금액·기간 등).

중위 함수 — 점·괄호 없이

infix 함수는 a.foo(b)a foo b 쓰게 한다(수신자·인자 하나).

infix fun Int.times(s: String) = s.repeat(this)
2 times "Bye "             // "Bye Bye "

mapOf("a" to 1)            // to 도 infix 함수 (Pair 생성)
if (x in 1..10) ...        // .. 는 rangeTo 연산자

수신자 있는 람다 — DSL의 핵심

DSL을 가능케 하는 핵심 문법이 수신자가 있는 람다(lambda with receiver)A.() -> Unit 타입의 람다는 블록 안에서 A의 멤버를 this 없이 부른다. apply { }가 바로 이것이다.

class HtmlBuilder {
    val sb = StringBuilder()
    fun p(text: String) { sb.append("<p>$text</p>") }
}
// 수신자 있는 람다를 받는 빌더 함수
fun html(block: HtmlBuilder.() -> Unit): String =
    HtmlBuilder().apply(block).sb.toString()

val page = html {            // 이 블록 안에서 this == HtmlBuilder
    p("안녕")                 // p()를 this 없이 호출
    p("DSL")
}

이 패턴으로 중첩 구조를 자연스럽게 표현한다 — Jetpack ComposeColumn { Text(...) }, Gradle Kotlin DSLdependencies { implementation(...) }, 코루틴의 launch { }가 모두 수신자 있는 람다다.

다이어그램 로딩 중…

@DslMarker중첩된 수신자들이 섞이는 걸 막아(바깥 수신자의 멤버를 안쪽에서 실수로 부르지 못하게) DSL을 안전하게 만든다.

Compose가 곧 DSL의 결정체

@Composable
fun Greeting(name: String) {
    Column(Modifier.padding(16.dp)) {        // 수신자 람다 → 중첩 UI
        Text("안녕, $name")
        Button(onClick = { /* ... */ }) { Text("확인") }
    }
}

위 코드가 연산자(16.dp는 확장 프로퍼티)·trailing 람다·수신자 람다의 종합이다 — [andsys] Compose 장에서 다시 다룬다. 코틀린의 문법 설계가 Compose 같은 선언형 UI를 가능케 했다.

정리 — 문법이 표현력을 만든다

코틀린의 연산자 오버로딩·중위 함수·수신자 람다코드를 도메인 언어처럼 읽히게 한다. 그 결정체가 Compose UI·Gradle DSL·코루틴 빌더다. 직접 DSL을 자주 만들진 않더라도 — 이 문법들을 알면 Compose·Gradle 코드가 왜 그렇게 생겼는지가 바닥부터 보인다.

한 줄 요약operator fun으로 +·[]·in·..을 내 타입에(직관적일 때만). infixa to b. 수신자 있는 람다(A.() -> Unit)가 DSL의 핵심 — apply·Compose Column { }·Gradle dependencies { }가 전부 이것. @DslMarker로 중첩 안전.

(출처: Kotlin Docs — Operator Overloading / Type-Safe Builders / Kotlin in Action 2e Ch 13 / Compose mental model.)

제네릭·변성 — in/out·스타 프로젝션·타입 소거자바 interop·코틀린 관용구