Да здравствует kotlin. Или моя ненависть к js
Программируя под веб я до ужаса не люблю писать клиентский код. И даже не потому что это сложно, или потому что это графический интерфейс, хотя и это то же. А по причине убогости 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. Так что не пинайте сильно.