Haxe — это кроссплатформенный язык программирования высокого уровня и компилятор , который может создавать приложения и исходный код для множества различных вычислительных платформ из одной базы кода. Это бесплатное программное обеспечение с открытым исходным кодом , выпущенное под лицензией MIT . [2] Компилятор, написанный на OCaml , распространяется под лицензией GNU General Public License (GPL) версии 2.
Haxe включает в себя набор функций и стандартную библиотеку [3] , поддерживаемую на всех платформах , таких как числовые типы данных , строки , массивы , карты , двоичные данные , отражение , математика, протокол передачи гипертекста ( HTTP ), файловая система и общие форматы файлов . Haxe также включает API-интерфейсы для каждой платформы, специфичные для каждой цели компилятора. [4] Kha, OpenFL и Heaps.io — популярные платформы Haxe, которые позволяют создавать многоплатформенный контент из одной базы кода. [5]
Хакс зародился [6] с идеей поддержки клиентского и серверного программирования на одном языке и упрощения логики связи между ними. Код, написанный на языке Haxe , можно скомпилировать в JavaScript , C++ , Java , JVM , PHP , C# , Python , Lua [7] и Node.js. [8] Haxe также может напрямую компилировать байт-код SWF , HashLink и NekoVM , а также работать в интерпретируемом режиме. [9]
Haxe поддерживает externs (файлы определений), которые могут содержать информацию о типах существующих библиотек для описания целевого взаимодействия типобезопасным способом, например, файлы заголовков C++ могут описывать структуру существующих объектных файлов . Это позволяет использовать значения, определенные в файлах, как если бы они были статически типизированными объектами Haxe. Помимо внешних средств, существуют и другие решения для доступа к собственным возможностям каждой платформы.
Многие популярные IDE и редакторы исходного кода поддерживают разработку Haxe . [10] Haxe Foundation официально не рекомендует какую-либо конкретную среду разработки или набор инструментов, хотя VS Code , IntelliJ IDEA и HaxeDevelop имеют наибольшую поддержку разработки Haxe. Основные функции подсветки синтаксиса , завершения кода , рефакторинга , отладки и т. д. доступны в различной степени.
Разработка Haxe началась в октябре 2005 года. Первая альфа-версия была выпущена 14 ноября 2005 года. [11] [12] Haxe 1.0 был выпущен в апреле 2006 года с поддержкой программ Adobe Flash , JavaScript и NekoVM . Поддержка PHP была добавлена в 2008 году, а C++ — в 2009 году. Дополнительные платформы, такие как C# и Java, были добавлены после капитального ремонта компилятора в 2012 году.
Haxe был разработан Николя Каннассом и другими участниками и первоначально назывался haXe [13] , потому что он был коротким, простым и «имеет X внутри», который, как с юмором утверждает автор, необходим для успеха любой новой технологии. [14]
Haxe является преемником компилятора ActionScript 2 с открытым исходным кодом MTASC [15] , также созданного Николя Каннассом и выпущенного под лицензией GNU General Public License версии 2 или более поздней.
Язык Haxe может компилироваться в байт-код , который может выполняться непосредственно виртуальными машинами, на которые он нацелен. Он может компилироваться в исходный код на C++ , JavaScript , PHP , C# , Java , Python и Lua . У Haxe также есть интерпретатор eval . [16] Этот же интерпретатор также используется во время компиляции для запуска макросов, которые позволяют модифицировать абстрактное синтаксическое дерево (AST).
Эта стратегия компиляции в несколько языков исходного кода основана на парадигме «запись один раз, запуск где угодно» . Это также позволяет программисту выбрать лучшую платформу для работы. Типичные программы Haxe работают одинаково на всех платформах, но разработчики могут указать код, специфичный для платформы, и использовать условную компиляцию , чтобы предотвратить его компиляцию на других платформах.
Компилятор Haxe является оптимизирующим компилятором и использует встраивание полей и функций , устранение хвостовой рекурсии , свертывание констант , развертывание цикла и устранение мертвого кода (DCE) для оптимизации производительности скомпилированных программ во время выполнения. [17] Компилятор Haxe предлагает опцию null-safety , он проверяет время компиляции на наличие значений, допускающих значение NULL.
В Haxe поддерживаемые платформы известны как «цели» и состоят из следующих модулей:
В следующей таблице описывается платформа и языковая поддержка в Haxe. Язык Haxe позволяет разработчикам получить доступ ко многим функциям платформы, но Haxe не является полнофункциональным движком, им могут потребоваться фреймворки, позволяющие создавать контент для определенных платформ.
Haxe — язык общего назначения, поддерживающий объектно-ориентированное программирование , обобщенное программирование и различные конструкции функционального программирования . Такие функции, как итерации , исключения и отражение кода , также являются встроенными функциями языка и библиотек. Необычный среди языков программирования, Haxe содержит одновременно строгую и динамичную систему типов . Компилятор будет проверять типы неявно, используя вывод типов , и выдавать ошибки во время компиляции, но он также позволяет программисту обойти проверку типов и полагаться на динамическую обработку типов целевой платформы. Можно использовать все собственные целевые API.
Haxe имеет сложную и гибкую систему типов. Типы типов, которые он предлагает, — это классы, интерфейсы, типы-функции-методы, анонимные типы, алгебраические типы данных (называемые enum в Haxe) и абстрактные типы. Параметрический полиморфизм возможен с классами, алгебраическими типами и типами функций, обеспечивая языковую поддержку универсального программирования, основанного на стирании типов. Это включает поддержку вариативности в полиморфных функциях , но не в конструкторах типов .
Система типов является статической , если не присутствуют аннотации для динамической типизации для использования с целями, которые их поддерживают. Проверка типов следует за номинальной типизацией, за исключением анонимных типов , где вместо этого используется структурная типизация . Наконец, поддерживается вывод типов , позволяющий объявлять переменные без аннотаций типов .
Весь код Haxe организован в модули, адресация которых осуществляется с помощью путей. По сути, каждый файл .hx представляет собой модуль, который может содержать несколько типов. Например, чтобы создать тип A
в пакете my.pack , как показано, структура папок должна быть my\pack , а файл в папке package может быть A.hx.
// файл my/pack/A.hx, пакет my . пакет ; класс А {}
В других модулях другие типы можно импортировать, поместив import
операторы под определением пакета, напримерimport my.pack.A;
Модуль может содержать несколько типов, например следующие. Из этого модуля можно импортировать по одному типу, используя import my.pack2.A;
. Тип может быть private
, и в этом случае доступ к нему может получить только содержащий его модуль.
упакуйте мой . пакет2 ; typedef A = { a : String } частный typedef B = { b : String }
Классы (ключевое слово class
) в Haxe аналогичны классам в Java или TypeScript. Их поля могут быть методами, переменными или свойствами, статическими или экземплярными соответственно. Haxe поддерживает методы доступа public
и private
и более продвинутые методы управления доступом, которые обозначаются с помощью аннотаций. Методы и статические константные переменные можно встроить с помощью ключевого слова inline
. Поля могут быть помечены как final
объявляющие константу, которая должна быть инициализирована немедленно или в конструкторе и не может быть записана, в случае, если функция final
будет помечена как непереопределяемая в подклассах.
Интерфейсы в Haxe очень похожи на интерфейсы, например, в Java.
интерфейс ICreature { общественная переменная рождения : Дата ; публичное имя переменной : String ; публичная функция age (): Int ; } класс Fly реализует ICreature { public varbirth : Date ; публичное имя переменной : String ; публичная функция age (): Int return Date . сейчас (). getFullYear () — рождение . получитьПолныйГод (); }
Haxe поддерживает общее программирование . Ниже приведен пример функции идентичности .
идентичность функции < T >( arg : T ): T { return arg ; }
Перечислимые типы — важная особенность языка; они могут иметь параметры типа и быть рекурсивными. [20] Они обеспечивают базовую поддержку алгебраических типов данных , позволяя включать типы продуктов аналогично Haskell и ML . Выражение switch
может применять сопоставление шаблонов со значением перечисления, что позволяет элегантно решать сложные проблемы программирования:
перечисление Цвет { красный ; зеленый ; синий ; rgb ( r : Int , g : Int , b : Int ); } класс Colors { статическая функция toInt ( c : Color ): Int { переключатель возврата ( c ) { красный регистр : 0xFF0000 ; зеленый регистр : 0x00FF00 ; синий регистр : 0x0000FF ; случай rgb ( р , г , б ): ( р << 16 ) | ( г << 8 ) | б ; } } статическая функция validCalls () { var redint = toInt ( Color . red ); var rgbint = toInt ( Color . rgb ( 100 , 100 , 100 )); } }
Примерами параметрических типов перечислений являются типы стандартной библиотеки Haxe Option [21] и либо: [22]
enum Option < T > { Some ( v : T ); Никто ; } enum Либо < L , R > { Влево ( v : L ); Вправо ( v : R ); }
Haxe также поддерживает обобщенные алгебраические типы данных (GADT). [23] [24]
Анонимные типы определяются путем явного обозначения их структуры с использованием синтаксиса, который соответствует математическому представлению типа на основе записей. Их можно использовать для реализации структурной типизации аргументов функции (см. ниже), и им можно присвоить псевдоним с ключевым словом typedef
:
typedef AliasForAnon = { a : Int , b : String , c : Float -> Void };
Функции — это первоклассные значения в Haxe. Их тип обозначается стрелками между типами аргументов, а также между типами аргументов и возвращаемым типом, как это принято во многих функциональных языках. Однако, в отличие от известных примеров, таких как Haskell или семейство языков ML , не все функции являются унарными (функциями только с одним аргументом), а в Haxe функции не могут применяться частично по умолчанию. Таким образом, следующие сигнатуры типов имеют иную семантику, чем в вышеупомянутых языках. Тип F1
— это функция, которая принимает String
в качестве аргументов и возвращает значение типа Float
.
Типы F1
и F2
обозначают один и тот же тип, за исключением того, что F2
используется помеченный параметр, что полезно для завершения и документирования.
Типы F4
и F5
обозначают один и тот же тип. Обе являются двоичными функциями, которые возвращают двоичную функцию типа F3
. Для F5
объявления типа функции внутри типа функции используется синтаксис.
typedef F1 = String -> Float ; typedef F2 = ( текст : String ) -> Float ; typedef F3 = ( оценка : Int, текст: String ) -> Float ; typedef F4 = ( оценка : Int, текст: String ) -> F3 ; typedef F5 = ( оценка :Int, текст:String ) -> (( оценка :Int, текст:String ) -> Float );
В Haxe анонимные функции называются лямбда и используют синтаксис function(argument-list) expression;
.
var f = функция ( x ) return x * x ; ж ( 8 ); // 64 ( функция ( x , y ) возвращает x + y )( 5 , 6 ); // 11
Относительно новым дополнением к системе типов Haxe является концепция, называемая абстрактными типами . В Haxe это относится к чему-то отличному от обычного абстрактного типа . Они используются для неявных преобразований между типами, позволяя повторно использовать существующие типы для определенных целей, например реализацию типов для единиц измерения. Это значительно снижает риск смешивания значений одного и того же базового типа, но с разным значением (например, мили и км).
В следующем примере предполагается, что по умолчанию используется метрическая система, а для устаревших данных требуется преобразование в мили. Haxe может автоматически конвертировать мили в километры, но не наоборот.
абстрактный километр ( Float ) { общественная функция new ( v : Float ) this = v ; } Abstract Mile ( Float ) { общественная функция new ( v : Float ) this = v ; @:to общедоступная встроенная функция toKilometer (): возврат километра ( новый километр ( this / 0.62137 )); } Класс Test { статический вар км : километр ; статическая функция main () { var one100Miles = новая миля ( 100 ); км = один100 миль ; трасса ( км ); // 160.935 } }
Как показано в примере, для присвоения «km = one100Miles;» явное преобразование не требуется. поступать правильно.
Абстрактные типы полностью являются особенностью Haxe во время компиляции и вообще не существуют во время выполнения программы. Например, обе переменные используют абстрактные типы, описанные выше Mile
, и Kilometer
будут иметь тип Float
во время выполнения. [25]
Во многих функциональных языках программирования важную роль играет структурная типизация . Haxe использует его при наличии анонимных типов, используя именительную типизацию объектно -ориентированного программирования , когда задействованы только именованные типы. Анонимные типы в Haxe аналогичны неявным интерфейсам языка Go в плане типизации. В отличие от интерфейсов Go, можно создать значение, используя анонимный тип.
класс FooBar { общественный вар foo : Int ; общественная панель var : String ; публичная функция new () { foo = 1 ; бар = "2" ; } функция AnyFooBar ( v : { foo : Int , bar : String }) трассировка ( v . foo ); тест статической функции () { вар fb = новый FooBar (); фб . AnyFooBar ( ФБ ); фб . AnyFooBar ({ foo : 123 , bar : "456" }); } }
Компилятор Haxe разделен на один интерфейс и несколько серверов. Интерфейсный интерфейс создает абстрактное синтаксическое дерево (AST) из исходного кода и выполняет проверку типов, расширение макросов и оптимизацию AST. Различные серверные части преобразуют обработанный AST в исходный код или генерируют байт-код , в зависимости от их цели.
Компилятор написан на OCaml . Его можно запускать в режиме сервера, чтобы обеспечить завершение кода для интегрированных сред разработки (IDE) и поддерживать кэш для дальнейшего ускорения компиляции. [26]
{{cite journal}}
: Требуется цитировать журнал |journal=
( помощь )haxe --wait [host:]port