본문 바로가기
Kotlin/Release Notes

[Kotlin Release Notes] Kotlin M11 is Out!

by 노력남자 2023. 8. 28.
반응형

2015년 3월 19일

 

오늘은 새로운 이정표인 Kotlin M11을 출시합니다. 이 버전에는 보조 생성자, Kotlin에 대한 실제 리플렉션 지원의 첫 번째 실마리 등이 포함되어 있습니다.


언어 변경 사항


M11은 상당한 언어 변경 사항을 가져왔습니다. 이 중 일부는 기존 방식의 제거 및 새로운 방식의 선호를 위해 더 나은 방식으로 작업하도록 기존 코드가 변경되거나 폐기되는 변경 사항입니다. 일부 코드가 깨질 수 있지만 가능한 원활한 전환 경로를 제공하려 노력했습니다.


다중 생성자


이 기능은 안드로이드 개발자들에게 가장 기다려진 기능 중 하나입니다. 안드로이드에서 표준 뷰 클래스를 서브 클래스화하려면 하나 이상의 생성자가 필요합니다. 이제 이렇게 할 수 있습니다:

 

class MyView : View {
    constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) {
        // ...
    }
    constructor(context: Context, attrs: AttributeSet) : this(context, attrs, 0) {}
}

 

사용자 문서와 사양 문서에서 자세한 내용을 확인하세요.

 

초기화 블록에 대한 접두사 추가


생성자와 관련된 다른 변경 사항은 초기화 블록 앞에 소프트 키워드 init을 추가하는 것입니다. 이 변경 사항의 주된 이유는 이전에 사용되던 구문(클래스 본문에서 중괄호만 사용하여 초기화 블록을 나타냄)이 초기화가 속성 선언을 따르는 경우(이는 꽤 일반적인 경우)에 잘 작동하지 않았기 때문입니다.

 

class Foo {
    val bar = baz() // 여기서 오류 발생
    {
        // M11 이전 초기화
    }
}

 

baz() 호출에서 오류가 발생했습니다. 이는 초기화 블록이 그냥 중괄호만 사용한 경우와 정확히 같아 보인다는 것이 원인이었습니다. 유일한 해결책은 속성 초기화 뒤에 세미콜론을 넣는 것이었는데, 이는 Kotlin에서 상당히 어색해 보입니다. 따라서 M11부터 초기화 블록 앞에 init을 요구합니다:

 

class Foo {
    val bar = baz()
    init {
        // 초기화
    }
}

 

구식 구문은 폐기되었으며, 즉 경고가 나타납니다. 또한 IDE에서는 구식 구문을 새 구문으로 변환하는 Alt+Enter 빠른 수정 작업이 제공됩니다. 이 작업은 프로젝트 전체를 대량으로 업데이트할 수 있는 옵션도 있습니다.

자세한 내용은 사용자 문서를 참조하세요.

 

동반 객체 (Class-Objects 재구상)


모두 아시다시피 Kotlin 클래스에는 정적 멤버가 없습니다. 대신 클래스와 관련된 특수한 싱글톤 객체이며, 이를 "클래스 객체"라고 부르곤 했습니다. 이 개념을 다시 설계하여 일반 객체와 더 일치하도록 선택한 다른 이름을 선택했습니다: 동반 객체(companion object).

불행한 용어 선택만이 이 변경의 유일한 이유는 아닙니다. 사실 일반 객체와 더 일치하도록 개념을 다시 설계했습니다.

클래스에는 여러 객체(일반적으로 이름이 있는 싱글톤)가 중첩될 수 있습니다.

 

class KotlinClass {
    object Obj1 { ... }
    object Obj2 { ... }
    ...
}

 

M11부터 이러한 객체 중 하나는 companion 한정자와 함께 선언될 수 있으며, 이는 해당 멤버를 클래스 이름을 통해 직접 액세스할 수 있게 합니다:

 

class KotlinClass {
    object Obj1 { ... }
    companion object Obj2 { ... }
    ...
}

 

Obj1의 멤버에 액세스하려면 KotlinClass.Obj1.foo()와 같이 지정이 필요합니다. Obj2의 멤버의 경우 객체 이름은 선택 사항입니다: KotlinClass.foo().

마지막 단계: 동반 객체의 이름을 생략할 수 있습니다(이 경우 컴파일러는 기본 이름인 Companion을 사용합니다):

 

class KotlinClass {
    object Obj1 { ... }
    companion object { ... }
    ...
}

 

이제 해당 클래스의 이름을 통해 여전히 멤버에 참조할 수 있거나 전체 지정을 통해 참조할 수 있습니다: KotlinClass.foo() 또는 KotlinClass.Companion.foo().

보시다시피 클래스 객체와 달리 동반 객체는 일반 객체와 완전히 일치합니다.

또 다른 중요한 이점은 이제 모든 객체가 이름을 가집니다(다시 말하지만 동반 객체의 이름이 생략된 경우 Companion이 사용됩니다). 이로써 동반 객체에 대한 확장 함수를 작성할 수 있게 되었습니다:

 

fun KotlinClass.Companion.bar() { ... }

 

함수 표현식


Kotlin은 고차 함수를 지원하므로 함수를 값으로 전달할 수 있습니다. M11 이전에는 람다 표현식(예: { x -> x + 1 }) 및 호출 가능한 참조(예: MyClass::myFun) 두 가지 방법으로 이러한 값을 얻을 수 있었습니다. M11에서는 논리적으로 매우 합리적인 새로운 방법을 소개했습니다:

 

val f = fun (x: Int): Int { return x + 1 }

 

따라서 전통적인 문법 형식의 함수를 값으로 사용할 수 있습니다. 자세한 내용은 사용자 문서와 사양 문서를 참조하세요.

 

람다 구문 제한(미래의 개선을 위해)


기능 표현식을 통해 람다의 매개변수에 다중 선언을 지원하기 위한 단계를 밟았습니다. 최종 목표(아직 구현되지 않음)는 다음과 같은 구문으로 목록의 쌍을 필터링하는 것과 같은 작업을 수행할 수 있게 하는 것입니다:

 

pairs.filter { (a, b) -> a != b }

 

여기서 (a, b)는 다중 선언입니다. 즉, a는 각 Pair 객체의 첫 번째 구성 요소를 가져오고 b는 두 번째 구성 요소를 가져옵니다. 현재 다중 선언은 지원되지 않지만 이러한 람다의 구문 형식 중 일부를 M12에서 삭제하고 다중 선언 구문을 가능하게 만들기 위해 준비하려 합니다.

다음이 폐기된 내용입니다:

- 람다의 반환 유형 지정, 예: { (a: Int): Int -> a + 1 }


- 람다의 수신자 유형 지정: { Int.(a: Int) -> this + a }


- 람다의 매개변수 이름 주변에 괄호 사용: { (a, b) -> a + b }


이 중 하나가 실제로 필요한 경우 함수 표현식 사용으로 전환하세요.

IDE에서는 코드를 자동으로 마이그레이션하는 빠른 수정을 제공합니다.

 

라벨이 지정된 람다에서 반환


오랜 시간 동안 람다에서 반환 표현식을 사용하는 제한이 있었습니다: 람다에 명시적 반환 유형이 지정된 경우에만 지역 반환이 허용되었습니다. 이것은 유형 추론 알고리즘의 제한으로 인한 것이었습니다. 이제 제한이 제거되어 지역 반환을 자유롭게 사용할 수 있습니다:

 

list.map {
    if (it < 10) return@map DEFAULT
    ...
}

 

임포트 의미론 변경됨


임포트는 IDE 사용자에게 가장 불가능한 언어 기능 중 하나입니다. 하지만 이것은 도구가 작동하는 방식 및 가끔은 사용자에게도 큰 영향을 미치는 중요한 기능입니다.
M11에서는 *-임포트(또는 "요청임포트"라고도 함)의 순서가 무의미하도록 만들었으며, 다른 조정 사항을 도입하여 IDE에서 임포트 지시문을 효율적으로 자동으로 관리할 수 있게 했습니다.

 

리플렉션


Kotlin 특정 리플렉션을 구현하는 것(Java 리플렉션을 Kotlin 클래스에 사용하게 만드는 대신)은 컴파일러에서 많은 작업을 필요로 하는 장기 프로젝트였습니다. 본질적으로 컴파일러의 큰 부분을 분리하여 런타임의 일부로 제공해야 했습니다. 이에는 이진 파일에서 Kotlin 특정 메타데이터를 로드하는 것, Kotlin 심볼을 개체로 표시하는 것(역사적으로 우리는 이를 기술자(descriptor)라고 부릅니다), Java 선언을 Kotlin 선언으로 로드하는 것(Kotlin 리플렉션은 Java 객체에서도 작동해야 하기 때문) 등이 포함되었습니다.

마침내 이 작업의 첫 결과물을 제시합니다. 새로운 kotlin-reflect.jar를 통해 속성을 내밀 수 있는 능력이 이에 포함되어 있으며, 컴파일러와 함께 제공됩니다(추가 기능이 곧 추가될 것입니다).

 

새로운 리플렉션 JAR


이제 kotlin-reflect.jar를 별도로 제공합니다(코틀린 런타임의 일부로 제공되지 않음). 현재 크기가 상당히 큽니다(약 1.8MB). 크기를 줄이는 방법을 고려해볼 것이지만, 항상 응용 프로그램과 함께 이를 배포하는 것은 항상 가능한 옵션은 아닙니다(특히 안드로이드 개발자의 경우).

따라서 속성 리터럴(::propertyName)을 사용하는 경우 클래스패스에 이 JAR를 추가해야 할 수도 있습니다. M11 컴파일러는 이를 해주지 않으면 오류가 발생하지만 나중에는 이 요구 사항이 완화될 것입니다. IDE에서는 프로젝트에 이 JAR를 자동으로 추가하는 빠른 수정 작업을 제공할 것입니다.


클래스 리터럴

 

Kotlin에서 클래스의 리플렉션 객체를 얻으려면 다음 구문을 사용하세요:

 

val c = MyClass::class

 

KClass<MyClass>의 인스턴스가 반환되며, 이를 내밀 수 있습니다(예: 속성을 가져옴).

사용자 문서에서 더 많은 정보를 확인하세요.

 

Java 리플렉션 API와의 호환성


Kotlin 리플렉션 API는 Kotlin 및 Java 클래스 모두에서 작동하며, Kotlin에서 Java 리플렉션 객체로 "변환"하고 다시 되돌릴 수 있습니다. 예를 들어 kClass.java를 사용하여 java.lang.Class 인스턴스를 얻을 수 있으며, 그 반대로 jlClass.kotlin을 사용하여 KClass 인스턴스를 얻을 수 있습니다.

 

@Nullable 및 @NotNull in Java


Java 상호 운용성은 항상 큰 우선 사항이었으며, 이번에는 M9에서 제공한 플랫폼 타입 기능을 개선하고 있습니다. 이제 컴파일러는 @Nullable 및 @NotNull로 주석이 달린 Java 값의 오용에 대한 경고를 발생시킵니다. 이것은 M9 이전과 같이 엄격하지는 않지만 더 이상 자주 깨지지 않습니다.

다음 단계는 Java nullability 오류를 안전하게 발생시키는 것(오류를 항상 합리적으로 고칠 수 있도록)이며, 이것은 다음 이정표에서 계획되어 있습니다.

 

Android Extensions


안드로이드 사용자에게 좋은 소식: M11은 Kotlin에서 안드로이드 개발을 더 쉽게 만드는 유용한 확장 기능을 제공합니다.

우리는 모두 findViewById()에 대해 알고 있습니다. 이것은 버그의 흔한 원인이며, 읽기 어렵고 지원하기 어려운 코드의 악명 높은 원천입니다. Java에서는 ButterKnife와 AndroidAnnotations과 같은 라이브러리를 통해 이 문제를 우회할 수 있습니다. 그러나 이들은 JSR 269에 의존하는 javac 특정 API이며 Kotlin에서는 지원되지 않습니다(아직).

M11부터는 JSR 269를 필요로 하지 않는 findViewById() 문제에 대한 Kotlin의 솔루션이 있습니다. 이는 타입 안전한 방식으로 뷰에 액세스할 수 있게 해주며 추가 사용자 코드(주석 또는 기타 요소 없음)나 런타임 라이브러리가 필요하지 않습니다.

이 확장 기능을 사용하려면 Gradle 빌드에서 활성화하고 IDE에 확장 플러그인을 설치해야 합니다. 자세한 내용은 여기를 참조하세요.

 

IntelliJ IDEA 지원


IntelliJ IDEA에 대한 더 많은 개선 및 기능

 

리팩터링과 인텐션


다음 리팩터링 및 인텐션을 사용할 수 있습니다.

 

- 속성 도입


속성을 도입하고 초기화자, getter 또는 지연 속성을 원하는지를 정의할 수 있는 능력

 

 

- Java 상호 운용성으로 사용 생성


Kotlin 파일에서 사용되는 Java 타입에 대해 "사용 생성"을 호출하는 것이 이제 가능합니다.

 

 

- 수신자를 매개 변수로 변환

 

매개 변수를 수신자로 리팩터링하는 특수한 경우의 Change Signature 리팩터링으로, 매개 변수를 T의 확장 기능으로 변환하는 함수를 T의 확장 기능으로 변환하는 것을 허용합니다. 또한 수신자를 매개 변수로 변환하는 것도 가능합니다.

 

 

- 함수를 속성으로 변환

 

함수를 속성으로 변환하거나 그 반대로 변환할 수 있는 능력

 

 

- 사용되지 않은 선언

 

프로젝트 전역에서 사용되지 않은 선언 검사가 이제 가능하며, 이로 인해 어떤 문맥에서라도 강조 표시될 수 있습니다.


식 평가

 

디버거에서 람다 표현식 및 익명 객체를 평가할 수 있는 능력이 있습니다.

 

 

KDoc 지원


인라인 문서를 제공하기 위한 완전한 언어인 KDoc을 이제 갖추었습니다. 이는 JavaDoc과 Markdown의 조합을 기반으로 합니다. 전체 참조는 온라인에서 확인할 수 있습니다. M11에서 IntelliJ IDEA는 KDoc에 대한 완성, 유효성 검사 및 리팩터링 지원을 제공합니다.


표준 라이브러리


표준 라이브러리의 큰 변경 사항 중 하나는 스트림을 시퀀스로 이름을 변경한 것입니다. 이것은 Java 8 스트림과 혼동을 피하기 위해 수행되었습니다.

 

val elements = sequence(1, { x -> x + 1})

 

위의 코드는 1부터 시작하는 무한한 지연 시퀀스를 생성합니다. 기존 반복 가능한(iterable)을 시퀀스로 변환할 수 있는 확장 기능도 있습니다.

 

val elements = listOf(1, 2, 3, 4).sequence()

 

또한 표준 라이브러리의 여러 버그 수정이 이루어졌습니다.

또한 팀은 Kotlin의 최근 변경 내용을 고려하여 RxKotlin의 업데이트에 기여하여 더 간결하게 만들었습니다.

마지막으로, 표준 라이브러리 API 참조도 개선하여 이제 Kotlin 웹 사이트에서 사용할 수 있습니다.

 

JavaScript 지원


JavaScript 백엔드는 이제 인라인 함수를 더 잘 지원합니다. 또한 "JavaScript 이진"이라는 새로운 개념을 통해 JavaScript를 대상으로 하는 라이브러리를 재사용하기 쉽게 만들었습니다. 이에 대한 자세한 내용은 나중에 더 자세히 다룰 예정입니다.


기타 변경 사항 및 개선 사항


위에서 언급한 것 외에도 이 릴리스에서는 다음과 같은 내용이 포함되어 있습니다:

- Gradle 변경
이제 Kotlin 및 Java 파일을 단일 소스 폴더에 두실 수 있습니다.


- 버그 수정 및 컴파일 속도 개선


M10 이후 220여개 이상의 버그 수정 및 커뮤니티에서 제출한 많은 외부 풀 리퀘스트가 있습니다.

항상 기존 버전이 설치되어 있는 경우 IntelliJ IDEA 14(또는 이전 버전)에서 플러그인을 업데이트하거나 JetBrains 플러그인 저장소에서 직접 설치할 수 있습니다. 또한 릴리스 페이지에서 독립 컴파일러를 다운로드할 수도 있습니다.

 

원문

 

https://blog.jetbrains.com/kotlin/2015/03/kotlin-m11-is-out/

반응형

댓글