Kotlin Updates Report 1.2.40

Обзор изменений в Kotlin 1.2.40

Автор: Ivan Osipov
Дата публикации: 2018-04-20
В категориях: Development, Kotlin, News, Practice, Вольный Перевод
Тэги: development, kotlin, report, intellij idea, tooling

Вчера вечером вышло описание нововведений в 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 из лямбды. Гифка скажет всё за меня:

Intention1

Добавлен интеншен для добавления и удаления 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