Да здравствует kotlin. Или моя ненависть к js

left Программируя под веб я до ужаса не люблю писать клиентский код. И даже не потому что это сложно, или потому что это графический интерфейс, хотя и это то же. А по причине убогости javascript. Когда я на нем пишу больше 8 строчек у меня появляется сильное ощущение что делал js не иначе как мой однокурсник. Ночью, за пару часов до зачета :-)

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

Kotlin

Kotlin это статически типизированный язык программирования компилируемый в JVM byte code и javascript. Лицензия Apache 2 Open Source License. Причина создания нового языка - хочется писать меньше, быстрее, использовать интересные веяние. Java почти не развивается, а другие языки не подошли в силу: динамической типизации, скорости, сложности и т.д. Более точно можно почитать в той же документации в разделах FAQ и Comparison to Java

Что бы ознакомиться с языком стоит сразу направиться на Kotlin confluence. Там можно найти исчерпывающею информацию по разрабатываемому языку. Так же можно посмотреть и потрогать базовые примеры на kotlin demo. В режиме server редактор умеет дополнять, выводить список методов, а так же проверять код на лету. В общем мини ide прямо в браузере.

Все выше изложенное это в основном идеи и ссылки из документации или презентаций которые я видел. От себя могу сказать, что когда я углубился в программирование на java, после С# и python, у меня было ощущение что я возвратился в прошлый век. Вроде бы и разница не большая, а видна сразу. При использовании kotlin у меня нет таких мыслей. А довольно гибкая архитектура позволяет создавать решения аналогичные жестко встроенным конструкциям других языков. Остается надеяться что основной библиотеке уделят не меньше внимания, и язык действительно станет той самой пулей.

Но речь сегодня не совсем о kotlin, а его "подмножестве" js. Все это потому, что у JVM реализации есть полная совместимость с java. Вы можете взять старые проект и дописывать код на новом языке. С js так не получиться, есть только базовые коллекции ну и конечно интеграция с jQuery.

Оцениваем

Как я уже упомянул в заголовке, меня тошнит от javascript. По мне это даже не язык, жалкое поделие. И я искренне не понимаю как такое можно пихать во все подряд. Веб, мобильные, сервера и т.д. Есть coffeescript, но опять таки это смесь всего подряд которую очень сложно читать. И да, в итоге это чистый js на выходе. И тут у kotlin есть то, за что его стоит выбрать. Давайте перечислим и разберем точнее.

  • Namespaces. Если у вас кода больше чем 20 строк, то без модулей у вас настанет хаос. И именно так и происходит в js.
  • Комментарии. Это не смешно. Вряд ли вы будете писать комментарии в том, что посылает конечному пользователю. Нет конечно есть YUI Compressor, но это дополнительные телодвижения и не маленькие.
  • Строгая статическая типизация. JS так мило работает, что даже если ты отрубишь ему ногу он продолжит бегать. Типизация хоть как то гарантирует валидность кода.
  • IDEA. Это не просто подсветка кода, это нормальный flow control. Он конечно еще далек от java имплементации и здоровски подтормаживает, но в целом уже лучше всяких реализаций для скриптовых языков.
  • Сам язык. kotlin является довольно коротким, емким и более чем читаемым. К нему конечно надо привыкать, но мне кажется любой нормальны человек писавший на чем то кроме js/php, сможет без проблем разобраться.

Исходя из всех этих соображений я решил, что лучше я буду писать на kolin js. Пусть проект в разработке и api частенько ломается. Пусть генерируемый код не особо красив. Пусть у меня будет технология поверх технологии, что я так не люблю в html стеке. Пусть мне придется портировать api вручную. Все равно доводы "за" сильно перевешивают доводы "против".

Начинаем полет

Что бы начать работать вам понадобиться IDEA, и еще пару действий что бы настроить ее. Потом скачать kotlin-js-hello и открыть в IDE и выбрать js.

Давайте разберемся что у нас и где. В папке src лежат исходные тексты, как пример hello.kt. Каждый файл должен содержать namespace. Например package hello, package hello.utils. Под модули лучше всего располагать в под папках. Точку входа в программу стоит назвать main. В папке deploy лежит html файл к которому собственно мы и будем подключать сгенерированный скрипт. Который будет создаваться там же. Папка lib это вспомогательные файлы. kotlinLib.js - необходимо подключить в html для корректной работы. kotlin-jslib.jar - js библиотека kotiln'a, в ней можно посмотреть весь api. Собственно все. Просто запустить проект, что бы посмотреть.

Сам html мы особо трогать не будем, да и грубо говоря это и не задача программиста. Единственно что нам в нем надо, это добавить script c src="http://code.jquery.com/jquery-1.7.2.js" в тег head. Что бы в дальнейшем мы могли вызывать jQuery. Еще стоит обратить внимание на строчку onload="Kotlin.defs.hello.main()". hello - это полное имя пакета. main() функция которую необходимо исполнить. Эта та точка откуда начнется выполнение нашей программы, после окончания загрузки данного тега. Стоит заметить что в конечный получившийся js файл войдет весь код из папки src.

Для продолжения нам теперь надо взять этот файлик и положить его в папке src. Я не стал выкладывать весь код, ибо его там прилично. И думаю скоро это будет часть стандартной библиотеки. Если кому интересно, это статический билдер html дерева. Полную версию можно найти на demo сайте. Там нет ничего сверх сложного, но надо посидеть и подумать. Документация в помощь.

Пишем код

Теперь давайте модифицируем наш пример. Создадим массив длиной в 4 элемента и заполним его от 1 до 4. После чего в body добавим тег p и в нем напишем 4 раза "Hello kotlin!" с номер выделенным жирным. Не забываем добавить import hello.html.p

window.document.body.innerHTML += "<br></br>Hello, Kotlin!"
val arr = Array(4, { it + 1 } )
window.document.body.innerHTML += p {
    for(i in arr) {
        b {
            +"$i."
        }
        +"Hello kotlin!"
    }
}

Выглядит непривычно? А при этом, это нормальные конструкции языка. Давайте немного разъясним. К примеру, b { +"$i." } это синтаксический сахар к b( { this.plus("$i.") } ). Так как последний параметр это анонимная функция, мы просто опустили скобки. А plus это перезагрузка оператора +.

Теперь вынесем этот код в отдельную функцию. Первым параметром мы укажем css селектор для jQuery куда необходимо положить результат. А вторым передадим список со строками. Заметьте, мы использовали специальную конструкцию rage 0..items.size() - 1. И обратились к List через индексацию, которая трактуется как вызов метода get(i). jQuery находиться в import js.jquery.jq

fun add_messages(selector: String, items: List<string>) {
    val html = p {
        for(i in 0..items.size() - 1) {
            b { +"$i." }
            +items[i]
        }
    }
    jq(selector).html(html.toString())
}

fun main(args: Array<string>) {
    window.document.body.innerHTML += """<div id="messages"></div>"""
    val list = ArrayList<string>()
    list.add("Hello")
    list.add("Kotlin!")
    add_messages("#messages", list)
}

И добавим после add_messages функции немного динамики на странницу в виде события на нажатие. Необходимо импортировать import js.debug.console

jq("#messages b").click {
    jq(this).attr("style", "color:red")
    console.log(this)
}

Подбрасываем API

Читатель наверное уже понял как все устроенно. Хоть синтаксис поменялся и добавились новые типы, в целом идеи остались те же. Но наверное возник вопрос - а как использовать наработки, которые уже написаны на javascript? Давайте рассмотрим пример из стандартного api.

native
class JQuery() {
    fun html() : String = "";
    fun html(s : String) = this;
    fun click() = this;
}

native("$")
fun jq(selector : String) = JQuery();

Мы объявляем класс jQuery и повторяем все методы и поля дня него. В нашем случае три, но на самом деле их больше. После дописываем аннотацию native и все. И мы можем создавать экземпляры, если конечно такой класс присутствует в js. Еще в аннотации можно прямо указать к чему привязать вызов. В коде еще было упомянуто логирование в консоль. Давайте посмотрим и эту реализацию.

native
val console : consoleClass = js.noImpl

native
class consoleClass() {
    fun log(message : Any?) : Unit = js.noImpl
}

То есть мы просто создали наш экземпляр в одноименной переменной, не забыв дописать аннотацию. А потом просто импортировали ее.

Вместо заключения

Надеюсь вы не сильно утомились хаением javascript'a. А почерпнули для для себя новый язык, новый способ взаимодействия с вебом.

Версия компилятора 0.1.2580. Проект в стадии разработки, поэтому где-то могут получится ляпы в ходе изменения api. Так что не пинайте сильно.

Categories: HowTo, Обзоры Tags: , ,