Haxe
Haxe — высокоуровневый кросс-платформенный язык программирования с открытым исходным кодом, а также компилятор, с помощью которого можно создавать приложения и генерировать исходный код для разных платформ, сохраняя единую кодовую базу[3][4][5][6]. Haxe включает в себя функциональность, поддерживаемую на всех платформах, например: числовые типы данных, строки, массивы, а также поддержку некоторых файловых форматов (xml, zip)[4][7]. Haxe также включает в себя поддержку специфических API для каждой целевой платформы компилятора. Код, написанный на языке Haxe, может быть скомпилирован в код JavaScript, C++, Java, JVM, PHP, C#, Python, Lua и Node.js[8]. Haxe-код также компилируется в SWF, HashLink и Neko, байт-код, а так же может быть выполнен в режиме интерпретации[8]. Основные пользователи Haxe — это TiVo, Prezi, Nickelodeon, Disney, Mattel, Hasbro, Coca Cola, Toyota и BBC[9][10]. OpenFL и Flambe — популярные фреймворки Haxe для создания мультиплатформенного контента и программ из единой кодовой базы[10]. Кроме этого, в данный момент активно развивается Snõwkit[11]. В связи с всё большим вытеснением технологии Adobe Flash в последние годы в пользу HTML5, Haxe, Unity и другие кросс-платформенные инструменты уделяют последнему всё больше времени, сохраняя обратную поддержку с Adobe Flash Player[10][12]. АрхитектураЕдиный языкСамым значимым аспектом разработки архитектуры Haxe было решение о поддержке Adobe Flash, JavaScript и серверных приложений единой кодовой базой[13][14]. В типичных веб-проектах разработчики должны использовать множество разных языков, чтобы построить полноценное веб-приложение[13][14]:
Haxe был создан с идеей объединения всех этих компонентов единой кодовой базой, а также упрощения взаимодействия между компонентами приложения[13][14][15]. В книге, за авторством Николаса Кеннеси (основателя проекта Haxe), указываются первоначальные цели создания Haxe[13]:
КомпиляторКомпилятор Haxe разделён на один фронтенд и множество бэкэндов. Фронтенд отвечает за парсинг и проверку типов, применение макросов, общую оптимизацию, различные трансформации кода и создания промежуточного представления кода в виде абстрактного синтаксического дерева (АСД). Каждый из бэкендов отвечает за трансляцию этого АСД в исходный код или байткод целевой платформы. Компилятор написан на OCaml. Он может быть запущен в режиме сервера для поддержки автодополнения кода в IDE, также в этом режиме поддерживается кэш для уменьшения времени компиляции[16]. ПроизводительностьКомпилятор Haxe — оптимизирующий компилятор, также использующий подстановку функций, свёртку констант, удаление мёртвого кода (DCE) для оптимизации производительности скомпилированных программ. Производительность программ, написанных на Haxe, зависит от целевой платформы.
РазработкаРазработка Haxe началась в октябре 2005[21], а первая бета-версия была выпущена в феврале 2006. Haxe 1.0 был выпущен в апреле 2006 и поддерживал трансляцию в Adobe Flash, Javascript и Neko. Haxe был разработан Николасом Хеннесси (Nicolas Cannasse) и другими авторами, и первоначально был назван haXe, потому что это короткое, простое имя, а также «у него есть X в названии» — атрибут, необходимый для того, чтобы новая технология стала успешной, с юмором отмечал автор языка[22]. Haxe — это преемник ActionScript 2 компилятора MTASC с открытым исходным кодом, также сделанный Николасом Хеннесси[13][23] и выпущенный под лицензией GNU General Public License версии 2 или выше[24]. Haxe имеет много общего с ActionScript 3. Компилятор Haxe разрабатывается на языке OCaml, но для того, чтобы писать на Haxe, знаний OCaml не требуется. Преимущества использования Haxe включают в себя:
Исходный кодРекомендуемая IDE для разработки на Haxe — это FlashDevelop[13], которая поддерживает ActionScript 2, 3 и Haxe, как основные языки с подсветкой синтаксиса, автодополнением кода и другими возможностями[13][26]. Эта IDE также поддерживает сворачивание кода, рефакторинг и интерактивную отладку.[27] Для того, чтобы использовать уже существующий код, сообщество открытого ПО создало конверторы исходного кода для: Поддержка платформЯзык Haxe можно транслировать в байткод различных виртуальных машин, таких как Adobe Flash Player и Neko, а также в исходные коды ActionScript 3, JavaScript, включая экспериментально поддерживаемые C++ и C#. Эта стратегия «компиляции» в различные исходные коды была разработана под вдохновение парадигмы «один раз написать, запускать где угодно». Данная стратегия также позволяет выбирать программисту наилучшую платформу для работы программ.
ЯзыкHaxe — это объектно-ориентированный язык общего назначения, с поддержкой механизма обработки исключений и вывода типов для параметров классов. Также языком и библиотеками поддерживаются обобщённое программирование, рефлексия, итераторы и функциональное программирование[34]. Haxe также, в отличие от многих других языков, одновременно поддерживает и статическую и динамическую типизацию. Компилятор может проверять вывод типов и выдавать ошибки времени компиляции, но также разработчики могут выключить эту проверку, и положиться на динамическую проверку типов целевой платформы. Язык Haxe похож на ECMAScript, хотя практически любой код на ECMAScript не сможет быть скомпилирован на Haxe без модификации. В отличие от ECMAScript, Haxe — компилируемый язык. Haxe был создан под влиянием ActionScript, Java, и OCaml[14]. Так как Haxe был основан на ActionScript 3, он поддерживает все функции Flash API, хотя и требует лучше оформленный код и более высокие стандарты разработки, нежели компиляторы Adobe. Hello worldЭта программа напишет «Hello World» после компиляции и запуска: class Main {
static function main() {
trace("Hello World");
}
}
Проверить этот код можно, сохранив его в файл с именем Система типовHaxe — статически типизированный язык. Он имеет богатую систему типов, включая классы, интерфейсы, функциональные типы, анонимные типы, алгебраические типы данных (ADT, называемые «перечислениями» в Haxe), а также абстрактные типы данных. Классы, алгебраические типы данных и функциональные типы поддерживают параметрический полиморфизм, основанный на стирании типов, в других объективно-ориентированных языках часто называемый «Дженериками». Haxe включает с себя поддержку ограниченного полиморфизма и полиморфизма подтипов. К тому же, Haxe поддерживает структурную типизацию и номинальную типизацию. Для облегчения работы программистов и без ущерба безопасности типов, Haxe поддерживает вывод типов, который во многих случаях позволяет не писать типы вручную. КлассыКлассы (ключевое слово «class») в Haxe похожи на таковые в Java или AS3. Их полями могут быть методы, статические переменные класса или свойства экземпляра класса. Haxe поддерживает атрибуты доступа «public» и «private», а также более продвинутые методы контроля доступа (ACL, ссылки), которые описываются аннотациями. Методы и статические переменные с постоянным значением могут быть встроены с помощью ключевого слова «inline». Интерфейсы в Haxe похожи на интерфейсы Java. interface ICreature {
public var birth:Date;
public var name:String;
public function age():Int;
}
class Fly implements ICreature {
public var birth:Date;
public var name:String;
public function age():Int return Date.now().getFullYear() - birth.getFullYear();
}
ПеречисленияПеречисляемые типы — это ключевая особенность языка. Перечисления могут иметь собственные параметры, а также быть рекурсивными[35]. Они похожи на алгебраические типы данных, как таковые в языках вроде ML или Haskell. Строго говоря, это правильные типы-суммы, при условии, что типы‑произведения, включенные в них, обязаны быть определены внутри этих типов-сумм. Это значит, что перечисления не просто именованные «магические числа», как в большинстве языков, ими можно элегантно решать сложные архитектурные проблемы: enum Color {
red;
green;
blue;
rgb( r : Int, g : Int, b : Int );
}
class Colors {
static function toInt ( c : Color ) : Int {
return switch ( c ) {
case red: 0xFF0000;
case green: 0x00FF00;
case blue: 0x0000FF;
case rgb(r, g, b): (r << 16) | (g << 8) | b;
}
}
static function validCalls() {
var redint = toInt(Color.red);
var rgbint = toInt(Color.rgb(100, 100, 100));
}
}
Haxe также поддерживает параметрические перечисляемые типы. Примером могут послужить реализация типов Option, Either и ConsList, причем ConsList ещё и рекурсивный: enum Option<T> {
Some(v:T);
None;
}
enum Either<T,U> {
Left(v:T);
Right(v:U);
}
enum ConsList<T> {
Nil;
Cons(head:T,tail:ConsList<T>);
}
Документация на сайте указывает[36], что Haxe также поддерживает обобщённые алгебраические типы (GADT), но не приводит пример создания такового. Анонимные типыАнонимные типы определяются с помощью явного описания их структуры, им также можно назначить псевдоним, используя определение типа (ключевое слово «typedef»): typedef Anon = { a:Int, b:String, c:Float->Void };
Функциональные типыФункциональные типы являются объектами первого класса в Haxe. Они описываются, используя стрелки между типами аргументов, и между типами и возвращаемым значением, как и в многих других функциональных языках. Однако, в отличие от Haskell или семейства ML, не все функции в Haxe унарные (функции с одним аргументом), по умолчанию они не могут быть частично применены. Таким образом сигнатуры типов в следующих примерах имеют отличное от вышеупомянутых языков значение. Тип F — это функция, которая принимает Int и String как аргументы и возвращает Float как результат. В языках, где существуют только унарные функции, этот тип означал бы функцию, которая принимает Int как аргумент и возвращает функцию типа String->Float. Типы F2 и F3 описывают один и тот же тип. Они оба описывают бинарные функции, которые возвращают бинарную функцию типа F. Для F2 описывается случай использования функционального типа внутри другого определения. typedef F = Int->String->Float;
typedef F2 = Int->String->F;
typedef F3 = Int->String->(Int->String->Float);
Абстрактные типыКонцепция, названная абстрактные типы, — это последнее дополнение в систему типов Haxe. Они позволяют повторно использовать существующие типы для специфических целей, например, реализации типов для единиц измерения, при этом сильно уменьшая возможность смешивания разных систем (например мили и километры). Термин «абстрактный тип» в контексте языка Haxe имеет другое значение, в отличие от обычных абстрактных типов. Следующий пример предполагает, что метрическая система используется по умолчанию, а конвертация в мили необходима, чтобы поддерживать устаревшие данные. Haxe способен автоматически преобразовывать мили в километры, но не в обратную сторону. abstract Kilometer(Float) {
public function new(v:Float) this = v;
}
abstract Mile(Float) {
public function new(v:Float) this = v;
@:to public inline function toKilometer():Kilometer return (new Kilometer(this / 0.62137));
}
class Test {
static var km:Kilometer;
static function main(){
var one100Miles = new Mile(100);
km = one100Miles;
trace(km); // 160.935
}
}
Пример показывает, что не обязательно делать явное преобразование Структурная типизацияСтруктурная типизация играет важную роль во многих функциональных языках программирования и, в то же время, довольно малую в распространенных ООП языках. В отличие от номинальной системы типов, равенство двух типов определяется не равенством каких-либо имён типа, а скорее устройством типа. Структурные типы можно рассматривать как неявные интерфейсы: class FooBar {
public var foo:Int;
public var bar:String;
public function new(){ foo=1; bar="2";}
function anyFooBar(v:{foo:Int,bar:String}) trace(v.foo);
static function test(){
var fb = new FooBar();
fb.anyFooBar(fb);
fb.anyFooBar({foo:123,bar:"456"});
}
}
См. такжеТакже, на платформе Haxe: Другие языки, компилирующиеся в JavaScript: Другие мультиплатформенные языки: Примечания
Ссылки |