Kotlin 1.4.20의 새로운 기능

Kotlin 1.4.20의 새로운 기능

릴리스: 2020년 11월 23일

Kotlin 1.4.20은 여러 새로운 실험적 기능을 제공하고, 1.4.0에 추가된 기능을 포함한 기존 기능에 대한 수정과 개선을 제공해요.

블로그 게시물에서도 다양한 예제와 함께 새로운 기능을 배워볼 수 있어요.

Kotlin의 릴리스 주기에 대한 자세한 내용은 Kotlin 릴리스 프로세스를 참고해 주세요.

출처: What's new in Kotlin 1.4.20

본문

Kotlin/JVM

Kotlin/JVM의 개선은 최신 Java 버전의 기능에 맞춰 따라가는 것을 목표로 해요.

  • Java 15 타깃
  • invokedynamic 문자열 연결

Java 15 타깃

이제 Java 15를 Kotlin/JVM 타깃으로 사용할 수 있어요.

invokedynamic 문자열 연결

invokedynamic 문자열 연결은 실험적 기능이에요. 언제든 제거되거나 변경될 수 있고, 옵트인(opt-in)이 필요해요(아래에서 자세히 설명해요). 평가 목적으로만 사용해 주세요. 이에 대한 피드백은 YouTrack에 남겨 주시면 감사하겠어요.

Kotlin 1.4.20은 JVM 9+ 타깃에서 문자열 연결을 동적 호출(dynamic invocation)로 컴파일할 수 있어서 성능이 개선돼요.

현재 이 기능은 실험적이며 다음 경우를 다뤄요.

  • 연산자(a + b), 명시적(a.plus(b)), 참조((a::plus)(b)) 형태의 String.plus
  • 인라인 및 데이터 클래스의 toString
  • 단일 비상수 인자를 가진 것을 제외한 문자열 템플릿(KT-42457 참고)

invokedynamic 문자열 연결을 활성화하려면 다음 값 중 하나를 가진 -Xstring-concat 컴파일러 옵션을 추가해 주세요.

  • indy-with-constantsStringConcatFactory.makeConcatWithConstants()로 문자열에 invokedynamic 연결을 수행해요.
  • indyStringConcatFactory.makeConcat()로 문자열에 invokedynamic 연결을 수행해요.
  • inlineStringBuilder.append()를 통한 기존 연결 방식으로 되돌려요.

Kotlin/JS

Kotlin/JS는 계속 빠르게 진화하고 있고, 1.4.20에서는 여러 실험적 기능과 개선 사항을 찾을 수 있어요.

  • Gradle DSL 변경
  • 새로운 Wizard 템플릿
  • IR 컴파일러로 컴파일 오류 무시하기

Gradle DSL 변경

Kotlin/JS용 Gradle DSL에는 프로젝트 설정과 커스터마이징을 단순화하는 여러 업데이트가 있어요. 여기에는 webpack 구성 조정, 자동 생성된 package.json 파일 수정, 전이적 의존성에 대한 제어 개선이 포함돼요.

webpack 구성을 위한 단일 지점

브라우저 타깃에 새로운 구성 블록 commonWebpackConfig를 사용할 수 있어요. 이 블록 안에서 webpackTask, runTask, testTask에 대해 구성을 중복하지 않고 한 곳에서 공통 설정을 조정할 수 있어요.

세 가지 태스크 모두에서 CSS 지원을 기본으로 활성화하려면 프로젝트의 build.gradle(.kts)에 다음 스니펫을 추가해 주세요.

browser {
    commonWebpackConfig {
        cssSupport.enabled = true
    }
    binaries.executable()
}

webpack 번들링 구성에 대해 자세히 알아보세요.

Gradle에서 package.json 커스터마이징

Kotlin/JS 패키지 관리와 배포를 더 잘 제어하기 위해, 이제 Gradle DSL을 통해 프로젝트 파일 package.json에 속성을 추가할 수 있어요.

package.json에 커스텀 필드를 추가하려면 컴파일의 packageJson 블록에서 customField 함수를 사용해 주세요.

kotlin {
    js(BOTH) {
        compilations["main"].packageJson {
            customField("hello", mapOf("one" to 1, "two" to 2))
        }
    }
}

package.json 커스터마이징에 대해 자세히 알아보세요.

선택적 yarn 의존성 해석

선택적 yarn 의존성 해석 지원은 실험적 기능이에요. 언제든 제거되거나 변경될 수 있어요. 평가 목적으로만 사용해 주세요. 이에 대한 피드백은 YouTrack에 남겨 주시면 감사하겠어요.

Kotlin 1.4.20은 Yarn의 선택적 의존성 해석(의존하는 패키지들의 의존성을 재정의하는 메커니즘)을 구성하는 방법을 제공해요.

Gradle에서 YarnPlugin 안의 YarnRootExtension을 통해 사용할 수 있어요. 프로젝트에서 패키지의 해석된 버전에 영향을 주려면 resolution 함수에 Yarn이 지정하는 패키지 이름 선택자와 해석할 버전을 전달해 주세요.

rootProject.plugins.withType<YarnPlugin> {
    rootProject.the<YarnRootExtension>().apply {
        resolution("react", "16.0.0")
        resolution("processor/decamelize", "3.0.0")
    }
}

여기서 react를 요구하는 모든 npm 의존성은 버전 16.0.0을 받고, processor는 자신의 의존성 decamelize를 버전 3.0.0으로 받게 돼요.

세분화된 워크스페이스(granular workspaces) 비활성화

세분화된 워크스페이스 비활성화는 실험적 기능이에요. 언제든 제거되거나 변경될 수 있어요. 평가 목적으로만 사용해 주세요. 이에 대한 피드백은 YouTrack에 남겨 주시면 감사하겠어요.

빌드 시간을 단축하기 위해 Kotlin/JS Gradle 플러그인은 특정 Gradle 태스크에 필요한 의존성만 설치해요. 예를 들어 webpack-dev-server 패키지는 *Run 태스크 중 하나를 실행할 때만 설치되고, assemble 태스크를 실행할 때는 설치되지 않아요. 이 같은 동작은 여러 Gradle 프로세스를 병렬로 실행할 때 문제를 일으킬 수 있어요. 의존성 요구 사항이 충돌하면 npm 패키지의 두 설치가 오류를 일으킬 수 있답니다.

이 문제를 해결하기 위해 Kotlin 1.4.20에는 소위 세분화된 워크스페이스를 비활성화하는 옵션이 포함되어 있어요. 이 기능은 현재 Gradle에서 YarnPlugin 안의 YarnRootExtension을 통해 제공돼요. 사용하려면 build.gradle.kts 파일에 다음 스니펫을 추가해 주세요.

rootProject.plugins.withType<YarnPlugin> {
    rootProject.the<YarnRootExtension>().disableGranularWorkspaces()
}

새로운 Wizard 템플릿

프로젝트를 만들 때 더 편리하게 커스터마이징할 수 있도록, Kotlin용 프로젝트 위저드는 Kotlin/JS 애플리케이션을 위한 새로운 템플릿을 제공해요.

  • Browser Application — 브라우저에서 실행되는 최소한의 Kotlin/JS Gradle 프로젝트예요.
  • React Application — 적절한 kotlin-wrappers를 사용하는 React 앱이에요. 스타일시트, 내비게이션 컴포넌트, 상태 컨테이너의 통합을 활성화하는 옵션을 제공해요.
  • Node.js Application — Node.js 런타임에서 실행하기 위한 최소한의 프로젝트예요. 실험적 kotlinx-nodejs 패키지를 직접 포함하는 옵션이 함께 제공돼요.

IR 컴파일러로 컴파일 오류 무시하기

컴파일 오류 무시 모드는 실험적 기능이에요. 언제든 제거되거나 변경될 수 있고, 옵트인이 필요해요(아래에서 자세히 설명해요). 평가 목적으로만 사용해 주세요. 이에 대한 피드백은 YouTrack에 남겨 주시면 감사하겠어요.

Kotlin/JS용 IR 컴파일러에는 새로운 실험적 모드(오류가 있는 컴파일)가 있어요. 이 모드에서는 전체 애플리케이션이 아직 준비되지 않았을 때 특정 부분을 시도해 보려는 경우처럼, 코드에 오류가 있어도 코드를 실행할 수 있어요.

이 모드에는 두 가지 허용 정책이 있어요.

  • SEMANTIC: 컴파일러가 구문적으로는 맞지만 의미적으로는 맞지 않는 코드(예: val x: String = 3)를 허용해요.
  • SYNTAX: 컴파일러가 구문 오류가 있어도 어떤 코드든 허용해요.

오류가 있는 컴파일을 허용하려면 위에 나열된 값 중 하나를 가진 -Xerror-tolerance-policy= 컴파일러 옵션을 추가해 주세요.

Kotlin/JS IR 컴파일러에 대해 자세히 알아보세요.

Kotlin/Native

1.4.20에서 Kotlin/Native의 우선순위는 성능과 기존 기능 개선이에요. 다음이 눈에 띄는 개선 사항이랍니다.

  • 이스케이프 분석(Escape analysis)
  • 성능 개선 및 버그 수정
  • Objective-C 예외의 옵트인 래핑
  • CocoaPods 플러그인 개선
  • Xcode 12 라이브러리 지원

이스케이프 분석

이스케이프 분석 메커니즘은 실험적 기능이에요. 언제든 제거되거나 변경될 수 있어요. 평가 목적으로만 사용해 주세요. 이에 대한 피드백은 YouTrack에 남겨 주시면 감사하겠어요.

Kotlin/Native에 새로운 이스케이프 분석 메커니즘의 프로토타입이 추가돼요. 특정 객체를 힙 대신 스택에 할당해서 런타임 성능을 개선해요. 이 메커니즘은 벤치마크에서 평균 10%의 성능 향상을 보여 주고 있고, 프로그램을 더 빠르게 만들기 위해 계속 개선하고 있답니다.

이스케이프 분석은 릴리스 빌드에서 -opt 컴파일러 옵션과 함께 별도의 컴파일 단계로 실행돼요.

이스케이프 분석 단계를 비활성화하려면 -Xdisable-phases=EscapeAnalysis 컴파일러 옵션을 사용해 주세요.

성능 개선 및 버그 수정

Kotlin/Native는 1.4.0에 추가된 코드 공유 메커니즘을 포함한 다양한 구성 요소에서 성능 개선과 버그 수정을 받아요.

Objective-C 예외의 옵트인 래핑

Objective-C 예외 래핑 메커니즘은 실험적 기능이에요. 언제든 제거되거나 변경될 수 있고, 옵트인이 필요해요(아래에서 자세히 설명해요). 평가 목적으로만 사용해 주세요. 이에 대한 피드백은 YouTrack에 남겨 주시면 감사하겠어요.

이제 Kotlin/Native는 프로그램 크래시를 피하기 위해 런타임에서 Objective-C 코드가 던지는 예외를 처리할 수 있어요.

NSExceptionForeignException 타입의 Kotlin 예외로 래핑하도록 옵트인할 수 있어요. 이 래핑된 예외는 원래 NSException에 대한 참조를 보유해요. 덕분에 근본 원인에 대한 정보를 얻고 제대로 처리할 수 있어요.

Objective-C 예외 래핑을 활성화하려면 cinterop 호출에 -Xforeign-exception-mode objc-wrap 옵션을 지정하거나 .def 파일에 foreignExceptionMode = objc-wrap 속성을 추가해 주세요. CocoaPods 통합을 사용한다면 의존성의 pod {} 빌드 스크립트 블록에 옵션을 이렇게 지정해 주세요.

pod("foo") {
    extraOpts = listOf("-Xforeign-exception-mode", "objc-wrap")
}

기본 동작은 이전과 동일해요. Objective-C 코드에서 예외가 던져지면 프로그램이 종료돼요.

CocoaPods 플러그인 개선

Kotlin 1.4.20은 CocoaPods 통합의 일련의 개선을 계속해요. 특히 다음과 같은 새로운 기능을 시도해 볼 수 있어요.

  • 개선된 태스크 실행
  • 확장된 DSL
  • Xcode와의 업데이트된 통합

개선된 태스크 실행

CocoaPods 플러그인은 개선된 태스크 실행 흐름을 갖게 돼요. 예를 들어 새 CocoaPods 의존성을 추가해도 기존 의존성은 다시 빌드되지 않아요. 추가 타깃을 추가하는 것도 기존 타깃의 의존성 다시 빌드에 영향을 주지 않아요.

확장된 DSL

Kotlin 프로젝트에 CocoaPods 의존성을 추가하는 DSL에 새로운 기능이 추가돼요.

로컬 Pod와 CocoaPods 저장소의 Pod 외에도 다음 유형의 라이브러리에 대한 의존성을 추가할 수 있어요.

  • 커스텀 spec 저장소의 라이브러리
  • Git 저장소의 원격 라이브러리
  • 아카이브의 라이브러리(임의의 HTTP 주소로도 사용 가능)
  • 정적 라이브러리
  • 커스텀 cinterop 옵션이 있는 라이브러리

Kotlin 프로젝트에서 CocoaPods 의존성을 추가하는 방법에 대해 자세히 알아보세요. 예제는 Kotlin with CocoaPods 샘플에서 찾을 수 있어요.

Xcode와의 업데이트된 통합

Xcode와 올바르게 동작하려면 Kotlin은 몇 가지 Podfile 변경이 필요해요.

  • Kotlin Pod에 Git, HTTP, 또는 specRepo Pod 의존성이 있다면 Podfile에도 지정해야 해요.
  • 커스텀 spec에서 라이브러리를 추가할 때는 Podfile 맨 앞에 specs의 위치도 지정해야 해요.

이제 통합 오류는 IDEA에서 자세한 설명과 함께 표시돼요. 그래서 Podfile에 문제가 있으면 어떻게 고쳐야 할지 바로 알 수 있어요.

Kotlin pods를 만드는 방법에 대해 자세히 알아보세요.

Xcode 12 라이브러리 지원

Xcode 12와 함께 제공되는 새로운 라이브러리 지원을 추가했어요. 이제 Kotlin 코드에서 사용할 수 있답니다.

Kotlin Multiplatform

멀티플랫폼 라이브러리 게시 구조 업데이트

Kotlin 1.4.20부터 별도의 메타데이터 게시물은 더 이상 없어요. 메타데이터 아티팩트는 이제 전체 라이브러리를 나타내는 루트 게시물에 포함되고, 공통 소스 세트에 의존성으로 추가되면 자동으로 적절한 플랫폼별 아티팩트로 해석돼요.

멀티플랫폼 라이브러리 게시에 대해 자세히 알아보세요.

이전 버전과의 호환성

이 구조 변경은 계층적 프로젝트 구조를 가진 프로젝트 사이의 호환성을 깨뜨려요. 멀티플랫폼 프로젝트와 그것이 의존하는 라이브러리 둘 다 계층적 프로젝트 구조를 가진다면, 둘 다 동시에 Kotlin 1.4.20 이상으로 업데이트해야 해요. Kotlin 1.4.20으로 게시된 라이브러리는 이전 버전으로 게시된 프로젝트에서 사용할 수 없어요.

계층적 프로젝트 구조가 없는 프로젝트와 라이브러리는 여전히 호환돼요.

표준 라이브러리

Kotlin 1.4.20의 표준 라이브러리는 파일 작업을 위한 새로운 확장과 더 나은 성능을 제공해요.

  • java.nio.file.Path용 확장
  • 개선된 String.replace 함수 성능

java.nio.file.Path용 확장

java.nio.file.Path용 확장은 실험적 기능이에요. 언제든 제거되거나 변경될 수 있고, 옵트인이 필요해요(아래에서 자세히 설명해요). 평가 목적으로만 사용해 주세요. 이에 대한 피드백은 YouTrack에 남겨 주시면 감사하겠어요.

이제 표준 라이브러리가 java.nio.file.Path용 실험적 확장을 제공해요. 현대적인 JVM 파일 API를 관용적인 Kotlin 방식으로 다루는 것이 이제 kotlin.io 패키지의 java.io.File 확장을 다루는 방식과 비슷해요.

// div(/) 연산자로 경로 구성하기
val baseDir = Path("/base")
val subDir = baseDir / "subdirectory"

// 디렉터리의 파일 목록 보기
val kotlinFiles: List<Path> = Path("/home/user").listDirectoryEntries("*.kt")

이 확장은 kotlin-stdlib-jdk7 모듈의 kotlin.io.path 패키지에서 사용할 수 있어요. 확장을 사용하려면 실험적 어노테이션 @ExperimentalPathApi에 옵트인해 주세요.

개선된 String.replace 함수 성능

String.replace()의 새로운 구현은 함수 실행을 빠르게 만들어요. 대소문자를 구분하는 변형은 indexOf 기반의 수동 교체 루프를 사용하고, 대소문자를 구분하지 않는 변형은 정규 표현식 매칭을 사용해요.

Kotlin Android Extensions

1.4.20에서 Kotlin Android Extensions 플러그인은 더 이상 사용되지 않게 되고(deprecated), Parcelable 구현 생성기는 별도의 플러그인으로 이동해요.

  • 합성 뷰(synthetic views)의 deprecation
  • Parcelable 구현 생성기용 새 플러그인

합성 뷰의 deprecation

합성 뷰는 한동안 Kotlin Android Extensions 플러그인에서 UI 요소와의 상호작용을 단순화하고 보일러플레이트를 줄이기 위해 제공되었어요. 이제 Google이 같은 역할을 하는 네이티브 메커니즘(Android Jetpack의 view binding)을 제공하므로, 합성 뷰 대신 그것을 사용하도록 deprecation을 진행하고 있어요.

kotlin-android-extensions에서 Parcelable 구현 생성기를 분리하고, 나머지(합성 뷰)에 대한 deprecation 주기를 시작해요. 지금은 deprecation 경고와 함께 계속 동작하지만, 앞으로는 프로젝트를 다른 솔루션으로 전환해야 해요. Android 프로젝트를 합성 뷰에서 view binding으로 마이그레이션하는 데 도움이 되는 지침이 있답니다.

Parcelable 구현 생성기용 새 플러그인

Parcelable 구현 생성기는 이제 새로운 kotlin-parcelize 플러그인에서 사용할 수 있어요. kotlin-android-extensions 대신 이 플러그인을 적용해 주세요.

kotlin-parcelizekotlin-android-extensions는 한 모듈에 함께 적용할 수 없어요.

@Parcelize 어노테이션은 kotlinx.parcelize 패키지로 이동했어요.

Parcelable 구현 생성기에 대해 Android 문서에서 자세히 알아보세요.

더 알아보기