Привет, меня зовут Дима. Я Full Stack программист, разрабатываю кроссплатформенные приложения и игры для web, desktop и mobile платформ. Чуть больше пяти лет я использую Haxe в своей повседневной работе. И так уж случилось, что большая часть Haxe-девелоперов используют его (в том или ином виде) только при разработке игр. Это, на мой взгляд, одна из причин недостаточной осведомленности о том, как его можно применять в других направлениях разработки ПО. В этой статье я хотел бы пролить свет на то, чем же является Haxe и почему вам стоит задуматься о том, чтобы начать использовать его в своих проектах уже сегодня.
О чем вообще речь?
Haxe — это open source инструмент (toolkit) для разработки кроссплатформенного ПО, в основе которого лежат такие вещи как:
- Сам язык Haxe со строгой типизацией (но для любителей динамики есть возможность писать динамический код!).
- Быстрый и современный компилятор.
- Стандартная, кроссплатформенная библиотека и доступ к нативным функциям всех поддерживаемых платформ.
Сильная сторона языка Haxe в том, что он в большинстве случаев не компилируется, а транслируется в другие языки. Хотя в официальной документации и используется термин «compiler», правильнее было бы назвать его «transcompiler». Для простоты понимания я буду называть его транслятором. В чем же тут сильная сторона, спросите вы? В обилии целевых платформ, список которых постепенно увеличивается: JavaScript, C#, C++, Java, PHP (включая PHP7), Python, ActionScript 3, Lua, а также загадочные Neko и HashLink.
Для Haxe не нужны никакие среды выполнения и виртуальные машины, потому что все это уже имеется на целевых платформах. Транслируя код, написанный на Haxe, вы сможете его использовать на любых проектах, которые работают под управлением языков из списка выше.
Стоит отметить также, что Haxe старается создавать максимально оптимизированный код, избегая лишних конструкций. Если задача может быть решена нативными средствами, значит Haxe решает ее нативными средствами, не прибегая к собственным решениям. В конце статьи на примере JavaScript я это продемонстрирую.
О синтаксисе и языке в целом
Приведу основной перечень преимуществ Haxe как языка:
- Мощная система типов (классы, интерфейсы, анонимные структуры, дженерик-типы, динамические типы, алгебрагические типы, абстрактные типы).
- Выразительный синтаксис (все есть выражение (everything is an expression), геттеры и сеттеры, сопоставление с образцом (pattern matching), упрощенный синтаксис создания массивов (array comprehension), интерполяция строк).
- Близость к целевой платформе (наличие extern-классов — позволяет применять нативные библиотеки конечной платформы, использование untyped кода, скрещивание Haxe с кодом целевой платформы).
- Оптимизация (inline-методы, inline для объектов, удаление мертвого кода (dead code elimination), статический анализатор, оптимизация кода).
- Метапрограммирование (макросы, кодогенерация на уровне выражений и целых типов — позволяет как генерировать, так и редактировать код во время компиляции, метаданные).
- Прочие вкусности (рефлексия, препроцессор, условная компиляция, статические расширения).
И этот список на самом деле можно еще продолжить, однако не стану усложнять все на данном этапе.
Так где все это использовать?
Краткий ответ — везде. Вот вам кейс из жизни и практики. Один из моих проектов — это мобильное, полуигровое приложение, в котором используется нативный UI и OpenGL для отрисовки игровых элементов. А также NodeJS сервер, который соединяется с Firebaseи обрабатывает клиентские запросы. Для решения этой задачи я написал мобильный фреймворк (что-то вроде React-native), который транслируется в С++ для iOS и в Java для Android, оставаясь полностью нативным. Но поскольку Haxe не умеет транслироваться в Objective-C, то мне все же пришлось написать небольшую прослойку для UI, которая обращалась к Obejctive-C методам из C++. Разделив логику и представление, я получил до 90% общей кодовой базы.
Используя JS как целевой язык, я продолжал писать код сервера на Haxe под NodeJS. Таким образом, сервер разделял единую логику с клиентами, написанную на одном языке, что оказалось гораздо приятнее и удобнее, чем если бы я тянул два\три\четыре разных языка на одном проекте. К слову, скоро я планирую открыть исходный код своего мобильного фреймворка.
Также Haxe постоянно выручает меня при разработке игр. Обилие фреймворков и библиотек в этой области позволяет запускать свои приложения абсолютно на всех платформах, включая консоли. А например, для тех, у кого остались проекты на ActionScript был создан такой фреймворк как OpenFL, который на 99,9% покрывает Flash API и способен запускаться как в браузере, так и на С++ платформах.
Я использую Haxe даже при написании мелких, консольных утилит, которые упрощают мне жизнь.
В итоге Haxe можно смело называть Full Stack языком. Используя только один инструмент и один язык, вы сможете гораздо более эффективно вести разработку своего продукта. И достаточно лишь поверхностного понимания целевой платформы, чтобы начать для нее разрабатывать.
Посмотрим код
В рамках этой статьи я приведу простые примеры использования Haxe для JavaScript. На мой взгляд, это один из самых оптимизированных целевых языков, так как JavaScript на выходе практически не уступает написанному вручную и остается легко читаемым.
Haxe | JavaScript |
class Test { static function main() { trace("Haxe is great!"); } } | (function () { "use strict"; var Test = function() { }; Test.main = function() { console.log("Haxe is great!"); }; Test.main(); })(); |
Попробовать самостоятельно: try.haxe.org
Справа в качестве исходных данных у нас есть класс Test
со статической функцией main
, которая является точкой входа для программ, написанных на Haxe. Ну а trace
— функция, которая выводит отладочную информацию в консоль.
Как и говорилось выше, по сгенерированному коду слева можно заметить, что Haxe старается все решать нативными средствами платформы. В случае с JavaScript он не создает ничего лишнего для функции trace и использует нативную для JS реализацию — console.log();
Взгляните теперь на следующий пример:
Haxe | JavaScript |
class Test { static function main() { var a:Int = 10; var b = 20; var c = a + b; trace('Result is ${c}'); } } | (function () { "use strict"; var Test = function() { }; Test.main = function() { console.log("Result is " + 30); }; Test.main(); })(); |
Попробовать самостоятельно: try.haxe.org/#3496D
Здесь мы можем увидеть сразу три интересные вещи:
- Хоть Haxe это строго типизированный язык, указывать тип необязательно. Haxe умеет выводить тип из выражения прямо во время компиляции.
- Интерполяция строк, где переменная захватывается прямо внутри самой строки.
- Haxe — это оптимизирующий компилятор. Он не станет генерировать вам переменные, если они нигде не используются. Haxe посчитает все во время компиляции, а в сгенерированный код подставит результат вычислений. К слову, это срабатывает статический анализатор, который можно отключить, при необходимости.
Ловко, не так ли?
Следующим примером я продемонстрирую то, что мы все еще имеем доступ к нативным функциям платформы.
Haxe
import js.Browser.document; import js.Browser.console; class Test { static function main() { document.addEventListener("DOMContentLoaded", function() { console.log(document.location); }); } }
JavaScript
(function () { "use strict"; var Test = function() { }; Test.main = function() { window.document.addEventListener("DOMContentLoaded",function() { window.console.log(window.document.location); }); }; Test.main(); })();
Попробовать самостоятельно: try.haxe.org/#b2A0c
И последний пример, который мы рассмотрим, — это untyped код. Untyped — это нетипизированные вставки кода на языке целевой платформы. В данном случае мы присваиваем к переменной Haxe функцию из JavaScript.
Haxe
class Test { static function main() { var a = untyped __js__('function(){console.log("Hello from untyped code!")}'); a(); } }
JavaScript
(function () { "use strict"; var Test = function() { }; Test.main = function() { var a = function(){console.log("Hello from untyped code!")} a(); }; Test.main(); })();
Попробовать самостоятельно: try.haxe.org/#AD46b
И это все, что вам генерирует Haxe, больше никаких зависимостей. Вы получаете компактный .js файлик, который можете свободно подключать как на свою домашнюю страничку, так и на высоконагруженный портал (или NodeJS сервер), не беспокоясь о производительности. Будьте уверены, на выходе будет оптимизированный код.
Подобные примеры справедливы и для всех остальных языков. Но, к сожалению, здесь мы их уже не будем рассматривать.
Выводы
Является ли Haxe волшебной палочкой? Вовсе нет. Написать один раз и использовать везде не всегда возможно, ведь Haxe старается не создавать оберток над нативными кодом. Таким образом, говоря о кроссплатформенной разработке, стоит понимать, что если вы используете JavaScript-пакеты (как на последних двух примерах), то вы не сможете транслировать такой код, например, в Java. Для решения подобных задач Haxe поддерживает условную компиляцию: когда вы можете обернуть какой-либо код в директивы (define), и все, что не попадает под их условие, не будет добавлено в компиляцию. Пример: try.haxe.org/#5B0FE
Однако Haxe все равно остается очень мощным инструментом, который стоит попробовать. Особенно если вы full-stack разработчик, особенно если вы ведете разработку кроссплатформенных приложений и не хотите, чтобы голова болела сразу о трех языках разом.
Если вы заинтересовались Haxe и решили его попробовать, то полистайте примеры кода (меню Examples сверху). Это поможет вам понять основные конструкции языка и как их применять на практике. Там же можно сравнить написанный, исходный код с кодом целевой платформы, который вы получаете на выходе.
Данная статья, скорее, просто ознакомительная. Однако если тема вызовет интерес у читателей, то я бы продолжил писать о Haxe и начал бы цикл статей с примерами и, возможно, даже уроками. Мы могли бы поговорить на такие темы как написание нативных мобильных приложений, использование NodeJS с Haxe, использование нативных библиотек целевых платформ и о разработке кроссплатформенных игр.
Как начать использовать Haxe?
- Скачайте установщик Haxeдля своей ОС.
- Скачайте и установите VSCodeи плагин vshaxe, который доступен в меню расширений VSCode (Ctrl + Shift + X).
- Переходите к мануалу, взгляните на cookbook.
- Начинайте писать код!
P. S. Если вы работаете под Windows, то можете установить HaxeDevelopвместо VSCode. Это IDE на основе FlashDevelop, которая со временем будет развиваться по своему пути. HaxeDevelop даст вам такие бонусы, как автозаполнение кода, рефакторинг, шаблоны Haxe проектов и многое другое.
Ссылки
Официальный сайт: haxe.org
Попробовать Haxe онлайн: try.haxe.org
Мануал: haxe.org/manual/introduction.html
Cookbook: code.haxe.org
Официальный форум: groups.google.com/forum/#!forum/haxelang
Русскоязычный skype-чат: join.skype.com/ck4xJ5Arrp3R
Связь со мной:
Email: dmitry.hryppa@gmail.com
Skype: dmitryhryppa
Спасибо skype-сообществу Haxe за помощь в редактировании материала.
И спасибо всем, кто дочитал ;)