В каком году появился язык программирования kotlin. Введение в язык Kotlin

Язык программирования 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, самое главное для них было создать «прагматичный» продукт. Это значит, что они фокусировались не только на устранении ошибок и совершенствовании продукта, что делал бы любой программист-разработчик, а хотели сделать именно полезный инструмент.

«Инструменты разработки, включая языки программирования, постоянно развиваются. Языки отличаются от других инструментов тем, что их довольно сложно развивать эволюционно. Новая версия языка должна поддерживать все уже существующие программы. Это ограничивает возможности развития существующих языков и создает потребность в появлении новых. Фактор, который определяет успешность нового языка программирования, это, в первую очередь, удобство для разработчиков. Кроме краткости и выразительности, 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. Цель компании - сделать язык программирования подходящим под разные платформы разработки.

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

Исторический экскурс

Первое моё знакомство с программированием смартфонов, работающих под управлением операционной системы Android, произошло в начале 2012 года , то есть ровно 6 лет назад. В те далёкие времена Google ещё не создал свою великолепную IDE (Integrated Development Environment, Интегрированная Среда Разработки) Android Studio, и я в IDE Eclipse с установленным плагином ADT (Android Development Tools, Инструменты разработчика Android) . Поводом к знакомству явилась покупка моего первого смартфона HTC Desire HD менее чем за год до этого, в начале лета 2011 года.

Родным языком программирования для Android считалась Java. Это был новый для меня язык, поэтому у меня возникла тройная сложность: новая IDE, новый ЯП и новая ОС (Операционная Система) , и это всё одновременно. Тем не менее, я худо-бедно научился писать программы под Android, и даже написал один коммерческий продукт, за что с удовольствием получил поощрение в €1000.

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

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

В 2014-м году появилась первая стабильная версия IDE от самого Гугла (правда, основанная на IDE IntelliJ IDEA, написанной в юридически Чешской компании JetBrains, основанной в Праге тремя российскими программистами) .

Вообще, всё началось с российской компании StarSoft , которая начала свою деятельность сразу после августовского путча 1991 года на базе лаборатории программного обеспечения при Независимой Гуманитарной Академии в Санкт-Петербурге, и состояла тогда из трёх человек. В 1993 году началась работа над проектом Together (средство проектирования ПО) , идея которого была предложена приехавшим из Германии немцем . В 1995 году компания была переименована в STAR SPb и официально зарегистрировалась как российское представительство STAR Group. В 1999 году из STAR SPb выделилась «российско-немецкая» компания TogetherSoft, состоявшая из специалистов, работавших над продуктом Together. В числе соучредителей как всегда оказались американцы, которые решили, что хороших программистов нужно срочно вывозить из Питера в Европу, и в том же 1999 году топовая команда TogetherSoft (около 50 человек) уехала в Прагу. Среди них были и три будущих основателя компании JetBrains . И вот, в 2000 году ими была основана компания JetBrains, и зарегистрирована там же, где они на тот момент и жили, в Праге.

Флагманским продуктом JetBrains является IntelliJ IDEA — IDE для многих языков программирования. Её то и взял за основу Гугл для своей IDE Android Studio . К слову, сооснователь Гугла тоже из России. Чуть копнёшь — и везде торчат российские корни... Он родился в Москве и жил там до 5 лет, а затем его семья в 1979 году эмигрировала в америку, как тогда это было принято у евреев. Из-за антисемитизма, в частности, наличия квот для евреев для поступления в ВУЗы и университеты. Сначала евреи, как народ, обособляются, всячески подчёркивают свою богоизбранность и не скрывают свой не всегда приемлемый менталитет в регионах с иной доминирующей религией и иным менталитетом, а потом удивляются результату. Впрочем, это уже другая тема. Несмотря на его, мягко говоря, скептическое отношение к своей бывшей родине (а что ещё можно ожидать от человека, воспитанного советскими эмигрантами) , я вполне разделяю его взгляды, в частности, на Интернет. Да и многие критические высказывания в адрес России вполне себе справедливы, хотя и неприятны, будучи слышимы из уст иностранца. Впрочем, я опять отвлёкся...

Итак, когда появилась Android Studio, и я сразу перешёл на неё, как на потенциально более перспективную для разработки под Андроид IDE. Надо сказать, что вначале были заметны как её плюсы, так и минусы по сравнению с Eclipse. Тем не менее плюсов было намного больше, и я прочно подсел на неё.

Как любитель, я программирую нерегулярно, и последний 2017 год в части Android пропустил вообще. И вот сейчас я решил обновить IDE и посмотреть, что там вообще появилось нового за пропущенное время. И оказалось, что появилось то там дофига существенного! Ниже я перечислю некоторые особо заметные нововведения, которые я оцениваю очень положительно.

Новый язык программирования Котлин

До недавнего времени Android Studio поддерживала программирование только на языке Java (Джава, ранее чаще говорили Ява. Язык назван в честь марки кофе, которая, в свою очередь, названа в честь острова в Индонезии) и на C++ для нативного кода. Язык Java — не сказать, чтобы очень старый, но, учитывая относительно молодую направленность его применения (мультиплатформенность) , довольно поживший. Он был разработан известной компанией Sun Microsystems в 1995 году. Изначально язык назывался Oak («Дуб») , и разрабатывался для программирования бытовых электронных устройств. Затем он был переименован в Java и стал использоваться для написания клиентских приложений и серверного программного обеспечения. Позже появились и другие его применения.

Замечу, что Java работает в паре с компилятрорм, который не выдаёт полноценный код для его выполнения в операционной системе. Исходные тексты, написанные на этом языке, компилируются в специальный байт-код, который выполняется на специальной виртуальной машине, дополнительно установленной в системе, и переводящей этот код в понятные операционной системе и процессору команды. Таким образом, программы, написанные на этом языке, могут выполняться на любом устройстве, в котором установлена такая виртуальная машина. А виртуальные машины Java написаны уже для самых разных архитектур. Этим и достигается мультиплатформенность программ. Минусом такого подхода является увеличенное время их выполнения за счёт дополнительной прослойки в виде виртуальной машины между кодом и процессором. Также программы на Java зачастую работают медленнее из-за несовершенства многих Java-библиотек, например, библиотек графического интерфейса. Но всё это плата за мультиплатформенность.

И вот, совсем недавно, в конце 2017 года, вышла Android Studio 3.0, которая наряду с языком Java и С++ стала поддерживать язык Kotlin (Котлин) , который, как и Java, предгазначен для создания того же самого байт-кода для той-же виртуальной машины, но имеет другой синтаксис, позволяющий писать намного более компактные исходники. Вместе с тем, файлы с исходниками на обоих языках можно без ограничений смешивать в одном проекте, что даёт возможность постепенно перевести весь проект на Котлин.

Язык совсем свежий. Он начал разрабатываться в 2010 году, был представлен общественности в 2011-м, программировать на нём под Android стало возможным с 2012 года, а официальный релиз был выпущен совсем недавно, в 2016 году. Кстати, по традиции (как и Java) язык назван в честь острова. На этот раз это российский остров Котлин в Финском заливе, на котором расположен город Кронштадт. А разработан язык питерскими программистами всё в той же компании JetBrains! О как, реальный российский язык программирования! [Патриотам размахивать флагами, а автор этого поста уже вовсю ходит кругами по комнате, грозно помахивая древком...]

Я уже попробовал писать на этом языке под Android, и могу с уверенностью заявить, что язык вполне себе годный. Ранее я терялся в Java-коде, потому что в Android надо прописывать всё и вся, и получались очень длинные простыни исходников. В итоге исходники разрастались до неприличных размеров, и их приходилось мелко дробить на классы, распихивая их в разные файлы, и тогда я уже терялся в файлах. В Kotlin же используется философия «всё, что можно сгенерировать автоматически, надо генерировать автоматически». С одной стороны, код становится менее прозрачный (минус, но, разве что, только для новичков) , но более простой и компактный (большой плюс для всех).

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

Архитектурные компоненты для Android от Google

Также очень компактным оказалось создание и использование базы данных SQLite с помощью библиотеки Room , являющейся обёрткой над известным классом SQLiteOpenHelper. Для использования Room достаточно описать два маленьких класса, описывающих таблицу и базу данных и один маленький интерфейс, описывающий функции взаимодействия с этой базой данных. Это всё в Котлине даже нет необходимости рассовывать в разные файлы. На основе этой мизерной информации Room воспроизведёт все действия, которые раньше приходилось расписывать в огромных файлах, автоматически и внутри себя. Чудеса!

В реальных приложениях нужно отслеживать изменения данных в базе и автоматически обновлять информацию в визуальных компонентах. Поэтому компонент Room чаще всего используется не сам по себе, а вместе с компонентом LiveData из библиотеки android.arch.lifecycle . Этот компонент также используется элементарно. Данные, которые необходимо отслеживать, передаются из базы в переменную не напрямую, а в виде класса LiveData, принявшего внутри Room эти данные в виде параметра. После этого в основном коде одной строкой Котлина задаётся наблюдение за ними и функция обновления визуального компонента, которая запускается при изменении данных. Всё элементарно!

Ещё один полезный компонент из библиотеки android.arch.lifecycle , решающий головную боль с сохранением данных активности при поворотах экрана — ViewModel. Раньше приходилось писать всякие хитроумные костыли для того, чтобы данные не терялись, а вычисления не прерывались. Теперь для этого есть официальный компонент! Если раньше мы отделяли интерфейс от кода (разметка и активность) , то теперь настало время отелять код, который должен работать только в период жизненного цикла активности (например, обеспечение функционирования интерфейса с пользователем) , от кода, который должен работать вне привязки к конкретному жизненному циклу активности (например, получение, обработка и передача данных) . При этом результат работы второй части кода мы можем автоматически прочитать в пересозданной после поворота экрана активности.

Для реализации всей этой схемы с ViewModel тоже требуется минимум действий. Пишется отдельный класс с кодом, который не должен прерываться (т.н. модель вида, почему «модель» — не знаю; может, перевожу неправильно) , а в основном коде одной строкой вызывается провайдер моделей, в который этот класс передаётся в качестве параметра. Провайдер либо возвращает существующий объект класса модели (после поворота экрана) , либо создаёт такой объект по переданному классу, если такового ещё нет, и тоже возвращает его (при первом запуске активности) . Активность всегда может обращаться к функциям и переменным этого объекта.

Все три компонента объединены под официальным названием Android Architecture Components (Архитектурные Компоненты для Android). Правда, туда ещё входит компонент LifeCycle, тоже находящийся в библиотеке android.arch.lifecycle , но он используется в плотной связке с LiveData, и я бы его вообще не выделял. Появление таких высокоуровневых компонентов — долгожданный шаг Google в правильном направлении. Я давно уже ругался на то, как много разных классов нужно расширить самому и соединить их все друг с другом, чтобы заставить работать что-то чуть большее, чем примитивные примеры из учебников для начинающих. И вот, наконец, среди библиотек стали появляться правильные компоненты. Надеюсь, что эта тенденция продолжится.

Визуальный редактор интерфейса

На этом обнаруженные мною новшества в программировании смартфонов не заканчиваются. С самого рождения в Android Studio было очень тяжко со стабильностью и предсказуемостью работы визуального редактора интерфейса, хотя он и был постабильнее, чем в Eclipse. Даже непосредственно редактируя xml-разметку интерфейса, очень сложно было настроить все эти Layout"ы и другие визуальные компоненты так, чтобы они отображались в нужных местах и в нужном виде.

К счастью, в Android Studio, начиная с версии 2.2, вместо гиморного построения интерфейса через макеты линейного расположения элементов (LinearLayout) предлагается использовать новый макет принудительного расположения (ConstraintLayout) . Кроме того, визуальный редактор, наконец, доведён до ума. Всё это вместе дало очень положительный эффект. Теперь правильно расположить элементы не так сложно, и ведут они себя вполне предсказуемо.Теперь можно даже не трогать xml-разметку, а все действия выполнять в визуальном редакторе.

Fun main(args: Array) { val numbers = arrayListOf(15, -5, 11, -39) val nonNegativeNumbers = numbers.filter { it >= 0 } println(nonNegativeNumbers) } // Вывод: 15, 11

Функции высшего порядка - это функции, которые принимают другие функции в качестве аргументов и возвращают функции. Рассмотрим следующий пример:

Fun alphaNum(func: () -> Unit) {}

В нём func - это имя аргумента, а () -> Unit - это тип функции. Мы говорим, что func будет функцией, не принимающей аргументов и ничего не возвращающей.

Лямбда-выражения, или анонимные функции - это функции, которые не объявляются, а передаются в виде выражений. Вот пример:

Val sum: (Int, Int) -> Int = { x, y -> x + y }

Мы объявляем переменную sum , которая берёт два числа, складывает их и принимает значение суммы, приведённое к целому. Для вызова достаточно простого sum(2,2) .

Сравнение скорости Java и Kotlin

Первая сборка Kotlin-кода занимает примерно на 15–20% больше времени, чем аналогичный процесс на Java. Однако инкрементная сборка Kotlin даже немного быстрее, чем у Java. Таким образом, языки примерно равны по скорости компиляции.

Будущее Kotlin

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

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

Вам потребуются следующие библиотеки:

  • Retrofit 2.0;
  • RxJava;
  • Picasso;
  • RecyclerView;
  • Расширения Kotlin для Android;
  • Dagger 2.

Все исходники доступны на GitHub . Серия состоит из следующих частей.

Последнее обновление: 02.12.2017

Kotlin представляет статически типизированный язык программирования от компании JetBrains. Kotlin можно использовать для создания мобильных и веб-приложений.

Kotlin работает поверх виртуальной машины Java (JVM) и при компиляции компилируется в байткод. То есть, как и в случае с Java, мы можем запускать приложение на Kotlin везде, где установлена JVM. Хотя также можно компилировать код в JavaScript и запускать в браузере. И, кроме того, можно компилировать код Kotlin в нативные бинарные файлы, которые будут работать без всякой виртуальной машины. Таким образом, круг платформ, для которых можно создавать приложения на Kotlin, чрезвычайно широк - Windows, Linux, Mac OS, iOS, Android.

Первая версия языка вышла 15 февраля 2016 года. Хотя сама разработка языка велась с 2010 года. Текущей версией языка на данный момент является версия 1.2, которая вышла 28 ноября 2017 года.

Kotlin испытал влияние многих языков: Java, Scala, Groovy, C#, JavaScript, Swift и позволяет писать программы как в объектно-ориентированном, так и в функциональном стиле. Он имеет ясный и понятный синтаксис и довольно легок для обучения.

Самым популярным направлением, где применяется Kotlin, является прежде всего разработка под ОС Android. Причем настолько популярным, что компания Google на конференции Google I/O 2017 провозгласила Kotlin одним из официальных языков для разработки под Android (наряду с Java и C++), а инструменты по работе с данным языком были по умолчанию включены в функционал среды разработки Android Strudio начиная с версии 3.0.

Загрузить компилятор непосредственно для самого языка Kotlin можно по адресу .

По выше указанному адресу можно найти архив. Загрузим и распакуем из архива папку kotlinc. В распакованном архиве в папке bin мы можем найти утилиту kotlinc , с помощью которой и будет производиться компиляция:

Теперь определим на жестком диске каталог для файлов с исходным кодом. Например, в моем случае каталог будет находиться по пути c:/kotlin . В этом каталоге создадим текстовый файл и переименуем его в app.kt . Расширение kt - это арсширение файлов на языке Kotlin.

Fun main(args: Array){ println("Hello Kotlin") }

В данном случае мы определяем функцию main, которая и будет представлять действия, выполняемые программой. Для определения функции применяется ключевое слово fun .

Эта функция принимает параметр args, который представляет массив строк.

Внутри функции main выполняется другая функция - println() , которая выводит некоторое сообщение на консоль.

Откроем командную строку. Вначале с помощью команды cd перейдем к папке, где находится файл app.kt. Затем для компиляции программы введем следующую команду:

C:\kotlin\bin\kotlinc app.kt -include-runtime -d app.jar

В данном случае мы передаем компилятору c:\kotlin\bin\kotlinc для компиляции файл app.kt. (Чтобы не писать полный путь к компилятору, путь к нему можно добавить в переменную PATH в переменных среды). Далее с помощью параметра -include-runtime указывается, что создаваемый файл будет включать среду Kotlin. А параметр -d указывает, как будет называться создаваемый файл приложения, то есть в данном случае это будет app.jar .

После выполнения этой команды будет создан файл app.jar. Теперь запустим его на выполнение. Для этого введем команду

Java -jar app.jar

В данном случае считается, что путь к JDK, установленном на компьютере, прописан в переменной PATH в переменных среды. Иначе вместо "java" придется писать полный путь к утилите java.

В итоге при запуске файла мы увидим на консоли строку "Hello Kotlin".

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

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

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

История разработки «альтернативных» языков на платформе Java насчитывает более десятилетия, однако распространение такие языки получили лишь относительно недавно. На волне популярности динамически типизированных языков поднялись JRuby, Groovy и Clojure, а среди статически типизированных языков следует упомянуть Scala, Fantom и Gosu. Сам язык Java тоже не стоит на месте , но его развитие осложнено как необходимостью сохранения обратной совместимости, так и непростой судьбой компании Sun Microsystems, поглощенной корпорацией Oracle.

На этом фоне новый проект компании JetBrains под кодовым названием Kotlin (ударение на «о»), с одной стороны, выглядит почти данью моде, а с другой - находится в окружении заметного числа конкурентов. Однако мы чувствуем себя достаточно уверенно в этой ситуации, и тому есть несколько причин. Во-первых, JetBrains уже более десяти лет занимается интегрированными средами разработки для разных языков программирования (многие из которых работают на платформе Java), и за это время была собрана сильная команда специалистов и накоплен значительный опыт в области языков программирования и смежных технологий. Во-вторых, мы не можем сказать, что какой-либо из существующих языков на платформе Java полностью удовлетворяет нашим потребностям, и полагаем, основываясь на предварительных отзывах программистов всего мира, что наши коллеги в других компаниях испытывают похожие затруднения.

Разработка проекта Kotlin началась летом 2010 года, в июле 2011-го проект был официально анонсирован и на сайте размещено описание языка. Выпуск публичной бета-версии компилятора запланирован на начало 2012 года.

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

Совместимость с Java. Платформа Java - это прежде всего экосистема : кроме «официальных» продуктов компании Oracle, в нее входит множество проектов с открытым кодом: библиотек и фреймворков разного профиля, на базе которых строится огромное количество приложений. Поэтому для языка, компилируемого для этой платформы, очень важна совместимость с существующим кодом, который написан на Java. При этом необходимо, чтобы существующие проекты могли переходить на новый язык постепенно, то есть не только код на Kotlin должен легко вызывать код на Java, но и наоборот.

Статические гарантии корректности. Во время компиляции кода на статически типизированном языке происходит множество проверок, призванных гарантировать, что те или иные ошибки не произойдут во время выполнения. Например, компилятор Java гарантирует, что объекты, на которых вызываются те или иные методы, «умеют» их выполнять, то есть что в соответствующих классах эти методы реализованы . К сожалению, кроме этого очень важного свойства, Java почти ничего не гарантирует. Это означает, что успешно скомпилированные программы завершаются с ошибками времени выполнения (вызывают исключительные ситуации). Ярким примером является разыменование нулевой ссылки, при котором во время выполнения вызывается исключение типа NullPointerException. Важным требованием к новому языку является усиление статических гарантий. Это позволит обнаруживать больше ошибок на этапе компиляции и, таким образом, сокращать затраты на тестирование.

Скорость компиляции. Статические проверки упрощают программирование, но замедляют компиляцию, и здесь необходимо добиться определенного баланса. Опыт создания языков с мощной системой типов (наиболее ярким примером является Scala) показывает, что такой баланс найти непросто: компиляция зачастую становится неприемлемо долгой. Вообще, такая характеристика языка, как время компиляции проекта, может показаться второстепенной, однако в условиях промышленной разработки, когда объемы компилируемого кода очень велики, оказывается, что этот фактор весьма важен - ведь пока код компилируется, программист зачастую не может продолжать работу. В частности, быстрая компиляция является одним из важных преимуществ Java по сравнению с C++, и Kotlin должен это преимущество сохранить.

Лаконичность. Известно, что программисты зачастую тратят больше времени на чтение кода, чем на его написание, поэтому важно, чтобы конструкции, доступные в языке программирования, позволяли писать программы кратко и понятно. Java считается многословным языком (ceremony language - «церемонный язык»), и задача Kotlin - улучшить ситуацию в этом смысле. К сожалению, строгие методы оценивания языков с точки зрения их лаконичности развиты довольно слабо, но есть косвенные критерии; один из них - возможность создания библиотек, работа с которыми близка к использованию предметно-ориентированных языков (Domain-Specific Language, DSL). Для создания таких библиотек необходима определенная гибкость синтаксиса в совокупности с конструкциями высших порядков ; наиболее распространены функции высших порядков, то есть функции, принимающие другие функции в качестве параметров.

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

Инструментальная поддержка. Современные программисты активно используют различные автоматизированные инструменты, центральное место среди которых занимают интегрированные среды разработки (Integrated Development Environment, IDE). Десятилетний опыт, накопленный в компании JetBrains, показывает, что определенные свойства языка могут существенно затруднять инструментальную поддержку. При разработке Kotlin мы учитываем этот факт и создаем IDE одновременно с компилятором.

Основные элементы языка

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

Объявления в Kotlin объединяются в пространства имен (namespace), и функция может быть объявлена непосредственно внутри пространства имен:

namespace example { fun max(a: Int, b: Int) : Int { if (a returna return b } }

Объявление функции предваряется ключевым словом fun , а типы параметров указываются после двоеточия, следующего за именем параметра. Аналогично обозначается и тип возвращаемого значения функции. Такой синтаксис следует традициям языков «функционального мира», например ML и Scala. Он позволяет легко опускать типовые аннотации, если тип может быть выведен компилятором из контекста автоматически.

Переменные в Kotlin, как и в Scala, объявляются с помощью ключевых слов val (неизменяемые переменные) и var (изменяемые):

var sinSum: Double = 0.0 for (x in xs ) { val y = sin(x) sinSum += y }

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

Классы. Основным инструментом декомпозиции в Kotlin, как и в других объектно-ориентированных языках, являются классы. При объявлении класса список параметров конструктора указывается непосредственно в заголовке:

class IntPair(x: Int, y: Int) {...}

Экземпляры класса создаются прямым вызовом конструктора; ключевого слова new в Kotlin нет:

val xy = IntPair(x, y)

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

class MyList (length: Int): List , Serializable {...}

Трейты. Класс может наследоваться от одного класса или от нескольких трейтов (trait – дословно «характерная черта», особенность). Трейты похожи на классы тем, что они тоже определяют типы, тоже могут иметь функции-члены и наследоваться от других трейтов. Основное отличие состоит в том, что трейты не имеют конструкторов и, как следствие, не могут иметь состояния (полей). Можно сказать, что трейты - это знакомые всем интерфейсы из языка Java, только функции в них могут иметь реализацию. Ограничения, накладываемые на трейты, позволяют избежать трудностей, связанных с множественным наследованием классов.

Внешние функции. Еще один механизм «расширения» типов в Kotlin - это внешние функции (extension function - «функция-расширение»). Такие функции могут быть объявлены вне какого-либо класса и при этом вызываться так, как будто они были объявлены внутри. Вот пример объявления внешней функции для типа Int:

fun Int.abs() : Int { if (this return -this else return this }

Тип, расширяемый данной функцией, указывается перед ее именем и отделяется точкой. Это соответствует объявлению «неявного» параметра, который внутри функции обозначается ключевым словом this . Например, в нашем примере функция abs() расширяет тип Int, и неявный параметр this является целым числом. Такую функцию можно вызывать с помощью операции «точка», как и функции - члены класса:

val x = (-1).abs()

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

Внешние функции связываются статически , то есть не являются виртуальными (virtual).

Управляющие конструкции. When

Kotlin поддерживает традиционные для императивных языков управляющие конструкции if , for и while , на которых мы не будем останавливаться подробно, а также конструкцию when - операцию ветвления, которую можно рассматривать как расширенную версию традиционного оператора switch :

when (x) { 1 => print(“One”) 2, 3 => print(“Two or three”) else => print(“Unknown number”) }

Слева от знака «=>» указывается выражение или список выражений, разделенных запятыми, называемый условием . Если аргумент конструкции when (в нашем примере - переменная x) равен хотя бы одному из этих выражений, выполняется тело данного условия, то есть выражение или блок, указанный справа от знака «=>». Условия проверяются последовательно, сверху вниз. Если ни одно из условий не выполнено, выполняется код, указанный после слова else . В отличие от switch , при использовании when условия не являются метками, поэтому не требуется заканчивать тело условия словом break .

Кроме простого сравнения на равенство, when позволяет проверять аргумент на принадлежность коллекции, с помощью операции in :

when (x) { in set => print(“in set”) in 1..10 => print(“1..10”) else => print(“Default branch”) }

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

Еще один вид условий отмечается ключевым словом is и позволяет проверять тип аргумента . Например, проверить к какому из нескольких типов относится значение x, можно следующим образом:

when (x) { is String => println(“String”) is Int => println(“Int”) is Array => println(“Array of Double”) }

Система типов

Нулевые ссылки. Система типов языка Kotlin позволяет гарантировать отсутствие в программах некоторых видов ошибок, например разадресации нулевой ссылки. Типы в Kotlin делятся на содержащие null и не содержащие null . Типы, содержащие null , аннотируются знаком вопроса:

fun isEmpty(s: String?): Boolean {...}

Знак вопроса после имени типа (String) означает, что ссылка s указывает на объект класса String или имеет значение null . Результат функции isEmpty, в свою очередь, должен быть булевым значением и не может иметь значения null , поскольку соответствующий тип не проаннотирован знаком вопроса.

return s.length() == 0 // Ошибка: разыменование нулевой ссылки

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

If ( s != null ) { return s.length() == 0 // s точно ссылается на существующий объект } else { return true } return (s == null ) || s.length() == 0//Оператор||обеспечивает проверку

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

A?.getB()?.getC()?.getD()

Если a не равно null , выражение a?.getB() возвращает a.getB(), а в противном случае - null .

Автоматическое приведение типа. Мы приводили пример того, как компилятор учитывает информацию, содержащуюся в условиях, и разрешает разыменовывать уже проверенные ссылки. Аналогичный механизм автоматически вставляет операцию приведения типа , если ранее в программе проверялось соответствующее условие. Оператор проверки типа (аналог instanceof в Java) в Kotlin называется is :

val x: Object = ... if (x is String) { print(x.length()) }

В этом примере ссылка x проверяется на принадлежность к типу String, и, если проверка прошла успешно, на экран выводится длина строки. При вызове функции length() компилятор автоматически вставляет приведение x к типу String, поскольку оно безопасно в этом месте программы.

Автоматическое приведение типа работает для всех условных конструкций: if , when , while , ||, && и т. д.

Функции высших порядков

Пользователи функциональных языков программирования хорошо знакомы с функциями высших порядков : механизмом, позволяющим передавать функции в качестве аргументов другим функциям, записывать функции в переменные и т. д. Как уже говорилось, этот механизм значительно облегчает создание библиотек. В объектно-ориентированных языках функции высших порядков обычно эмулируются с помощью паттерна Strategy . Например, для того чтобы реализовать фильтрацию для коллекций произвольного типа, необходимо параметризовать функцию filter() объектом, который «умеет» отвечать на вопрос, нужно ли включить данный элемент в результирующую коллекцию. Этот объект является стратегией фильтрации . В функциональном языке создавать стратегию не нужно - можно просто передать функцию.

Являясь объектно-ориентированным языком, Kotlin тем не менее поддерживает функции высших порядков. Это означает в первую очередь, что функция в Kotlin может являться значением , имеющим соответствующий тип:

val predicate: fun (x: Int): Boolean =...

В данном примере переменная predicate имеет функциональный тип «fun (x: Int): Boolean», то есть хранимое ею значение является функцией, принимающей целочисленный параметр и возвращающей булевское значение. В частности, мы можем вызвать эту функцию:

val yesOrNo = predicate(1)

Такая функция может использоваться, например, при фильтрации набора целых чисел:

fun Collection .intFilter(predicate: fun (x: Int): Boolean): Collection {...}

А для произвольных коллекций можно ее обобщить с помощью типовых параметров (generic):

fun Collection .filter(predicate: fun (x: T) : Boolean) : Collection { val result = ArrayList () for (x in this ) if (predicate(x)) result.add(x) return result }

(Здесь приведена лишь наивная реализация функции filter(). Более реалистичная реализация требует ленивых вычислений, но эта тема выходит за рамки данной статьи.)

Самое интересное - как задавать значение аргумента, имеющего функциональный тип. Для этого широко используются уже упоминавшиеся функциональные литералы :

Ints.filter({x => x % 2 == 0})

В данном примере аргумент внешней функции filter() представляет собой функциональный литерал, то есть короткое объявление функции. Он обязательно заключается в фигурные скобки, до символа «=>» следуют объявления параметров, а после - тело функции, причем оператор return не требуется, поскольку результатом считается последнее выражение в теле литерала. Таким образом, из коллекции ints будут выбраны только четные числа , поскольку наш литерал возвращает true, только если остаток от деления x на 2 равен нулю.

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

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

Ints.filter({it % 2 == 0}) // Вызов аналогичен предыдущему примеру

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

Ints.filter {it % 2 == 0} // Вызов аналогичен двум предыдущим примерам

Такой синтаксис позволяет записывать преобразования коллекций в стиле, напоминающем LINQ :

Ints.select {it * it}. where {it % 2 == 0} // Среди квадратов элементов коллекции // выбрать четные

(Здесь функция where() делает то же, что и функция filter().)

Кроме того, данная конвенция делает вызовы функций больше похожими на привычные управляющие конструкции. Приведем еще один пример. Функция synchronized() принимает два параметра: объект синхронизации (монитор) и функцию. Во время выполнения сначала захватывается монитор, далее в блоке try..finally выполняется функция, а затем монитор освобождается:

fun synchronized (l: Lock, body: fun () : T) : T { l.lock() try { return body() } finally { l.unlock() } }

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

Synchronized (myLock) { // Код, который необходимо выполнить }

Данный пример показывает, как в Kotlin можно средствами языка выразить конструкцию, которая в Java является встроенной.

Предметно-ориентированные языки

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

val homeDir = "..." module("org.jetbrains.test") { // Объявление модуля depends(MavenRepo("[email protected]")) // Зависимость importNamespace("java.lang") // Импорт по умолчанию importNamespace("org.junit") // Импорт по умолчанию sourceRoot("$homeDir/src") // Путь к исходным файлам testSourceRoot("$homeDir/tests") // Путь к тестам }

Несмотря на то что перед нами обыкновенная программа на Kotlin, она выглядит как программа на специализированном языке, предназначенном для декларативного описания модулей. Такой подход к описанию структур данных весьма популярен в Groovy и других динамических языках, поскольку позволяет избежать громоздких и трудно читаемых дескрипторов, написанных на XML. В Groovy такой подход известен под названием Builders . Ярким примером его использования является библиотека Gradle .

По сравнению с Groovy и другими динамическими языками, важным отличием внутренних DSL в Kotlin является то, что при той же краткости синтаксиса, система типов статически гарантирует корректность программы.

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

// Абстрактный модуль abstract class Module(name: String) { val dependencies: List = ArrayList() } // Модуль, состоящий из классов, написанных на Kotlin class KotlinModule(name: String) : Module(name) { fun dependency(module: Module) { dependencies.add(module) } } // Модуль на основе репозитория Maven class MavenRepo(name: String) : Module(name) { ... }

Определим функцию module(), создающую новый модуль:

fun module(name: String, init: fun KotlinModule.() : Unit) : KotlinModule { val result = KotlinModule(name) result.init() return result }

Данная функция является функцией высшего порядка, поскольку параметр init сам является функцией, причем внешней функцией: об этом говорит тип KotlinModule, указанный перед (пустым) списком параметров в функциональном типе. Это означает, что функцию module() можно вызывать следующим образом:

Module(“org.jetbrains.test”) { // тело функции init }

Это похоже на пример сценария, который мы уже видели. Заметим, что внутри функционального литерала доступен неявный параметр this типа KotlinModule (поскольку этот литерал имеет тип «внешняя функция»), и мы можем его использовать:

Module(“org.jetbrains.test”) { this .dependency(MavenRepo("[email protected]")) this .dependency(anotherModule) // ... }

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

Module(“org.jetbrains.test”) { dependency(MavenRepo("[email protected]")) dependency(anotherModule) // ... }

Аналогичным образом можно реализовать многие декларативные языки, включая языки разметки, такие как HTML. При этом вместо тегов будут использоваться вызовы функций высших порядков, и корректность использования таких «тегов», как и их атрибутов, будет гарантироваться системой типов:

Html { head { title {+"XML encoding with Kotlin"} } body { h1 {+"XML encoding with Kotlin"} p { +"This is some text. For more see the" a(href = "http://jetbrains.com/kotlin") {+"Kotlin home page"} } }

Мы рассмотрели несколько наиболее интересных особенностей языка Kotlin, но за рамками остались такие возможности языка, как обобщенные типы (generic), встраиваемые функции (inline function), представление типов во время выполнения (reified type), поддержка делегирования, переопределение операторов и др. Об этих возможностях, а также о ходе работы над проектом можно прочесть на странице проекта.

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

Литература

  1. Bloch J. Effective Java. Second Edition. - Prentice Hall, 2008.
  2. Гамма Э., Хелм Р., Джонсон Р., Влиссидес Дж. Приемы объектно-ориентированного проектирования. Паттерны проектирования. - СПб.: Питер, 2007.
  3. Троэлсен Э. Язык программирования С# 2008 и платформа. NET 3.5. - М.: Вильямс, 2010.

За исключением случаев несогласованной раздельной компиляции. - Прим. автора.

Операция is также позволяет проводить сопоставление с образцом (pattern matching) - Прим. автора.

Андрей Бреслав ([email protected]) - ведущий разработчик языка Kotlin, компания JetBrains.