깔끔한 API를 작성할 수 있도록 코틀린에서 도움을 주는 기능 정리
| 일반 구문 | 간결한 구문 | 사용한 언어 특성 |
| StringUtil.capitalize(s) | s.capitalize() | 확장 함수 |
| 1.to("One") | 1 to "One" | 중위 호출 |
| set.add(2) | set += 2 | 연산자 오버로딩 |
| map.get("key") | map["key"] | get 메서드에 대한 관례 |
| file.use({f → f.read()}) | file.use{ it.read()} | 람다를 괄호 밖으로 빼내는 관례 |
| sb.append("yes") sb.append("no") |
with(sb){ append("yes") append("no") } |
수신 객체 지정 람다 |
코틀린 DSL은 간결한 구문을 제공하는 기능과 그런 구문을 확장해서 여러 메서드 호출을 조함으로써 구조를 만들어내는 기능에 의존한다.
그 결과 DSL은 API에 비해 더 표현력 풍부, 사용 편리
또한, DSL도 컴파일 시점에 타입이 정해져 컴파일 시점 오류 감지, IDE 지원 등 정적 타입 지정 언어의 장점을 누릴 수 있다.
영역 특화 언어라는 개념
DSL이란? 도메인 특화 언어(Domain-specific language)는 특정한 도메인을 적용하는데 특화된 컴퓨터 언어이다. 이는 어느 도메인에서나 적용 가능한 범용 언어(General-purpose language)와는 반대되는 개념이다. 도메인 특화 언어에는 매우 넓은 다양성이 존재한다. HTML과 같이 웹페이지 분야에서 널리 쓰이는 언어가 있는가 하면, GNU Emacs와 XEmacs를 위한 Emacs Lisp와 같이 한정된 분야에서 사용되는 언어도 있다. 도메인 특화 언어는 또한 언어의 종류로 세분화될 수 있다. 그리고 도메인 특화 마크업 언어, 도메인 특화 모델링 언어(일반적으로는, 설명 언어), 도메인 특화 프로그래밍 언어를 포함한다.
https://ko.wikipedia.org/wiki/%EB%8F%84%EB%A9%94%EC%9D%B8_%ED%8A%B9%ED%99%94_%EC%96%B8%EC%96%B4
도메인 특화 언어 - 위키백과, 우리 모두의 백과사전
위키백과, 우리 모두의 백과사전. 도메인 특화 언어(Domain-specific language)는 특정한 도메인을 적용하는데 특화된 컴퓨터 언어이다. 이는 어느 도메인에서나 적용 가능한 범용 언어(General-purpose langu
ko.wikipedia.org
DSL은 스스로 제공하는 기능을 제한함으로써 효율적으로 목표를 달성할 수 있다.
- SQL은 첫 키워드에 수행하려는 연산 종류를 지정하고, 각 연산은 처리해야 할 작업에 맞춰 서로 다른 문법, 키워드 사용
- 정규식은 압축적인 기호 문법 사용해 텍스트가 어떻게 달라질 수 있는지 지정함으로써 대상 텍스트를 직접 기술
DSL은 선언적이다.
- 일반 범용 프로그래밍 언어(java, kotlin)는 명령적인 거에 비해, DSL은 선언적이다.
- 원하는 결과를 기술하기만 하고, 세부 실행은 언어를 해석하는 엔진에 맡긴다.
DSL을 범용 언어로 만든 호스트 애플리케이션과 조합시키기 어렵다.
- DSL 자체 문법이 있어 다른 언어의 프로그램 안에 직접 포함시킬 수 없다.
- 호출하기 위해서는 DSL 프로그램을 별도 파일, 문자열 리터럴로 저장해야 한다(컴파일 검증 어려워짐, 디버그, IDE 사용 힘들다)
내부 DSL
내부 DSL : 범용 언어로 작성된 프로그램의 일부며, 범용 언어와 동일한 문법을 가진다(DSL 장점을 유지 가능)
EX) 익스포즈드 프레임워크(DB 프레임워크)
SELECT Country.name, COUNT(Customer.id)
FROM Country
JOIN Customer
ON Country.id = Customer.country_id
GROUP BY Country.name
ORDER BY COUNT(Customer.id) DESC
LIMIT 1
(Country join Customer)
.slice(Country.name, Count(Customer.id))
.selectAll()
.groupBy(Country.name)
.orderBy(Count(Customer.is), isAsc = false)
.limit(1)
- 내부 DSL에서 사용된 코드는 일반 코틀린 코드이며, seletAll()과 같은 메서드는 일반 코틀린 메서드이다.
- 또한, SQL 질의가 돌려주는 결과 집합을 따로 코틀린 객체로 변환할 필요도 없다(실행 결과가 코틀린 객체이다)
DSL 구조
명령 - 질의 API : 함수 호출 시퀀스에는 아무런 구조가 없으며, 한 호출과 다른 호출 사이에는 아무 맥락 존재 X
DSL의 메서드 호출은 DSL문법에 의해 정해지는 더 커다란 구조에 속한다.
DSL에서는 여러 함수 호출을 조합해서 연산을 만들며, 타입 검사기는 여러 함수 호출이 바르게 조합되었는지 검사한다(함수 이름=동사, 함수 인자=명사 역할을 한다)
project.dependencies.add("compile", "junit:junit:4.11")
project.dependencies.add("compile", "com.google.inject:guice:4.1.0")
dependencies{
compile("junit:junit:4.11")
compile("com.google.inject:guice:4.1.0")
}
assertTrue(str.startsWith("kot"))
str should startWith("kot")
내부 DSL로 HTML 만들기
kotlin.html 라이브러리
fun createAnotherTable() = createHTML().table {
val numbers = mapOf(1 to "one", 2 to "two")
for ((num, string) in numbers) {
tr {
td { +"$num" }
td { +string }
}
}
}

코틀린으로 HTML을 작성하므로 얻는 이점
- 타입 안전성( td는 tr 안에서만 사용 가능 → 잘못 사용 시 컴파일 에러)
- HTML이 아닌 일반 코틀린 언어(코틀린 문법을 사용해서 동적 HTML 출력이 가능)
'KotlinInAction > DSL 만들기' 카테고리의 다른 글
| 중위 호출 연쇄: 테스트 프레임워크의 should (0) | 2022.08.21 |
|---|---|
| invoke 관례를 사용한 더 유연한 블록 중첩 (0) | 2022.08.21 |
| 구조화된 API 구축: DSL에서 수신 객체 지정 DSL 사용 (0) | 2022.08.21 |