Котлин язык


Архитектор Kotlin: «Язык программирования — рабочий инструмент. Если никогда их не менять, можно отстать от жизни»

В феврале 2016-го, после шести лет разработки, компания JetBrains выпустила в релиз версию 1.0 статически типизированного языка программирования Kotlin. Его авторы ставили целью создать язык «более лаконичный и типобезопасный, чем Java, и более простой, чем Scala». О том, что из этого вышло, а также о моде на языки программирования, конкуренции между ними, перспективах и «серебряной пуле» в интервью dev.by рассказал руководитель разработки проекта Kotlin в JetBrains​ Андрей Бреслав.   

— Первому релизу Kotlin предшествовали шесть лет разработки. Получилось ли у вас то, к чему стремились?

— В разные моменты мы стремились к разным вещам, но большая часть из того, что сейчас мы считаем правильными целями, состоялась. Мы хотели сделать удобный язык для разработчиков с широким кругом задач — получилось. Мы хотели сделать язык, который будет нравиться людям и сделает их жизнь заметно лучше — результатом мы довольны. Цели в процессе менялись: менялись приоритеты, появлялись новые внешние обстоятельства — конкуренты, новые платформы. Например, Android, о котором мы изначально не думали, стал для нас очень интересной и важной платформой, и сейчас мы получаем аудиторию в среде Android-разработчиков. Мы придумали компилироваться в JavaScript — сразу такой мысли не было, а сейчас понятно, что это тоже очень полезное направление.

— Кстати, о конкурентах. За последние 10-15 лет языков под JVM развелось много, и многие на слуху: Groovy, Gosu, Ceylon. Почему этих разработок так много? Почему не удаётся сконцентрироваться на какой-то одной, особенно в случаях, когда цели схожи?

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

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

Многие языки возникают, чтобы заполнить новые или пустующие ниши. Например, Gosu изначально создавался для внуренних конфигурационных скриптов, то есть как язык внутри конкретного продукта компании Guidewire, и только потом отделился и стал более самостоятельным. Groovy — одна из первых успешных попыток сделать динамически типизированный язык специально для JVM, и в какой-то момент он стал новым словом в этом направлении.

— Многие ли идеи конкурентов перекочевали в Kotlin?

— Мы использовали всё полезное, что нашли у других: цели придумывать всё с нуля не было. Из названных языков по задачам мы пересекаемся с Ceylon, но общий набор требований у нас другой. Большой упор в Kotlin — на взаимодействие с существующим кодом, так называемый interop с Java, а создатели Ceylon от этой идеи отказались. Они запускаются на JVM, но при этом полностью переписывают стандартную библиотеку: вместо классов из JDK используется их собственная SDK. Это сильно меняет дело: подмешать немножечко Ceylon в существующий проект на Java — большая проблема просто потому, что язык создан не для этого, а для того, чтобы на нём с нуля разрабатывать красивые проекты. А Kotlin хорошо подходит для уже существующих проектов.

— Создание обратной совместимости с Java и стало самой сложной частью проекта?

— Да, это, пожалуй, принесло больше всего головной боли. По пути мы перебрали четыре основных схемы взаимодействия с библиотеками Java. Первая была очень консервативной: мы считали, что код на Java очень небезопасен, и в Kotlin нужно проверять всё, что можно. Оказалось, что это очень неудобно. Потом мы пытались аннотировать Java-библиотеки, чтобы внести в код на Java дополнительную типовую информацию и её использовать — это решение оказалось слишком хрупким. Закончили мы тем, что создали концепцию платформенных типов, у меня есть целый доклад о ней на JVM Language Summit. Модель достаточно сложна и оригинальна, но на практике она работает хорошо.

— Вернёмся к релизу. Первый фидбек уже собран? Что понравилось пользователям?

— Разным людям — разные вещи. Очень многим нравится, что программы становятся короткими и понятными, что компилятор ловит ошибки, которые другие компиляторы не поймали бы.

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

— Появились ли в последние лет 10-15 языки, которые уже стали поворотными для сферы или могут ими стать?

— Есть такое образное выражение: «Язык превратился в COBOL». Казалось бы, COBOL — старый язык, который должны давно забыть, но в реальности на нём работает ещё очень много систем, особенно в финансовой сфере. Мы наверняка пишем на Java больше новых проектов, чем на COBOL, но при этом я не брался бы утверждать, что мы пишем больше кода на Java в целом :).

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

В своё время C в этом смысле совершил революцию, Java тоже стала судьбоносным языком. Из более новых языков не смогу назвать ни одного —  наверное, прошло недостаточно много времени, чтобы они могли набрать такую популярность. Но в любом случае, очень успешные языки были. На JVM это Scala и Groovy, на которых крупные компании написали уже немало кода. Вне JVM в своё время имел огромный успех Ruby, на нём писали крупные web-проекты; потом случился кризис роста, люди стали отказываться от Ruby, но этот язык так или иначе серьёзно повлиял на восприятие динамических языков программирования.

Очень большое влияние на направление мысли оказывают функциональные языки. С одной стороны, это языки семейства Lisp-Scheme и всё, что рядом с ним. На JVM есть Clojure, который воплощает те же идеи. С другой стороны — Haskell и другие языки семейства ML. Думаю, что хорошо закрепится Swift, поскольку Apple переводит на него разработчиков для своих платформ, а платформа — вещь такая, что с ней не поспоришь. Раз велено писать на Swift под устройства Apple, значит, все будут писать на Swift — а язык очень хороший, поэтому никакого сопротивления я не ожидаю.

— Как вы считаете, стоит ли гнаться за модой на языки?

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

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

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

— Тот же Ruby, да и Swift тоже, частенько называют «хипстерскими языками». Почему они стали такими модными?

— Элемент моды возникает там, где пишутся короткие маленькие проекты. Люди начинают новый проект каждые три месяца и могут себе позволить очередной из них написать на Ruby или на новомодной технологии на базе JavaScript. Естественно, этот эффект хайпа недолговечен, как и любая мода. В мире клиентской разработки это видно особенно ярко: фреймворки и системы программирования на JavaScript сменяют одна другую со страшной скоростью. Мы даже испытываем некоторые сложности из-за этого при разработке Kotlin, потому что при компиляции в JavaScript нам нужно поддерживать какие-то популярные технологии, а их каждый день появляется очень много, и за всем очень сложно уследить. Для Swift всё сказанное тоже частично релевантно, но у этого языка принципиально другая судьба: это стандартное решение, которое поставляется вместе с платформой, и его выбирают не из-за моды.

— Есть ли, по-вашему, критерии, по которым язык может «выстрелить»?

— Возвращаясь к сказанному, самый надёжный способ «выстрелить» — быть языком, привязанным к платформе. В своё время C широко распространился, потому что он был языком для платформы Unix, которая была популярной и очень удобной. Java тоже в распространялась как платформа, и язык был её частью. То же касается C#: пускай это и не единственный, но основной язык для платформы .NET. Опять же, есть JavaScript, который популярен не потому, что он хороший или плохой, а потому, что это язык для браузера, браузер нужен всем.

Дать надежный рецепт «Как сделать язык, который станет популярным», я не могу, но есть и другие понятные причины, по которым языки становятся популярными.

Есть языки, которые распространяются по идеологическим моделям — например, Haskell или в какой-то степени Python. Но идеология — это скорее способ сформировать комьюнити, а не удержать его. Тот же Python — это просто хороший язык для многих задач. А вот кто победит из нескольких конкурирующих языков, которые не являются частью платформы и не являются идеологической революцией — как Kotlin, например, — решает рынок.

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

— В каком направлении сейчас меняются языки программирования?

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

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

— Чего, на ваш взгляд, современным языкам не хватает? Что в них «ещё не пришло» из того, что уже, казалось бы, должно?

— Про языки мне сложно ответить: если бы знал, чего не хватает, уже добавил бы! Мне кажется, что основные болезненные места на сегодня связаны, как я отмечал выше, с многопоточностью. А там главная сложность в том, что никто не знает хорошей модели для многопоточного программирования. Сама эта идея — независимые нитки исполнения, имеющие общую память — несколько противоестественная, и порождает тяжкие ухищрения на аппаратном уровне. Процессор, синхронизируя кеши между ядрами, фактически реализует message passing, но мы притворяемся, что этого нет, и на самом деле у нас разделяемая память. Но чтобы как-то совладать с многопоточным программированием, мы стараемся поменьше пользоваться разделяемой памятью, и программно реализуем поверх неё — снова message passing!

Так получилось исторически: новые процессоры эмулируют поведение старых для совместимости, поэтому сменить парадигму радикально очень сложно. И это отражается на программировании, конечно. Если бы железо могло быть гибче, программирование тоже было бы другим, я думаю. Но мы все в этом смысле связаны во многом всё той же совместимостью. Можно сделать всё очень здорово — и процессор и языки, но только программ и библиотек под это все никаких не будет, и пользователи останутся на традиционных платформах...

— У программистов есть давняя мечта о «серебряной пуле» — одном языке, который удовлетворил бы большинство или даже всех. Возможно ли его появление?

— Думаю, в обозримое время ни один язык не победит. Есть искусственные ситуации, в которых можно писать только на одном языке: например, в случае с клиентским вебом. Основным языком браузера был и остаётся JavaScript, и не очень понятно, может ли это измениться. А в остальных случаях, когда есть свобода выбора, я не вижу никаких предпосылок к появлению универсальной идеи, которая бы всех примирила. Слишком уж много противоречивых требований.

— Программирование становится всё более популярным. Сложится ли так, что через какое-то время программировать должен будет уметь каждый?

— Не думаю, что такое должно произойти. У людей есть автоматически не приобретаемые навыки, которые нужны всем. Например, писать на родном языке или считать. А вот зачем всем на свете нужно будет программировать, я себе представить не могу. Непрограммисты иногда пишут программы, но, как правило, этим всё же занимаются профессионалы. Например, инженеры, которые работают с численными моделями и используют специализированные языки программирования для математического моделирования. Или люди, которые пользуются сложными офисными программами — внутри того же Microsoft Office есть язык программирования Visual Basic for Applications, на котором часто пишут достаточно сложные вещи.

Если человек по роду деятельности никак не связан с таким набором задач, то зачем ему программировать? Многие считают, что раз компьютеры — передний край прогресса, значит, все должны разбираться в компьютерах. Когда квантовая физика казалась передним краем прогресса, многие думали, что все будут очень «квантово» жить, но на самом деле никто не будет жить более «квантово», чем живёт сейчас, по-моему.

— Тем не менее, пока число программистов растёт, и количество запросов на программы тоже растёт.

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

— Стоит ли тогда, на ваш взгляд, преподавать программирование в школе?

— Я сам восемь лет преподавал программирование в физико-математической школе, и мне кажется, что это столь же разумно, как и преподавание математики или физики. Другой вопрос — содержание курса. Как правильно преподавать программирование в школе без специализации или с гуманитарным уклоном, я не знаю, но всё равно считаю, что это может быть полезным. Программирование развивает алгоритмические и аналитические навыки мышления, очень полезные по жизни, даже если человек никогда больше не будет писать программы.

Об особенностях и практическом применении языка Kotlin можно будет подробно узнать в ходе выступления Бориса Ванина, Java-архитектора с 7-летним стажем, на конференции JavaDay Minsk в субботу, 11 июня.    

 

Фото: JUG.ru

dev.by

Основной синтаксис - Kotlin

Определение имени пакета

Имя пакета указывается в начале исходного файла, так же как и в Java:

package my.demo import java.util.* // ...

Но в отличие от Java, нет необходимости, чтобы структура пакетов совпадала со структурой папок: исходные файлы могут располагаться в произвольном месте на диске.

См. Пакеты.

Объявление функции

Функция принимает два аргумента Int и возвращает Int:

fun sum(a: Int, b: Int): Int { return a + b }

Функция с выражением в качестве тела и автоматически выведенным типом возвращаемого значения:

fun sum(a: Int, b: Int) = a + b

Функция, не возвращающая никакого значения (void в Java):

fun printSum(a: Int, b: Int): Unit { print(a + b) }

Тип возвращаемого значения Unit может быть опущен:

fun printSum(a: Int, b: Int) { print(a + b) }

См. Функции.

Определение внутренних переменных

Неизменяемая (только для чтения) внутренняя переменная:

val a: Int = 1 val b = 1 // Тип `Int` выведен автоматически val c: Int // Тип обязателен, когда значение не инициализируется c = 1 // последующее присвоение

Изменяемая переменная:

var x = 5 // Тип `Int` выведен автоматически x += 1

См. Свойства и поля.

Комментарии

Также, как Java и JavaScript, Kotlin поддерживает однострочные комментарии.

// однострочный комментарий /* Блочный комментарий из нескольких строк. */

В отличие от Java, блочные комментарии не могут быть вложенными.

См. Documenting Kotlin Code для информации о документации в комментариях.

Использование строковых шаблонов

Допустимо использование переменных внутри строк в формате $name или ${name}:

fun main(args: Array<String>) { if (args.size == 0) return print("Первый аргумент: ${args[0]}") }

См. Строковые шаблоны.

Использование условных выражений

fun max(a: Int, b: Int): Int { if (a > b) return a else return b }

Также if может быть использовано как выражение (т. е. if ... else возвращает значение):

fun max(a: Int, b: Int) = if (a > b) a else b

См. Выражение if.

Nullable-значения и проверка на null

Ссылка должна быть явно объявлена как nullable (символ ?) когда она может принимать значение null.

Возвращает null если str не содержит числа:

fun parseInt(str: String): Int? { // ... }

Использование функции, возвращающей null:

fun main(args: Array<String>) { if (args.size < 2) { print("Ожидается два целых числа") return } val x = parseInt(args[0]) val y = parseInt(args[1]) // Использование `x * y` приведет к ошибке, потому что они могут содержать null if (x != null && y != null) { // x и y автоматически приведены к не-nullable после проверки на null print(x * y) } }

или

// ... if (x == null) { print("Неверный формат числа у '${args[0]}'") return } if (y == null) { print("Неверный формат числа у '${args[1]}'") return } // x и y автоматически приведены к не-nullable после проверки на null print(x * y)

См. Null-безопасность.

Проверка типа и автоматическое приведение типов

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

fun getStringLength(obj: Any): Int? { if (obj is String) { // в этом блоке `obj` автоматически преобразован в `String` return obj.length } // `obj` имеет тип `Any` вне блока проверки типа return null }

или

fun getStringLength(obj: Any): Int? { if (obj !is String) return null // в этом блоке `obj` автоматически преобразован в `String` return obj.length }

или даже

fun getStringLength(obj: Any): Int? { // `obj` автоматически преобразован в `String` справа от оператора `&&` if (obj is String && obj.length > 0) return obj.length return null }

См. Классы и Приведение типов.

Использование цикла for

fun main(args: Array<String>) { for (arg in args) print(arg) }

или

for (i in args.indices) print(args[i])

См. цикл for.

Использование цикла while

fun main(args: Array<String>) { var i = 0 while (i < args.size) print(args[i++]) }

См. цикл while.

Использование выражения when

fun cases(obj: Any) { when (obj) { 1 -> print("One") "Hello" -> print("Greeting") is Long -> print("Long") !is String -> print("Not a string") else -> print("Unknown") } }

См. выражение when.

Использование интервалов

Проверка на вхождение числа в интервал с помощью оператора in:

if (x in 1..y-1) print("OK")

Проверка значения на выход за пределы интервала:

if (x !in 0..array.lastIndex) print("Out")

Итерация по интервалу:

for (x in 1..5) print(x)

Или по арифметической прогрессии:

for (x in 1..10 step 2) { print(x) } for (x in 9 downTo 0 step 3) { print(x) }

См. Интервалы.

Использование коллекций

Итерация по коллекции:

for (name in names) println(name)

Проверка, содержит ли коллекция данный объект, с помощью оператора in:

val items = setOf("apple", "banana", "kiwi") when { "orange" in items -> println("juicy") "apple" in items -> println("apple is fine too") }

Использование лямбда-выражения для фильтрации и модификации коллекции:

names .filter { it.startsWith("A") } .sortedBy { it } .map { it.toUpperCase() } .forEach { print(it) }

См. Функции высшего порядка и лямбды.

kotlinlang.ru

Наука в университете ИТМО

  1. ←  Все новости

Язык программирования Kotlin, разработанный петербургской компанией JetBrains, стал официальным языком разработок для Android. Об этом официально объявили на конференции Google I/O. Командой Kotlin руководит выпускник Университета ИТМО Андрей Бреслав. Почему именно Kotlin так полюбился IT-гиганту среди многих других «молодых» языков, как и зачем вообще появляются новые языки программирования, читайте в комментариях экспертов и информационной подборке ITMO.NEWS.

Как разрабатываются языки программирования

По разных подсчетам, в мире уже более двух тысяч разных языков программирования. Для старых языков постоянно выходят обновления, а также появляются новые языки. Когда синтаксис языка не меняется, а лишь усложняется и дополняется, разработчику достаточно немного потренироваться, чтобы продолжать писать на любимом языке. Иногда же меняется сама структура языка, и тогда программисту подчас приходится переучиваться, адаптируясь к обновленному языку. Обычно переход на новую структуру идет постепенно и частями, то есть только 10-20% программного кода начинает писаться с помощью нового языка.

«Программисты не были абсолютно довольны языками С++ и Java, потому что это достаточно сложные языки, при этом первый сложнее, чем второй. Поэтому появился язык Scala, который нравится многим программистам, но и он весьма сложен. Огромный опыт компании JetBrains в создании средств разработки программ для разных языков программирования позволил за семь лет создать язык Kotlin, который полностью совместим с Java, но проще и удобнее его. Языки программирования разрабатываются постоянно, задачу сделать универсальный язык уже никто перед собой не ставит. Несмотря на это, каждый язык более эффективен в определенной области, где его чаще всего и используют. Есть даже такое направление в создании языков, когда они разрабатываются под конкретную предметную область», – прокомментировал заведующий кафедрой технологии программирования Университета ИТМО Анатолий Шалыто.

Анатолий Шалыто

Сегодня некоторые компании даже составляют свои рейтинги языков. Например, компания TIOBE, которая специализируется в оценке качества программного обеспечения, ежемесячно вычисляет индекс популярности тех или иных языков с 2001 года. В генерируемом списке 50 строчек, и чтобы язык программирования попал в индекс, разработчики должны написать соответствующее письмо в компанию. Подсчет ведется на основе данных 25 поисковых Интернет-систем. Пока в рейтинге с большим отрывом лидирует Java, за ней идет С. При этом составители списка подчеркивают, что за последний год оба языка программирования стали менее популярными, примерно на 6%. При этом TIOBE показывает, что язык С был языком №1 вплоть до 2002 года, а Java в 1997 году была на 14 месте, но уже через пять лет заменил С на первой позиции.

Отличную лекцию по истории развития языков можно послушать здесь: о том, как появились языки С, PHP, Ruby и Java рассказывает куратор академических программ «Яндекса», директор центра студенческих олимпиад факультета компьютерных наук ВШЭ Михаил Густокашин. Лектор подчеркивает, что для каждой задачи следует выбирать разный язык программирования. Например, он говорит, что для военной промышленности лучше всего писать на старом-добром Pascal – языке, который родился еще в 1970 году! Почему? Потому что он надежней. Приложения для бизнеса можно писать на Java, потому что этот язык тоже достаточно надежен, но гораздо более прост в использовании. Эксперт также подчеркивает, что важно поддерживать интерес к языку среди программистов с помощью создания сообщества разработчиков, которые пишут на этом языке. Если вокруг какого-нибудь нового языка создается инфраструктура, собираются люди, которые им пользуются, только тогда язык станет популярным. Кстати, разработчики Kotlin тоже взяли на вооружение эту стратегию.

Немного о  Kotlin

Язык программирования Kotlin начал разрабатываться в петербургской компании JetBrains в 2010 году. Официальный релиз продукта был выпущен в 2016 году. Такое название язык получил в честь острова в Финском заливе, на котором расположен Кронштадт. По интересному совпадению, название популярного языка Java – это тоже имя острова в Индонезии. Вероятно, совпадение не случайно. Как сообщается в пресс-релизе, Kotlin должен работать везде, где работает Java, и один из ориентиров был сделать такой продукт, который можно будет использовать в смешанных проектах, которые создаются на нескольких языках.

Язык программирования Kotlin. Источник: cdn-business.discourse.org

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

«Инструменты разработки, включая языки программирования, постоянно развиваются. Языки отличаются от других инструментов тем, что их довольно сложно развивать эволюционно. Новая версия языка должна поддерживать все уже существующие программы. Это ограничивает возможности развития существующих языков и создает потребность в появлении новых. Фактор, который определяет успешность нового языка программирования, это, в первую очередь, удобство для разработчиков. Кроме краткости и выразительности, Kotlin хорошо совместим с кодом на Java: можно использовать все существующие библиотеки и даже смешивать код на двух языках в одном проекте, поэтому не возникает особенных сложностей с переходом», – прокомментировал Андрей Бреслав, руководитель проекта Kotlin в JetBrains, выпускник Университета ИТМО.

Почему Google полюбил Kotlin

На официальном сайте разработчики Android пишут, что они наблюдали «восхождение» Kotlin все последние годы. «Гуглеры» не стесняются описывать этот язык как впечатляющий и лаконичный, который отрывает больше возможностей и с которым приятно работать. Он обладает повышенной производительностью: программный код на нем получается в среднем на 40% короче, чем на других языках, а также Kotlin позволяет не допускать некоторые ошибки в коде. Одним из определяющих факторов популярности Kotlin в Google стало то, что он совместим с Java, который уже используется при разработке приложений под Android.

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

«Отсутствие гарантий поддержки языка со стороны Google отпугивало многих разработчиков от перехода на Kotlin. Даже если язык очень нравится,  программист всегда думает о риске, что в какой-то момент этот язык просто перестанет работать. Теперь есть гарантия того, что работать Kotlin не перестанет, и мы ожидаем, что количество пользователей языка резко возрастет. Было бы естественно предположить, что многие компании со временем перейдут на Kotlin полностью, хотя технически их к этому ничего не вынуждает, это просто вопрос предпочтений», – подчеркнул Андрей Бреслав.

Он добавил, что Kotlin очень активно развивается. Команда разработчиков сейчас работает над билд-системой, скоростью компиляции, улучшает производительность IDE, добавляет в инструментарий новые возможности, в том числе связанные с интеграцией в Android Studio. Также идет работа над мультиплатформенными проектами (возможность компилировать один и тот же код под несколько платформ), целый ряд языковых улучшений находится в стадии дизайна.

Андрей Бреслав

В Google также подчеркнули, что их вдохновляет концепт языка Kotlin, по которому он всегда был и останется бесплатным для разработчиков, то есть open source project. Это значит, что язык не привязан к какой-либо отдельной компании, а исходный код распространяется под свободной лицензией. Загрузить продукт можно здесь. Чтобы поддерживать развитие Kotlin, компаниями Google и JetBrains будет создано некоммерческое партнерство. Также в рамках «миссии» Android очень важно, что авторы Kotlin создают вокруг своего продукта сообщество людей, которые профессионально занимаются разработкой на этом языке и любят делиться опытом. Например, в ноябре в США состоится конференция Kotlin, также разработчики могут получать ежедневные новости и советы о программном продукте, встречаться на местном уровне.

Кстати, сам проект Android Studio был разработан на базе программной среды разработки IntelliJ IDEA, которую также создали в компании JetBrains. Но несмотря на тесной сотрудничество, в петербургской компании подчеркивают, что ни о какой продаже JetBrains американскому IT-гиганту речи не идет. При этом Koltin не будет заточен только под Android. Цель компании – сделать язык программирования подходящим под разные платформы разработки.

Please enable JavaScript to view the comments powered by Disqus.

research.ifmo.ru

Теперь официально / Блог компании JetBrains / Хабрахабр

Вчера на конференции Google I/O 2017 команда Android объявила об официальной поддержке языка Kotlin для разработки Android-приложений. Это огромный шаг вперед для Kotlin, и отличная новость для всего сообщества Android-разработчиков.

Kotlin дает разработчикам Android-приложений возможность использовать мощный современный язык, код на котором получается более компактным и надежным, уменьшая вероятность падения приложений у пользователей. Kotlin прост в освоении и отлично сочетается с Java, что позволяет постепенно внедрять его в существующие проекты, не теряя накопленный опыт, навыки и технологии.

Плагин для поддержки Kotlin теперь входит в поставку Android Studio 3.0, так что разработчикам не нужно ставить дополнительные плагины или беспокоиться о совместимости. JetBrains и Google также берут на себя обязательство поддерживать разработку на Kotlin и в будущем, по мере развития Android-платформы.

При этом другие платформы, которые поддерживают Kotlin (Kotlin/JVM для разработки серверных и десктопных приложений, Kotlin/JS для браузера и Kotlin/Nativе для нативной разработки) остаются не менее важными для JetBrains. Наше видение заключается в том, чтобы создать единый инструмент, позволяющий разрабатывать все компоненты современного приложения на одном и том же языке, независимо от того, на какой платформе эти компоненты запускаются. Это включает в себя и full-stack веб-приложения, и мобильные клиенты под Android и iOS, и встраиваемые платформы IoT, и другое. Как и с человеческими языками, для языка программирования очень полезно быть популярным. Официальная поддержка со стороны Android приведет к росту количества программистов на Kotlin, а это значит, что для Kotlin будет разрабатываться больше библиотек и инструментов, больше обучающих материалов, проще будет найти решения для возможных проблем или устроиться работать программистом на Kotlin. Мы очень рады новым перспективам, которые это открывает для экосистемы Kotlin!

Мы приняли решение о том, чтобы создать вокруг Kotlin некоммерческое партнерство совместно с Google. При этом разработка языка и в дальнейшем будет производиться силами JetBrains, и команда Kotlin (на данный момент более 40 человек) будет работать как и раньше. Ведущим дизайнером языка остается Андрей Бреслав, и принципы, которыми мы руководствуемся в разработке, никак не меняются. Наш дизайн по-прежнему будет открытым, потому что обратная связь со стороны сообщества необходима нам для того, чтобы развивать Kotlin в верном направлении.

19 мая 2017 года в 20:30 по московскому времени вы сможете посмотреть живую трансляцию доклада с Google I/O про Kotlin, который будут делать Андрей Бреслав и Хади Харири, ведущий евангелист JetBrains. А в ноябре у Kotlin состоится собственная конференция, которая пройдет в городе Сан-Франциско.

Огромное спасибо!

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

Мы крайне благодарны Google и Android-команде за то доверие, которое они нам оказали, но прежде всего мы благодарны вам — нашему сообществу, нашим пользователям. Без вас Kotlin не смог бы достичь того, чего он достиг сегодня. Спасибо вам, что вы были с нами на этом пути, и надеемся видеть вас с нами и дальше.

Частые вопросы

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

Будет ли Kotlin сфокусирован в первую очередь на Android?

Одна из основным целей Kotlin, и сейчас, и в будущем — это поддержка различных платформ. Мы продолжаем разрабатывать Kotlin/JVM (для серверных, десктопных и других приложений для Java-платформы) и Kotlin/JS. Для других платформ, таких, как macOS, iOS и встраиваемые/IoT системы, мы ведем работу над Kotlin/Native.

Как это повлияет на релизный цикл Kotlin?

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

Кто будет разрабатывать плагин для Android Studio?

Как и раньше, за разработку плагина для Android Studio будет отвечать JetBrains. Мы планируем плотно сотрудничать с командой Android Studio.

Повлияет ли это на поддержку Kotlin в IntelliJ IDEA, Eclipse или NetBeans?

Нет. Kotlin — это многоплатформенный язык, и мы будем вкладываться в поддержку различных IDE так же, как и раньше. Основные наши усилия сосредоточены на плагине для IntelliJ IDEA, и мы будем рады помощи сообщества в работе над плагинами под Eclipse и NetBeans.

Повлияет ли это на поддержку macOS и iOS?

Нет. Мы планируем поддержать обе эти платформы в Kotlin/Native, и этот план никак не меняется.

Собирается ли Google купить JetBrains?

Нет. JetBrains не планирует продаваться никакой другой компании. Мы были и остаемся независимым производителем инструментов для всех разработчиков, независимо от того, на каком языке и под какую платформу они программируют.

habrahabr.ru

Почему следует полностью переходить на Kotlin / Блог компании Mail.Ru Group / Хабрахабр

Хочу рассказать вам о новом языке программирования, который называется Kotlin, и объяснить, почему вам стоит использовать его в своём следующем проекте. Раньше я предпочитал Java, но в последний год пишу на Kotlin везде, где только можно. И в данный момент я не представляю себе ситуации, в которой лучше было бы выбрать Java.

Kotlin разработан в JetBrains, и участие тех же людей в создании наборов IDE, таких как IntelliJ и ReSharper, хорошо заметно по самому языку. Он прагматичен и краток, благодаря чему написание кода превращается в приятный и эффективный процесс.

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

Итак, несколько причин, почему вам следует полностью переходить на Kotlin (порядок случаен):

0# Совместимость с Java

Kotlin на 100 % совместим с Java. Вы можете в буквальном смысле продолжать работать над своим старым Java-проектом, но уже используя Kotlin. Все ваши любимые Java-фреймворки также будут доступны, и, в каком бы фреймворке вы ни писали, Kotlin будет легко принят упрямым любителем Java.

1# Знакомый синтаксис

Kotlin — не какой-то там странный язык, рождённый в академических кругах. Его синтаксис знаком любому программисту, воспитанному на парадигме ООП, и с самого начала может быть более-менее понятным. Конечно, есть некоторые отличия от Java вроде переработанного конструктора или объявлений переменных val var. В этом коде отражена большая часть базового синтаксиса:

class Foo { val b: String = "b" // val means unmodifiable var i: Int = 0 // var means modifiable fun hello() { val str = "Hello" print("$str World") } fun sum(x: Int, y: Int): Int { return x + y } fun maxOf(a: Float, b: Float) = if (a > b) a else b }

Это как бы более умная и читабельная версия String.format() из Java, встроенная в язык:

val x = 4 val y = 7 print("sum of $x and $y is ${x + y}") // sum of 4 and 7 is 11

3# Выведение типа

Kotlin будет выводить ваши типы, если вы посчитаете, что это улучшит читабельность:

val a = "abc" // type inferred to String val b = 4 // type inferred to Int val c: Double = 0.7 // type declared explicitly val d: List<String> = ArrayList() // type declared explicitly

4# Умные приведения типов (Smart Casts)

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

if (obj is String) { print(obj.toUpperCase()) // obj is now known to be a String }

5# Интуитивные равенства (Intuitive Equals)

Можно больше не вызывать явно equals(), потому что оператор == теперь проверяет структурное равенство:

val john1 = Person("John") val john2 = Person("John") john1 == john2 // true (structural equality) john1 === john2 // false (referential equality)

6# Аргументы по умолчанию

Больше не нужно определять несколько одинаковых методов с разными аргументами:

fun build(title: String, width: Int = 800, height: Int = 600) { Frame(title, width, height) }

7# Именованные аргументы

В сочетании с аргументами по умолчанию именованные аргументы избавляют от необходимости использовать Строителей:

build("PacMan", 400, 300) // equivalent build(title = "PacMan", width = 400, height = 300) // equivalent build(width = 400, height = 300, title = "PacMan") // equivalent

8# Выражение When

Оператор ветвления заменён гораздо более читабельным и гибким в применении выражением when:

when (x) { 1 -> print("x is 1") 2 -> print("x is 2") 3, 4 -> print("x is 3 or 4") in 5..10 -> print("x is 5, 6, 7, 8, 9, or 10") else -> print("x is out of range") }

Оно работает и как выражение (expression), и как описание (statement), с аргументом или без него:

val res: Boolean = when { obj == null -> false obj is String -> true else -> throw IllegalStateException() }

9# Свойства

Можно добавить публичным полям кастомное поведение set & get, т. е. перестать набивать код безумными геттерами и сеттерами.

class Frame { var width: Int = 800 var height: Int = 600 val pixels: Int get() = width * height }

10# Data Class

Он наполнен POJO-объектами toString(), equals(), hashCode() и copy(), но, в отличие от Java, не занимает 100 строк кода:

data class Person(val name: String, var email: String, var age: Int) val john = Person("John", "[email protected]", 112)

11# Перегрузка оператора (Operator Overloading)

Заранее определённый набор операторов, которые можно перегружать для улучшения читабельности:

data class Vec(val x: Float, val y: Float) { operator fun plus(v: Vec) = Vec(x + v.x, y + v.y) } val v = Vec(2f, 3f) + Vec(4f, 1f)

12# Деструктурирующие объявления (Destructuring Declarations)

Некоторые объекты могут быть деструктурированы, что бывает полезно, к примеру, для итерирования map:

for ((key, value) in map) { print("Key: $key") print("Value: $value") }

13# Диапазоны (Ranges)

Для улучшения читабельности:

for (i in 1..100) { ... } for (i in 0 until 100) { ... } for (i in 2..10 step 2) { ... } for (i in 10 downTo 1) { ... } if (x in 1..10) { ... }

14# Функции-расширения (Extension Functions)

Помните свой первый раз, когда пришлось сортировать List в Java? Вам не удалось найти функцию sort(), и пришлось изучать Collections.sort(). Позднее, когда нужно было в строковом значении заменить все буквы строчными, вам пришлось писать собственную вспомогательную функцию, потому что вы не знали о StringUtils.capitalize().

Если бы существовал способ добавления новых функций в старые классы, тогда ваш IDE помог бы найти правильную функцию при завершении кода. Именно это можно делать в Kotlin:

fun String.format(): String { return this.replace(' ', '_') } val formatted = str.format()

Стандартная библиотека расширяет функциональность оригинальных Java-типов, что особенно полезно для String:

str.removeSuffix(".txt") str.capitalize() str.substringAfterLast("/") str.replaceAfter(":", "classified")

15# Безопасность Null

Java следует называть почти статично типизированным языком. Внутри него переменная типа String не гарантированно ссылается на String — она может ссылаться на null. И хотя мы к этому привыкли, это снижает безопасность проверки на статичное типизирование, и в результате Java-разработчики вынуждены жить в постоянном страхе перед NPE.

В Kotlin эта проблема решена посредством разделения на типы, допускающие и не допускающие значение null. По умолчанию типы не допускают null, но их можно преобразовать в допускающие, если добавить ?:

var a: String = "abc" a = null // compile error var b: String? = "xyz" b = null // no problem

Kotlin заставляет вас бороться с NPE, когда вы обращаетесь к типу, допускающему null:

val x = b.length // compile error: b might be null

Возможно, выглядит громоздко, но благодаря нескольким своим возможностям действительно полезно. У нас всё ещё есть умные приведения типов, когда типы, допускающие null, преобразуются в не допускающие:

if (b == null) return val x = b.length // no problem

Также можно использовать безопасный вызов ?., он возвращает значение null вместо бросания NPE:

val x = b?.length // type of x is nullable Int

Можно объединять безопасные вызовы в цепочки, чтобы избегать вложенных проверок если-не-null, которые иногда мы пишем в других языках. А если нам по умолчанию нужно не null-значение, то воспользуемся elvis-оператором ?::

val name = ship?.captain?.name ?: "unknown"

Если всё это вам не подходит и вам совершенно точно нужны NPE, то скажите об этом явно:

val x = b?.length ?: throw NullPointerException() // same as below val x = b!!.length // same as above

16# Улучшенные лямбды

Это хорошая система лямбд — идеальный баланс между читабельностью и лаконичностью благодаря нескольким толковым решениям. Синтаксис прост:

val sum = { x: Int, y: Int -> x + y } // type: (Int, Int) -> Int val res = sum(4,7) // res == 11

А вот и толковые решения:

  1. Можно переместить или опустить круглые скобки в методе, если лямбда идёт последней либо является единственным аргументом метода.
  2. Если вы решили не объявлять аргумент одноаргументной лямбды, то он будет неявно объявлен под именем it.

Комбинация этих факторов делает эквивалентными эти три строки:

numbers.filter({ x -> x.isPrime() }) numbers.filter { x -> x.isPrime() } numbers.filter { it.isPrime() }

Это позволяет нам писать лаконичный функциональный код, вы только посмотрите на эту красоту:

persons .filter { it.age >= 18 } .sortedBy { it.name } .map { it.email } .forEach { print(it) }

Система лямбд, объединённая с функциями-расширениями, делает Kotlin идеальным инструментом для создания DSL. Anko — пример DSL, предназначенного для расширения возможностей Android-разработки:

verticalLayout { padding = dip(30) editText { hint = “Name” textSize = 24f } editText { hint = “Password” textSize = 24f } button(“Login”) { textSize = 26f } }

17# Поддержка IDE

У вас есть целый ряд вариантов, как можно начать работать с Kotlin, но я крайне рекомендую использовать IntelliJ, идущий в комплекте поставки Kotlin — его возможности демонстрируют преимущество ситуации, когда одни и те же люди разрабатывают как язык, так и IDE. Небольшой пример: это сообщение всплыло, когда я впервые попытался скопипастить Java-код со Stack Overflow:

IntelliJ заметит, что вы вставляете Java-код в файл Kotlin

На этом всё, спасибо за чтение! Если мне пока не удалось убедить вас насчёт Kotlin, то рекомендую почитать дополнительные материалы:

habrahabr.ru

Функции - Kotlin

Объявление функций

В Kotlin функции объявляются с помощью ключевого слова fun

fun double(x: Int): Int { }

Применение функций

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

val result = double(2)

Для вызова вложенной функции используется знак точки

Sample().foo() //создаёт экземпляр класса Sample и вызывает foo

Инфиксная запись

Функции так же могут быть вызваны при помощи инфиксной записи, при условии, что:

  • Они являются членом другой функции или расширения
  • В них используется один параметр
  • Когда они помечены ключевым словом infix
// Определяем выражение как Int infix fun Int.shl(x: Int): Int { ... } // вызываем функцию, используя инфиксную запись 1 shl 2 // то же самое, что 1.shl(2)

Параметры

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

fun powerOf(number: Int, exponent: Int) { ... }

Аргументы по умолчанию

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

fun read(b: Array<Byte>, off: Int = 0, len: Int = b.size()) { ... }

Значения по умолчанию указываются после типа знаком =.

Переопределённые методы всегда используют те же самые значения по умолчанию, что и их базовые методы. При переопределении методов со значениями по умолчанию эти параметры должны быть опущены:

open class A { open fun foo(i: Int = 10) { ... } } class B : A() { override fun foo(i: Int) { ... } // значение по умолчанию указать нельзя }

Имена в названиях аргументов

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

Рассмотрим такую функцию

fun reformat(str: String, normalizeCase: Boolean = true, upperCaseFirstLetter: Boolean = true, divideByCamelHumps: Boolean = false, wordSeparator: Char = ' ') { ... }

мы можем вызвать её, используя аргументы по умолчанию

reformat(str)

Однако, при вызове этой функции без аргументов по умолчанию, получится что-то вроде

reformat(str, true, true, false, '_')

С названными аргументами мы можем сделать код намного более читаемым

reformat(str, normalizeCase = true, upperCaseFirstLetter = true, divideByCamelHumps = false, wordSeparator = '_' )

Или, если нам не нужны все эти аргументы

reformat(str, wordSeparator = '_')

Обратите внимание, что синтаксис названных аргументов не может быть использован при вызове Java функций, потому как байт-код Java не всегда хранит имена параметров функции.

Функции с возвращаемым типом Unit

Если функция не возвращает никакого полезного значения, её возвращаемый тип - Unit. Unit - тип только с одним значением - Unit. Это возвращаемое значение не нуждается в явном указании

fun printHello(name: String?): Unit { if (name != null) println("Hello ${name}") else println("Hi there!") // `return Unit` или `return` необязательны }

Указание типа Unit в качестве возвращаемого значения тоже не является обязательным. Код, написанный выше, совершенно идентичен с

fun printHello(name: String?) { ... }

Функции с одним выражением

Когда функция возвращает одно-единственное выражение, фигурные скобки { } могут быть опущены, и тело функции может быть описано после знака =

fun double(x: Int): Int = x * 2

Компилятор способен сам определить типа возвращаемого значения.

fun double(x: Int) = x * 2

Явные типы возвращаемых значений

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

Нефиксированное число аргументов (Varargs)

Параметр функции (обычно для этого используется последний) может быть помечен модификатором vararg:

fun <T> asList(vararg ts: T): List<T> { val result = ArrayList<T>() for (t in ts) // ts - это массив (Array) result.add(t) return result }

это позволит указать множество значений в качестве аргументов функции:

val list = asList(1, 2, 3)

Внутри функции параметр с меткой vararg и типом T виден как массив элементов T, таким образом переменная ts в вышеуказанном примере имеет тип Array<out T>.

Только один параметр может быть помечен меткой vararg. Если параметр с именем vararg не стоит на последнем месте в списке аргументов, значения для соответствующих параметров могут быть переданы с использованием named argument синтаксиса. В случае, если параметр является функцией, для этих целей можно вынести лямбду за фигурные скобки.

При вызове vararg функции мы можем передать аргументы один-за-одним, например asList(1, 2, 3), или, если у нас уже есть необходимый массив элементов и мы хотим передать его содержимое в нашу функцию, использовать оператор spread (необходимо пометить массив знаком *):

val a = arrayOf(1, 2, 3) val list = asList(-1, 0, *a, 4)

Область действия функций

В Kotlin функции могут быть объявлены в самом начале файла. Подразумевается, что вам не обязательно создавать объект какого-либо класса, чтобы воспользоваться его функцией (как в Java, C# или Scala). В дополнение к этому, функции в языке Kotlin могут быть объявлены локально, как функции-члены (ориг. "member functions") и функции-расширения ("extension functions").

Локальные функции

Koltin поддерживает локальные функции. Например, функции, вложенные в другие функции

fun dfs(graph: Graph) { fun dfs(current: Vertex, visited: Set<Vertex>) { if (!visited.add(current)) return for (v in current.neighbors) dfs(v, visited) } dfs(graph.vertices[0], HashSet()) }

Такие локальные функции могут иметь доступ к локальным переменным внешних по отношению к ним функций (типа closure). Таким образом, в примере, приведённом выше, visited может быть локальной переменной.

fun dfs(graph: Graph) { val visited = HashSet<Vertex>() fun dfs(current: Vertex) { if (!visited.add(current)) return for (v in current.neighbors) dfs(v) } dfs(graph.vertices[0]) }

Функции-элементы

Функции-элементы - это функции, объявленные внутри классов или объектов

class Sample() { fun foo() { print("Foo") } }

Функции-элементы вызываются с использованием точки

Sample().foo() // создаёт инстанс класса Sample и вызвает его функцию foo

Для более подробной информации о классах и их элементах см. Классы

Функции-обобщения (Generic Functions)

Функции могут иметь обобщённые параметры, которые задаются треугольными скобками и помещаются перед именем функции

fun <T> singletonList(item: T): List<T> { // ... }

Для более подробной информации об обобщениях см. Обобщения

Встроенные функции (Inline Functions)

О встроенных функциях рассказано здесь

Функции-расширения (Extension Functions)

О расширениях подробно написано в отдельной статье

Высокоуровневые функции и лямбды

О лямбдах и высокоуровневых функциях см. раздел Лямбды

Функции с хвостовой рекурсией

Kotlin поддерживает такой стиль функционального программирования, более известный как "хвостовая рекурсия". Это позволяет использовать циклические алгоритмы вместо рекурсивных функции, но без риска переполнения стэка. Когда функция помечена модификатором tailrec и её форма отвечает требованиям компилятора, он оптимизирует рекурсию, оставляя вместо неё быстрое и эффективное решение этой задачи, основанное на циклах.

tailrec fun findFixPoint(x: Double = 1.0): Double = if (x == Math.cos(x)) x else findFixPoint(Math.cos(x))

Этот код высчитывает fixpoint косинуса, который является математической константой. Он просто напросто постоянно вызывает Math.cos, начиная с 1.0 до тех пор, пока результат не изменится, приняв значение 0.7390851332151607. Получившийся код эквивалентен вот этому более традиционному стилю:

private fun findFixPoint(): Double { var x = 1.0 while (true) { val y = Math.cos(x) if (x == y) return y x = y } }

Для соответствия требованиям модификатора tailrec, функция должна вызывать сама себя в качестве последней операции, которую она предпринимает. Вы не можете использовать хвостовую рекурсию, когда существует ещё какой-то код после вызова этой самой рекурсии. Также нельзя использовать её внутри блоков try/catch/finally. На данный момент, хвостовая рекурсия поддерживается только в backend виртуальной машины Java(JVM).

kotlinlang.ru

Классы и наследование - Kotlin

Классы

Классы в Kotlin объявляются с помощью использования ключевого слова class:

class Invoice { }

Объявление класса состоит из имени класса, заголовка (указания типов его параметров, первичного конструктора и т.п) и тела класса, заключённого в фигурные скобки. И заголовок, и тело класса являются необязательными составляющими: если у класса нет тела, фигурные скобки могут быть опущены.

class Empty

Конструкторы

Класс в Kotlin может иметь первичный конструктор (primary constructor) и один или более вторичных конструкторов (secondary constructors). Первичный конструктор является частью заголовка класса, его объявление идёт сразу после имени класса (и необязательных параметров):

class Person constructor(firstName: String)

Если у конструктора нет аннотаций и модификаторов видимости, ключевое слово constructor может быть опущено:

class Person(firstName: String)

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

class Customer(name: String) { init { logger.info("Customer initialized with value ${name}") } }

Обратите внимание, что параметры первичного конструктора могут быть использованы в инициализирующем блоке. Они также могут быть использованы при инициализации свойств в теле класса:

class Customer(name: String) { val customerKey = name.toUpperCase() }

В действительности, для объявления и инициализации свойств первичного конструктора в Kotlin есть лаконичное синтаксическое решение:

class Person(val firstName: String, val lastName: String, var age: Int) { // ... }

Свойства, объявленные в первичном конструкторе, могут быть изменяемые (var) и неизменяемые (val).

Если у конструктора есть аннотации или модификаторы видимости, ключевое слово constructor обязательно, и модификаторы используются перед ним:

class Customer public @Inject constructor(name: String) { ... }

Для более подробной информации по данному вопросу см. "Модификаторы доступа".

Второстепенные конструкторы

В классах также могут быть объявлены дополнительные конструкторы (secondary constructors), перед которыми используется ключевое слово constructor:

class Person { constructor(parent: Person) { parent.children.add(this) } }

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

class Person(val name: String) { constructor(name: String, parent: Person) : this(name) { parent.children.add(this) } }

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

class DontCreateMe private constructor () { }

Примечание: В виртуальной машине JVM компилятор генерирует дополнительный конструктор без параметров в случае, если все параметры первичного конструктора имеют значения по умолчанию. Это делает использование таких библиотек, как Jackson и JPA, более простым в языке Kotlin, так как они используют пустые конструкторы при создании экземпляров классов.

class Customer(val customerName: String = "")

Создание экземпляров классов

Для создания экземпляра класса конструктор вызывается так, как если бы он был обычной функцией:

val invoice = Invoice() val customer = Customer("Joe Smith")

Обращаем ваше внимание на то, что в Kotlin не используется ключевое слово new.

Члены класса

Классы могут содержать в себе:

Наследование

Для всех классов в языке Koltin родительским суперклассом является класс Any. Он также является родительским классом для любого класса, в котором не указан какой-либо другой родительский класс:

class Example // Implicitly inherits from Any

Класс Any не является аналогом java.lang.Object. В частности, у него нет никаких членов кроме методов: equals(), hashCode(), и toString(). Пожалуйста, ознакомьтесь с совместимостью c Java для более подробной информации.

Для явного объявления суперкласса мы помещаем его имя за знаком двоеточия в оглавлении класса:

open class Base(p: Int) class Derived(p: Int) : Base(p)

Если у класса есть основной конструктор, базовый тип может (и должен) быть проинициализирован там же, с использованием параметров первичного конструктора.

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

class MyView : View { constructor(ctx: Context) : super(ctx) { } constructor(ctx: Context, attrs: AttributeSet) : super(ctx, attrs) { } }

Ключевое слово open является противоположностью слову final в Java: оно позволяет другим классам наследоваться от данного. По умолчанию, все классы в Kotlin имеют статус final, что отвечает Effective Java, Item 17: Design and document for inheritance or else prohibit it.

Переопределение членов класса

Как упоминалось ранее, мы придерживаемся идеи определённости и ясности в языке Kotlin. И, в отличие от Java, Kotlin требует чёткой аннотации и для членов, которые могут быть переопределены, и для самого переопределения:

open class Base { open fun v() {} fun nv() {} } class Derived() : Base() { override fun v() {} }

Для Derived.v() необходима аннотация override. В случае её отсутствия компилятор выдаст ошибку. Если у функции типа Base.nv() нет аннотации open, объявление метода с такой же сигнатурой в производном классе невозможно, с override или без. В final классе (классе без аннотации open), запрещено использование аннотации open для его членов.

Член класса, помеченный override, является сам по себе open, т.е. он может быть переопределён в производных классах. Если вы хотите запретить возможность переопределения такого члена, используйте final:

open class AnotherDerived() : Base() { final override fun v() {} }
Стойте! Как мне теперь хакнуть свои библиотеки?

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

Мы думаем, что это не является недостатком по следующим причинам:

  • Опыт поколений говорит о том, что, в любом случае, лучше не позволять внедрять такие хаки
  • Люди успешно используют другие языки (C++, C#), которые имеют аналогичный подход к этому вопросу
  • Если кто-то действительно хочет хакнуть, пусть напишет свой код на Java и вызовет его в Kotlin (см. Java-совместимость)

Правила переопределения

В Kotlin правила наследования имплементации определены следующим образом: если класс перенимает большое количество имплементаций одного и того члена от ближайших родительских классов, он должен переопределить этот член и обеспечить свою собственную имплементацию (возможно, используя одну из унаследованных). Для того, чтобы отметить супертип (родительский класс), от которого мы унаследовали данную имплементацию, мы используем ключевое слово super. Для уточнения имя родительского супертипа используются треугольные скобки, например super<Base>:

open class A { open fun f() { print("A") } fun a() { print("a") } } interface B { fun f() { print("B") } // interface members are 'open' by default fun b() { print("b") } } class C() : A(), B { // The compiler requires f() to be overridden: override fun f() { super<A>.f() // call to A.f() super<B>.f() // call to B.f() } }

Нормально наследоваться одновременно от A и B. У нас не возникнет никаких проблем с a() и b() в том случае, если C унаследует только одну имплементацию этих функций. Но для f() у нас есть две имплементации, унаследованные классом C, поэтому необходимо переопределить f() в C и обеспечить нашу собственную реализацию этого метода для устранения получившейся неоднозначности.

Абстрактные классы

Класс и некоторые его члены могут быть объявлены как abstract. Абстрактный член не имеет реализации в его классе. Обратите внимание, что нам не надо аннотировать абстрактный класс или функцию словом open - это подразумевается и так.

Можно переопределить не-абстрактный open член абстрактным

open class Base { open fun f() {} } abstract class Derived : Base() { override abstract fun f() }

Объекты-помощники

В Kotlin, в отличие от Java или C#, в классах не бывает статических методов. В большинстве случаев рекомендуется использовать функции на уровне пакета (ориг.: "package-level functions").

Если вам нужно написать функцию, которая может быть использована без создания экземпляра класса, но имела бы доступ к данным внутри этого класса (к примеру, фабричный метод), вы можете написать её как член объявления объекта внутри этого класса.

В частности, если вы объявляете объект-помощник в своём классе, у вас появляется возможность обращаться к его членам, используя тот же синтаксис, как при использовании статических методов в Java/C# (указав название класса для доступа).

Прочие классы

Также обратите внимание на:

kotlinlang.ru


Смотрите также