Spec-Zone.ru › Kotlin 1.9

Эволюция Kotlin

Принципы прагматичной эволюции

Проектирование языка — дело жёсткое,

но этот камень довольно мягок,

и приложив усилия, мы сможем его переформировать позже.

Команда разработчиков Kotlin

Kotlin разработан как прагматичный инструмент для программистов. В вопросах эволюции языка его прагматичность отражается в следующих принципах:

  • Сохранять современность языка на протяжении многих лет.

  • Поддерживать постоянную обратную связь с пользователями.

  • Обеспечить удобство обновления до новых версий для пользователей.

Поскольку это ключевой момент для понимания дальнейшего развития Kotlin, давайте подробнее рассмотрим эти принципы.

Сохранение современности языка. Мы признаем, что системы со временем накапливают устаревший код. Технологии, которые когда-то были передовыми, могут сегодня быть совершенно устаревшими. Мы должны развивать язык, чтобы он оставался актуальным для потребностей пользователей и соответствовал их ожиданиям. Это включает не только добавление новых функций, но и постепенное удаление устаревших, которые больше не рекомендуются для использования в производстве и вообще стали «наследием».

Удобные обновления. Несовместимые изменения, такие как удаление элементов из языка, могут привести к болезненной миграции с одной версии на другую, если их не выполнить с должной заботой. Мы всегда будем объявлять о таких изменениях заранее, помечать элементы как устаревшие и предоставлять автоматические инструменты миграции до внесения изменения. К моменту изменения языка мы хотим, чтобы большая часть кода в мире уже была обновлена, и, таким образом, не возникало проблем при миграции на новую версию.

Цикл обратной связи. Прохождение этапов устаревания требует значительных усилий, поэтому мы хотим свести к минимуму количество несовместимых изменений, которые будем вносить в будущем. Помимо использования нашего опыта, мы считаем, что лучший способ подтвердить дизайн — протестировать его в реальных условиях. Прежде чем окончательно закрепить что-либо, мы хотим протестировать это в реальных условиях. Вот почему мы используем каждую возможность, чтобы сделать ранние версии наших дизайнов доступными в производственных версиях языка, но в одном из предоставленных статусов: Экспериментальный, Альфа или Бета. Такие функции не являются стабильными, они могут быть изменены в любое время, и пользователи, которые выбирают их использование, делают это явно, чтобы указать, что они готовы к будущим проблемам миграции. Эти пользователи предоставляют неоценимую обратную связь, которую мы собираем, чтобы уточнять дизайн и сделать его надёжным.

Несовместимые изменения

Если при обновлении с одной версии на другую какой-либо код, который ранее работал, больше не работает, это несовместимое изменение в языке (иногда называемое «изменением, ломающим код»). В некоторых случаях может быть спор о том, что именно означает «больше не работает», но это определённо включает в себя следующее:

  • Код, который успешно компилировался и выполнялся, теперь отклоняется с ошибкой (во время компиляции или линковки). Это включает удаление конструкций языка и добавление новых ограничений.

  • Код, который выполнялся нормально, теперь генерирует исключение.

Менее очевидные случаи, которые относятся к «серой области», включают обработку особых случаев иначе, вызов исключения другого типа, изменение поведения, наблюдаемого только через рефлексию, изменения недокументированного/неопределённого поведения, переименование двоичных артефактов и т. д. Иногда такие изменения очень важны и существенно влияют на опыт миграции, иногда они несущественны.

Примеры того, что определённо не является несовместимым изменением:

  • Добавление новых предупреждений.

  • Включение новых конструкций языка или ослабление ограничений для существующих.

  • Изменение частных/внутренних API и других деталей реализации.

Принципы «Сохранение современности языка» и «Удобные обновления» предполагают, что несовместимые изменения иногда необходимы, но их следует вводить с осторожностью. Наша цель — информировать пользователей о предстоящих изменениях заранее, чтобы они могли комфортно мигрировать свой код.

В идеале каждое несовместимое изменение должно объявляться с помощью предупреждения во время компиляции, отображаемого в проблемном коде (обычно называемого предупреждением об устаревании) и сопровождаться автоматическими средствами миграции. Идеальный процесс миграции выглядит следующим образом:

  • Обновление до версии A (где объявляется изменение)

    • Просмотр предупреждений о предстоящем изменении

    • Миграция кода с помощью инструментов

  • Обновление до версии B (где происходит изменение)

    • Отсутствие каких-либо проблем

На практике некоторые изменения нельзя точно определить на этапе компиляции, поэтому никакие предупреждения не могут быть отображены, но пользователи будут проинформированы о предстоящем изменении в примечаниях к выпуску версии А.

Обработка ошибок компилятора

Компиляторы — это сложное программное обеспечение, и несмотря на все усилия их разработчиков, в них могут быть ошибки. Ошибки, которые приводят к сбоям самого компилятора или к выдаче ложных ошибок или генерации очевидно ошибочного кода, хотя и раздражают, а иногда и постыдны, легко исправляются, так как исправления не являются несовместимыми изменениями. Другие ошибки могут заставить компилятор генерировать некорректный код, который не приводит к сбоям: например, пропуская некоторые ошибки в исходном коде или просто генерируя неправильные инструкции. Исправления таких ошибок технически являются несовместимыми изменениями (некоторый код раньше компилировался нормально, но теперь этого сделать нельзя), но мы склонны исправлять их как можно скорее, чтобы предотвратить распространение плохих шаблонов кода в коде пользователей. На наш взгляд, это способствует принципу удобных обновлений, поскольку у меньшего количества пользователей есть возможность столкнуться с проблемой. Конечно, это относится только к ошибкам, которые обнаружены вскоре после появления в выпущенной версии.

Процесс принятия решений

JetBrains, первоначальный создатель Kotlin, продвигает его развитие с помощью сообщества и в соответствии с Фондом Kotlin.

Все изменения в языке программирования Kotlin контролируются Главным разработчиком языка (в настоящее время Роман Елизаров). Главный разработчик имеет окончательное слово по всем вопросам, связанным с эволюцией языка. Кроме того, несовместимые изменения в полностью стабильных компонентах должны быть одобрены Комитетом по языку, назначенным Фондом Kotlin (в настоящее время состоит из Джеффри ван Гоха, Уильяма Р. Кука и Романа Елизарова).

Комитет по языку принимает окончательные решения о том, какие несовместимые изменения будут внесены и какие именно меры должны быть предприняты для удобства обновления пользователей. При этом он руководствуется набором руководящих принципов, доступных здесь.

Выпуск новых функций и инкрементные релизы

Стабильные релизы с версиями 1.2, 1.3 и т. д. обычно считаются релизами новых функций, вносящими существенные изменения в язык. Обычно мы публикуем инкрементные релизы, пронумерованные 1.2.20, 1.2.30 и т. д., между релизами новых функций.

Инкрементные релизы включают обновления инструментов (часто с новыми функциями), улучшения производительности и исправления ошибок. Мы стараемся поддерживать совместимость таких версий друг с другом, поэтому изменения компилятора в основном сводятся к оптимизациям и добавлению/удалению предупреждений. Предварительные стабильные функции, конечно, могут быть добавлены, удалены или изменены в любое время.

Релизы новых функций часто добавляют новые функции и могут удалять или изменять ранее устаревшие. Переход функций от предварительно стабильного состояния к стабильному также происходит в релизах новых функций.

Сборки EAP

Перед выпуском стабильных версий мы обычно публикуем ряд предварительных сборок, именуемых EAP (для "Early Access Preview"), что позволяет нам быстрее итеративно работать и собирать отзывы сообщества. EAP релизов новых функций обычно производят бинарные файлы, которые впоследствии будут отклонены стабильным компилятором, чтобы убедиться, что возможные ошибки в бинарном формате не сохранятся дольше периода предварительного просмотра. Окончательные кандидаты на выпуск обычно лишены этого ограничения.

Предварительно стабильные функции

В соответствии с принципом цикла обратной связи, описанным выше, мы итеративно работаем над нашими проектами открыто и выпускаем версии языка, где некоторые функции имеют статус предварительно стабильных и предполагается, что изменятся. Такие функции могут быть добавлены, изменены или удалены в любое время и без предупреждения. Мы прилагаем все усилия, чтобы предотвратить случайное использование предварительно стабильных функций неосведомленным пользователем. Такие функции обычно требуют какой-либо явной опции включения, как в коде, так и в конфигурации проекта.

Предварительно стабильные функции обычно переходят в стабильное состояние после нескольких итераций.

Статус различных компонентов

Для проверки статуса стабильности различных компонентов Kotlin (Kotlin/JVM, JS, Native, различных библиотек и т. д.) обратитесь к этой ссылке.

Библиотеки

Язык ничто без своего экосистемы, поэтому мы уделяем особое внимание обеспечению плавного развития библиотек.

В идеале новая версия библиотеки может использоваться как «замена без переделки» для старой версии. Это означает, что обновление бинарной зависимости не должно вызывать ошибок, даже если приложение не перекомпилируется (это возможно при динамической подгрузке).

С одной стороны, для достижения этого компилятор должен предоставлять определённые гарантии стабильности ABI в рамках ограничений отдельной компиляции. Именно поэтому каждое изменение в языке рассматривается с точки зрения бинарной совместимости.

С другой стороны, многое зависит от того, насколько внимательны авторы библиотек в отношении того, какие изменения можно безопасно внести. Поэтому очень важно, чтобы авторы библиотек понимали, как изменения исходного кода влияют на совместимость, и соблюдали определённые лучшие практики, чтобы поддерживать стабильность как API, так и ABI своих библиотек. Ниже приведены некоторые предположения, которые мы делаем при рассмотрении изменений языка с точки зрения развития библиотек:

  • Код библиотеки всегда должен явно указывать возвращаемые типы публичных/защищённых функций и свойств, не полагаясь на вывод типов для публичного API. Незначительные изменения в выводе типов могут привести к непредвиденному изменению возвращаемых типов, что приведёт к проблемам бинарной совместимости.

  • Перегруженные функции и свойства, предоставляемые одной и той же библиотекой, должны делать по существу одно и то же. Изменения в выводе типов могут привести к более точным статическим типам, известным в местах вызова, вызывая изменения в решении перегрузки.

Авторы библиотек могут использовать аннотации @Deprecated и @RequiresOptIn для управления развитием своей поверхности API. Обратите внимание, что @Deprecated(level=HIDDEN) может использоваться для сохранения бинарной совместимости даже для объявлений, удалённых из API.

Кроме того, по соглашению, пакеты с именем «internal» не считаются общедоступным API. Весь API, находящийся в пакетах с именем «experimental», считается предварительно стабильным и может изменяться в любой момент.

Мы развиваем Kotlin Standard Library (kotlin-stdlib) для стабильных платформ в соответствии с вышеизложенными принципами. Изменения в контрактах для её API проходят те же процедуры, что и изменения в самом языке.

Ключи компилятора

Ключи командной строки, принимаемые компилятором, также являются своего рода общедоступным API, и они подлежат тем же соображениям. Поддерживаемые флаги (те, которые не имеют префикса "-X" или "-XX") могут быть добавлены только в релизах новых функций и должны быть надлежащим образом устаревшими перед удалением. Флаги "-X" и "-XX" являются экспериментальными и могут быть добавлены и удалены в любое время.

Инструменты совместимости

По мере удаления устаревших функций и исправления ошибок исходный язык изменяется, и старый код, который не был должным образом мигрирован, может больше не компилироваться. Обычный цикл устаревания позволяет комфортный период времени для миграции, и даже когда он завершается и изменение включено в стабильную версию, всё ещё есть возможность компилировать немигрированный код.

Флаги совместимости

Мы предоставляем флаги -language-version X.Y и -api-version X.Y, которые позволяют новой версии эмулировать поведение старой для целей совместимости. Чтобы дать вам больше времени на миграцию, мы поддерживаем разработку трёх предыдущих версий языка и API в дополнение к последней стабильной.

Активно поддерживаемые базы кода могут извлечь выгоду из получения исправлений ошибок как можно скорее, не дожидаясь завершения полного цикла устаревания. В настоящее время такие проекты могут включить флаг -progressive и получить такие исправления, включённые даже в инкрементные релизы.

Все флаги доступны в командной строке, а также в Gradle и Maven.

Развитие бинарного формата

В отличие от исходных кодов, которые в худшем случае можно исправить вручную, бинарные файлы гораздо сложнее мигрировать, что делает обратную совместимость очень важной в случае бинарных файлов. Несовместимые изменения в бинарных файлах могут сделать обновления очень неудобными, и поэтому они должны вводиться ещё с большей осторожностью, чем изменения в синтаксисе исходного языка.

Для полностью стабильных версий компилятора протокол бинарной совместимости по умолчанию следующий:

  • Все бинарные файлы обратной совместимы, т. е. более новый компилятор может читать более старые бинарные файлы (например, 1.3 понимает 1.0–1.2).

  • Более старые компиляторы отклоняют бинарные файлы, которые полагаются на новые функции (например, компилятор 1.0 отклоняет бинарные файлы, использующие сопрограммы).

  • В идеале (но мы не можем этого гарантировать) бинарный формат в основном совместим с последующим выпуском новой функции, но не с более поздними (в тех случаях, когда новые функции не используются, например, 1.3 может понять большинство бинарных файлов из 1.4, но не из 1.5).

Этот протокол разработан для удобных обновлений, так как ни один проект не может быть заблокирован от обновления своих зависимостей, даже если он использует немного устаревший компилятор.

Обратите внимание, что не все целевые платформы достигли такого уровня стабильности (но Kotlin/JVM — да).

Последнее изменение: 24 января 2023 г.
FAQ Стабильность компонентов Kotlin

© 2010–2023 JetBrains s.r.o. and Kotlin Programming Language contributors
Licensed under the Apache License, Version 2.0.
https://kotlinlang.org/docs/kotlin-evolution.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API