Вчера вечером вышло описание нововведений в Kotlin 1.2.40. Сегодня, по традиции, мы с вами взглянем на очередной релиз и актуализируем знания по языку.
Список изменений:
- множественное использование expectedBy зависимостей;
- поддержка crossinline suspend параметров в inline функциях;
- экспериментальная поддержка аннотации @JvmDefault для создания методов интерфейсов из Java 8 с модификатором default;
- добавлены новые инспекции и интеншены в плагин;
- прямое обращение к классам внутри companion object в скоупе наследования теперь deprecated;
- фиксы в компиляторе и IDE плагине, улучшения производительности.
Этот update совместим с Intellij IDEA от 2017.1 до 2018.1, также как с Android Studio 3.x.
Улучшения мультиплатформенных проектах
Платформенные модули теперь позволяют реализовывать платформенно-специфичные декларации для более чем одного мультиплатформенного
модуля. Теперь вы можете использовать expectedBy
в зависимостях несколько раз. Выглядит это, например, так:
apply plugin: 'kotlin-platform-jvm'
// ...
dependencies {
expectedBy project(":io-common")
expectedBy project(":data-common")
// ...
}
Такие зависимости нетранзитивны, разберемся с этим. Пусть есть вот такая цепочка зависимостей: my-common -> lib-common
Это два common модуля (напомню, что мы разделяем платформенные и common модули), где первый зависит от второго.
При попытке установить зависимость на my-common модуль в платформенном модуле у нас есть один из двух путей:
- либо мы вручную определяем две
expectedBy
зависимости; - или добавляем
expectedBy
только наmy-common
и компилируем зависимость на существующем платформенном модуле дляlib-common
.
Напомню, что для мультиплатформенных проектов есть понятие expect/actual модификатора. Эти модификаторы позволяют связывать “ожидания реализации” интерфейса и фактические платформенные реализации. Так вот, для expect функций и конструкторов в Kotlin 1.2.40 появилась поддержка значений по умолчанию, пример ниже:
expect class StringMatcher {
fun match(value: String, matchStrictly: Boolean = false): Boolean
}
При этом, default параметры поддерживаются только для expect конструкторов/функций, но не для их actual двойников.
Поддержка crossinline suspend параметров функций
Напомню, что crossinline модификатор говорит о том, что лямбда, передаваемая в качестве параметра inline функции, может быть передана в другой контекст, а, например, если мы передадим лямбду без этого модификатора, то компилятор не знает как поступать в случае non-local возвратов. Для того, чтобы решить эту проблему добавим модификатор crossinline, который подскажет компилятору, что нужно запретить non-local return и благодаря этому запрету появится возможность передавать лямбды в другие контексты.
До версии Kotlin 1.2.40 в случае совместного использования crossinline и suspend для лямбд, мы получали сообщение:
Inline lambda parameters of suspend function type are not fully supported. Add noinline modifier
. Теперь конструкция ниже компилируется:
inline fun schedule(crossinline runner: suspend () -> Unit) {
launch(CommonPool) {
runner()
}
}
@JvmDefault
Экспериментальная фича, которая при таргете на JVM 1.8 генерирует default методы интерфейса при наличии аннотации @JvmDefault. Фича
выключена по умолчанию, чтобы включить передаем компилятору флаг -Xenable-jvm-default
. Т.к. фича экспериментальная, то она
может быть передизайнена, изменена, ровно как может быть изменено название ключа для компилятора.
Ограничения видимости типов через наследование companion object
В Kotlin 1.3 планируются потенциально ломающие изменения связанные с видимостью через companion object. Для того чтобы сглядить этот переход в Kotlin 1.2.40 вводится warning на использование краткого имени (non-qualified) для доступа к внутренностям companion object’а родительского класса. В примере ниже безо взякого импорта, мы можем получить доступ к классу внутри companion object’а нашего супертипа. Именно это и хотят постепенно запретить. Хорошая новость, Kotlin Plugin на борту содержит туллинг для миграции этого кейса, так что, если вы писали подобный код, то миграция поможет вам обновиться. Пример кода, ниже:
interface Bar {
companion object {
class FromBarCompanion
}
}
class Foo : Bar {
fun foo(): FromBarCompanion = TODO()
// Warning: access to this type by short name
// is deprecated and is going to be removed.
}
В Kotlin 1.3 запретят такие конструкции в принципе. Мне нравится, что разработчики языка тестируют доступную кодовую базу на 1.5 млн. строк кода для оценки важности этого изменения. В данном случае влияние изменения ожидается минимальным.
Intellij IDEA. Улучшения плагина
Добавлен интеншен для добавления явного return из лямбды. Гифка скажет всё за меня:
Добавлен интеншен для добавления и удаления use-site targets аннотаций. В Kotlin на одну аннотацию (например, в primary конструкторе) может приходиться несколько Java аннотаций. Для контроля того какая именно аннотация нужна вводятся Use-Site Target. Их-то мы и контролируем. Для интересующихся, вот ссылка на документацию по этому виду аннотаций.
Добавлена инспекция на подсветку и удаление необязательных явных ссылок на companion object’ы.
Сделаны улучшения по стабильности и производительности.
Изменения в компиляторе
Улучшена производительность и поправлены некоторые известные проблемы.
Обещают более эффективный генерируемый компилятором код для следующийх ситуаций: доступ к private свойствам companion object’ов, проверка enum’ов на равенство, сравнение Long’ов.
Заключение
Релиз понравится тем, кто не может жить без inline лямбд в корутинах, любителям плодить common модули в мультиплатформенных проектах, тем кто пишет Kotlin “рядом” с Java. В целом есть приятные маленькие улучшения в плагине и радостно видеть, что ошибки дизайна, как в случае с видимостью типов из чужих companion object’ов, исправляются по намеченому плану: deprecated -> restricted.
Чтобы быть в курсе последних событий присоединяйтесь к Telegram (@from_junior_to_senior)
Источник comments powered by Disqus