Привет, Хабр! Представляю вашему вниманию перевод статьи The Joy of Haxe. FontStruct’s love affair with a neglected programming language.

Логотип Haxe в редакторе шрифтов FontStruct

Довольно грубая попытка воспроизвести логотип Haxe в редакторе шрифтов FontStruct

Недавно мы открыли исходный код наиболее важной части нашего модуля для создания шрифтов. Это библиотека fonthx для создания TrueType-шрифтов, и написана она на Haxe.
В данной статье практически нет кода. Если же вас интересует только код, то ознакомиться с ним можно на github, а его работа показана на примере простейшего редактора пиксельных шрифтов, построенного с использованием библиотеки fonthx.

Независимо от того, знакомы ли вы с Haxe или нет, проект fonthx возможно заинтересует вас, так как в нем демонстрируются некоторые удивительные возможности языка, малоизвестные вне сообщества Haxe — в частности, возможность писать код на одном приятном языке с дальнейшей компиляцией / трансляцией не только в Javascript, но и во множество других платформ, в случае fonthx такими платформами являются JVM (код проекта транслируется в Java), нативный код (C++ или C #), NodeJS или WASM.

Меня можно назвать убежденным полиглотом. Как и многие другие разработчики, я пишу код на разных языках и, уважая серьезные намерения тех, кто предпочитает специализироваться только на каком-либо одном языке, я также опасаюсь всех тех фанатов и мошенников-евангелистов, которые твердят об одном истинно верном языке. Но что же побудило меня использовать такой нишевый язык как Haxe для создания ключевых компонентов FontStruct, а также написать данную статью? И что же такое Haxe?

Haxe


Haxe — это современный, строго типизированный язык программирования с некоторыми интересными функциями и небольшой стандартной библиотекой.

Наиболее существенной особенностью языка является его способность компилировать один и тот же код под разные целевые платформы.

Большинство разработчиков знакомы с понятием «изоморфной» разработки, когда программист пишет и серверный и клиентский код на одном языке. Чаще всего в качестве такого языка используется Javascript или TypeScript, но также может использоваться любой другой язык, способный компилироваться в Javascript. Haxe в данном направлении идет намного дальше, открывая ряд интересных дополнительных возможностей. Из одной кодовой базы на Haxe возможно скомпилировать исполняемый файл, Java-приложение, WASM-модуль, приложение на NodeJS, приложение, работающее в браузере, мобильное приложение, и даже библиотеки для таких языков как PHP, Lua или Python.

В FontStruct мы пользуемся данной возможностью, разрабатывая ключевые компоненты нашего приложения на Haxe. Серверные модули компилируются как Java-сервлеты, а модули клиента скомпилированы в виде приложений на JS. И хотя в настоящее время мы фокусируемся в основном на этих двух целевых платформах (а также на NodeJS для запуска тестов на скорость), мы также рассматриваем возможность использования инструментов, предоставляемых экосистемой Haxe, для создания мобильных приложений на C++. Кроме того, использование Haxe в дальнейшем может позволить создать нативное (не основанное на Electron) настольное приложение.

Благодаря тому, что Haxe поддерживает такое множество целевых платформ, он лучше всех (по крайней мере для наших задач) реализует идею “напиши код один раз — запускай его везде”, лучше чем любой инструмент, с которым я встречался за последние двадцать лет. Это дает ощущение того, что один и тот же код возможно скомпилировать под любую платформу или среду выполнения.

Процесс принятия Haxe


FontStructor - бесплатный редактор шрифтов на FontStruct.com
FontStructor — бесплатный редактор шрифтов на FontStruct.com

Более 10 лет назад, когда FontStruct был запущен, для редактора шрифтов FontStructor, а также для виджетов для просмотра шрифтов использовался Adobe Flash. А для создания TrueType-шрифтов на сервере использовался совершенно независимый код, написанный на Java.

Старая Flash-версия редактора FontStructor
Старая Flash-версия редактора FontStructor. Все элементы управления в нем рисовались во Flash. Обратите внимание на странные полосы прокрутки на панелях слева. Со временем главное меню в верхней части страницы постепенно расходилось визуально и функционально с html-меню, используемом в остальных частях сайта. Здесь нет ни DOM, ни CSS

Хотя FontStruct был и остается огромным успехом, наши первоначальные технические решения не прошли проверку временем. Развитие веб-стандартов и отсутствие поддержки плагина на мобильных платформах сделали Flash непригодным для использования в веб-приложениях. Также нам приходилось иметь дело с дублированием кода между сервером на Java и клиентом на Flash, а также между Flash и остальными частями клиента, написанными на HTML/JS/CSS. Было необходимо постоянно синхронизировать между собой три кодовые базы как с точки зрения функциональности, так и дизайна.

В 2013 году мы начали рассматривать возможность использования Haxe, в частности, в качестве средства для перевода редактора FontStructor с Flash на HTML5. В наших первоначальных исследованиях мы обнаружили, что уже имеются доступные инструменты для автоматического преобразования ActionScript кода в Haxe (as3hx) и даже Haxe-порт MVC-фреймворка Robotlegs, который мы использовали во Flash-версии. И так мы начали эксперимент по портированию клиента.

Медленный и полный проблем старт


Наш первый год отношений с Haxe сопровождался нерешительностью и сомнениями.

По нескольким причинам, и не в последнюю очередь из-за ограниченности ресурсов, которые мы могли бы ему посвятить, процесс портирования оказался довольно медленным. Как уже отмечали другие авторы, инструмент для автоматического преобразования ActionScript-кода в Haxe (as3hx) оказался очень полезным, но не лишенным недостатков — полученный с помощью него код пришлось дополнительно просматривать и править. Во время этого процесса пришло понимание того, что наша кодовая база раздута и ошибочна в своем дизайне, поэтому параллельно с портированием мы решили внести улучшения, тем самым еще больше замедлив дальнейший прогресс. Кроме того, Haxe был для нас новым языком, поэтому мы неизбежно делали ошибки, изучая этот язык и его инструменты.

Безусловно, самой большой нашей ошибкой было решение дополнительно использовать сторонний UI-фреймворк на Haxe.

Для Haxe существует множество таких фреймворков (возможно, их даже слишком много), предоставляющих унифицированный API-интерфейс для отрисовки графики на различных платформах. OpenFL и NME являются примерами таких фреймворков и предоставляют инструменты для сборки приложений на Haxe под мобильные платформы и даже консоли. При этом они предоставляют реализацию Flash API для отрисовки графики. Все это казалось очень заманчивым — мы могли перенести наше приложение на HTML5, используя знакомое API и, возможно, даже создать одновременно с этим приложения для Android и iOS!

Поэтому для портирования нашего приложения на Haxe мы решили использовать еще и OpenFL.

Я не хочу проявить неуважение к OpenFL (мне даже хочется сказать, что: «Проблема не в OpenFL, а в нас»). OpenFL — фантастический проект, который хорошо показал себя во многих проектах, и мы можем вернуться к нему в будущем, но после портирования порядка 90% нашего приложения на Haxe, мы решили все же отказаться от него.

OpenFL оказался гораздо более серьезной зависимостью, чем мы ожидали. Изначально планировалось, что он будет использоваться лишь как внешняя библиотека для нашего UI, однако в итоге оказалось, что OpenFL тащит за собой свои собственные инструменты для сборки проектов, специальные форматы файлов для описания проектов, а также дополнительные внешние зависимости. Возможно это обусловлено тем, что как и большая часть экосистемы Haxe, OpenFL старается отвечать потребностями инди-разработчиков игр, при этом он развивается довольно быстро и основное внимание при его разработке уделяется добавлению новых функций, а не стабильности.

Самым главным для нас стало то, что сгенерированный с помощью OpenFL HTML5-код идеален для игр, но для такого приложения как FontStruct он не подходит. Все, чего мы хотели в итоге, это отобразить в браузере обычное DOM-дерево, которое мы могли бы стилизовать с помощью CSS, а не набор canvas-элементов или спрайтов, созданных OpenFL.

Нам был нужен обычный HTML5, а не попытка повторить Flash в браузере без использования дополнительных плагинов.

Веселье


Как только мы отказались от использования OpenFL и поняли, что можем делать все, что хотели, используя только Haxe, все пошло быстрее, проще и, в конечном счете, намного веселее.

И работать с Haxe — это весело. Он, можно сказать, создан специалистами по веселью — независимыми разработчиками игр. Разработчикам игр нужна быстрая компиляция, а также единая кодовая база для создания приложений для настольных компьютеров, браузеров, iOS, Android и консолей. Разработчикам игр нужен производительный и стабильный код. И Haxe предоставляет все эти замечательные возможности, и не только для разработчиков игр.

Не побоюсь высказать идею о том, что одна из самых больших проблем Haxe — относительно небольшой размер его сообщества и связанная с этим разреженность его экосистемы — также является его преимуществом с точки зрения опыта для разработчика. Работая с Haxe, вы вряд ли будете тратить часы на гугление и поиск информации на stack-overflow, или на разбор и сравнение разных уроков по интересующей теме, а также во время изучения API какого-нибудь нового фреймворка или библиотеки — этих ответов, уроков и библиотек вполне может просто не быть. А если и есть, то, скорее всего, они будут единственными материалами по данным темам. С Haxe вы будете решать задачи программирования самостоятельно (!), самостоятельно писать библиотеки или, не испытывая ни малейшего чувства вины, даже самостоятельно заново изобретать или портировать колесо. Это весело и дает свободу, и это то, к чему многие разработчики стремятся после бесконечных фреймворков и современной разработки, связанной с копированием кода из разных источников. Используя принцип “меньше — значит лучше”, Haxe не уникален, но это его определенный плюс.

Haxe дает программисту уникальные возможности. Он дает особое ощущение удивительного открытия и радости. Используя Haxe, с его возможностью компилировать код под множество целевых платформ, возникает ощущение, что программист освобождается от одной из самых фундаментальных зависимостей из всех существующих — самой среды исполнения.

Рендерер FontStruct


Запуск нашего первого компонента на Haxe для сайта FontStruct в апреле 2015 года был странным и неожиданным событием.

Галерея является центральной частью FontStruct: доступные для поиска, сортируемые списки тысяч шрифтов, созданных на нашей платформе. С самого начала в 2008 году у нас были постоянные проблемы со скоростью загрузки и с производительностью предварительного просмотра шрифтов как в самой галерее, так и на других страницах сайта.

Предварительный просмотр шрифтов в галерее FontStruct
Часть страницы галереи FontStruct, где показан предварительный просмотр шрифтов, созданных на платформе. Первоначально каждый отдельный элемент предварительного просмотра был представлен медленно загружаемым Flash-роликом!

Поскольку шрифты FontStruct («FontStructions») хранятся в проприетарном формате и часто редактируются, невозможно использовать их для рендеринга, как обычные TrueType-шрифты. Это означало невозможность создания на сервере растровых изображений для предварительного просмотра шрифтов (с использованием библиотеки FreeType).

Чтобы «решить» эту проблему, в самые ранние дни жизни FontStruct мы использовали отдельные Flash-ролики для элементов галереи. Каждый Flash-ролик загружал и парсил данные в нашем проприетарном формате, и затем показывал на клиенте изображение для предварительного просмотра. При отображении на странице 20 и более таких роликов, каждый из которых загружал данные и пытался отрисовать шрифт, время загрузки и потребление ресурсов пользовательской машины значительно увеличивались, и ситуация еще больше усугублялась со временем, так как шрифты, разработанные в нашем редакторе, становились все более и более сложными.

В конце концов мы использовали причудливое гибридное решение: при самом первом просмотре шрифта использовался Flash-ролик, который генерировал изображение для предпросмотра, затем данное изображение захватывалось и сохранялось на сервере в виде PNG-файлов. И для предпросмотра для следующих пользователей уже использовались сохраненные на сервере PNG. — Этот странный хак значительно улучшил время загрузки страницы, но он был грязным и, в конечном счете, неправильным что ли. Верным решением было бы написать совершенно новый серверный модуль — например, на Java или PHP — для загрузки и парсинга данных шрифта, и дальнейшего создания на его основе растрового изображения, но у нас просто не было ресурсов для этого.

Тем временем процесс портирования Fontstructor на Haxe продвигался очень медленно, и мы были далеки от релиза. Но мы продвинулись достаточно далеко, чтобы понять, что новый код на Haxe может решить наши проблемы с предварительным просмотром шрифтов в галерее.

У нас уже был Haxe код для загрузки и парсинга нашего формата шрифтов. У нас был код для отрисовки глифов (на Canvas в HTML5 или на спрайтах во Flash). У нас также были все компоненты, необходимые для решения проблемы на стороне клиента. Могли ли мы адаптировать этот код для использования на сервере?

Да! После того, как мы осознали это, процесс пошел очень быстро. Сначала мы думали задействовать C++ и библиотеку Cairo для отрисовки шрифтов (надеясь, что мы сможем написать расширение для PHP или какой-нибудь CGI-модуль), однако вместо этого было решено использовать Java. — Как замечательно иметь возможность сделать такой фундаментальный выбор с помощью нескольких строк кода и условной компиляции! Мы также могли использовать для этого NodeJS и node-canvas, но мы уже были знакомы с процессом создания и развертывания Java-сервлетов, и в Java есть все необходимые нам функции для отрисовки и манипулирования растровыми изображениями. Возможно, писать код на Java нам было не по нраву, но с Haxe такая необходимость отпадает.

Код для отрисовки
Такой высокоуровневый код для отрисовки может быть скомпилирован и запущен как на клиенте (JavaScript), так и для сервере (в JVM)

В итоге на внесение изменений в нашей кодовой базе у нас ушло всего несколько дней, и новый рендерер был запущен. В одночасье мы значительно улучшили производительность галереи FontStruct, избавились от использования грязных хаков, и, самое главное, запустили наш самый первый компонент на Haxe на бой. Мы поняли, что Haxe способен удивлять и обладает гораздо большими возможностями, чем мы от него ожидали.

Прощание с Flash (и c ванильной Java)


В ноябре 2015 года, то есть спустя 7 месяцев, мы успешно запустили первый клиентский модуль на Haxe — HTML5-версию виджета для предпросмотра шрифтов. Я думаю, что наши пользователи практически не заметили изменений, что с одной стороны как-то разочаровывает, но, в конечном счете, является показателем успешности данного начинания.

Теперь у нас оставался только один Flash-модуль на сайте — редактор FontStructor, и нам понадобился еще один год, чтобы, наконец, запустить в ноябре 2016 года его HTML5-версию. Так настало время окончательно отказаться от нашего AS3-кода и объявить FontStruct свободным от Flash.

Новая HTML5-версия FontStructor
Новая HTML5-версия FontStructor, запущенная в 2016 году

В августе 2018 мы портировали на Haxe модуль генерации шрифтов «FontMortar». Этот последний порт позволил нам полностью отказаться от кода, написанного на Java.

Я не готов использовать Haxe для всего. Да, я знаю, что есть проекты, где он используется в качестве основного инструмента для всех аспектов веб-разработки, но меня в качестве основы нашего веб-приложения очень устраивает превосходный Symfony фреймворк. В FontStruct продолжает использоваться множество различных языков программирования, но внедрение Haxe позволило нам уменьшить размер и сложность наиболее важных частей нашего кода. Для нашей крошечной организации такое упрощение оказалось жизненно необходимым для поддержания и развития платформы.

Погружаясь глубже в Хакс


Если это первый раз, когда вы услышали о Haxe и мой рассказ заинтересовал вас, то я просто обязан перечислить еще несколько фактов о нем.

  • Поддержка языка со стороны IDE вполне приличная и постоянно улучшается, активно развиваются модули под IntelliJ Idea и Visual Studio Code.
  • Haxe предоставляет средства для работы с нативным кодом и библиотеками, таким образом, он не ограничивает ваши возможности, навязывая лишь небольшое подмножество доступных функций. Если вы ведете разработку под JavaScript, то у вас есть возможность использовать любую JavaScript-библиотеку, например, для работы с React доступны различные биндинги. Для FontStructor мы используем несколько npm-модулей, таких как interactive.js и opentip. Написание биндингов для них заняло всего пару минут.
  • Haxe имеет надежную продвинутую систему типов с такими возможностями как параметризация типов, обобщенные классы и методы, абстрактные типы и выведение типов.
  • В Haxe есть чрезвычайно мощные макросы, обеспечивающее доступ к AST во время компиляции, что позволяет разработчикам добавлять свои собственные языковые конструкции и генерировать код динамически.
  • Несмотря на то, что по Haxe в интернете не так уж и много ресурсов, для него есть репозиторий библиотек, покрывающих общие потребности разработчиков за пределами стандартной библиотеки (кроме того на Github можно найти еще больше репозиториев, не представленных на haxelib — прим. переводчика).
  • И последнее, но от этого не менее важное: у Haxe очень талантливое и отзывчивое сообщество.

Заключение


Большинство опытных разработчиков готовы к изменениям, но при этом они осторожны в выборе используемых технологий. Вероятно, что в какой-то момент большинство из Вас также испытывало желание сменить язык программирования в рамках проекта, особенно когда появляются новые, модные языки, с большим количеством интересных возможностей. Мы были осторожны насчет выбора Haxe, думая о том, как долго продлятся наши отношения. Примерно такими были наши мысли на его счет:

Звучит здорово, но у него такое маленькое сообщество. Что с ним будет через 5 лет? Сайт вроде нормальный, но почему-то он не выглядит современным. И это не внушает доверия.
Кажется, что он не так уж хорошо документирован.

Разве это не для инди-разработчиков игр?


Спустя пять лет использования Haxe, я искренне удивлен тем, что не сожалею о нашем выборе данной технологии. Несмотря на все недостатки и все сложности, вызванные ими, несмотря на относительно небольшое сообщество и отсутствие крупных корпоративных спонсоров, Haxe полностью справляется со своими задачами. С Haxe я чувствую свободу и независимость от какой-либо платформы. Теперь у нас единая кодовая база для основных компонентов FontStruct, в то время как раньше их было две. За прошедшие несколько месяцев работы новые версии сервлетов, отвечающих за генерацию шрифтов и изображений для предварительного просмотра, ни разу не давали сбоев. Новые HTML5-редактор и виджет для предварительного просмотра теперь работают во всех браузерах, включая мобильные, тогда как раньше мы были вынуждены работать с устаревшей и умирающей технологией.

И, если отбросить практическую выгоду, работа с Haxe приносит радость и чувство волшебства, радость Haxe!

Комментарии (34)


  1. Fengol
    11.12.2018 10:28

    Haxe — это современный, строго типизированный язык программирования с некоторыми интересными функциями и небольшой стандартной библиотекой.

    Наиболее существенной особенностью языка является его способность компилировать один и тот же код под разные целевые платформы.

    Лично мое мнение, что это препроцессор для множества языков. Ведь несмотря, что его синтаксис можно скомпилировать под множество языков, не зная их api, то есть не зная сам язык, написать ничего не получится. К тому же, его возможности можно считать доисторическими.


    1. Zaphy Автор
      11.12.2018 12:03

      А какой язык тогда вместо него предложите?


      1. Fengol
        11.12.2018 14:34

        В зависимости от задачи? мой выбор — ts, c#, f#. Просто когда говорят о подобных языках, то перечисляют только плюсы. Типа — один язык, все платформы. А минусы — нужно знать все языки под которые будешь компилировать. Невозможно написать одно приложение под все платформы будут просадки производительности, тем более трансляторе как haxe. Если на xamarin несмотря наприведение все к единому интерфейсу упорешся разграничивать все в зависимости от платформы, здесь логика и методы будут вообще разные, это рано или поздно сделает проект неповоротливым.

        Поэтому в 2019 году нужно выбирать технологии в зависимости от задач. Почти у всех нормальных языков есть кроссплатформенные инструменты.


        1. andrew911
          11.12.2018 15:33

          Не обязательно знать и компилировать под все языки в конкретном случае.
          Haxe намного раньше и в чем-то лучше заменяет TS для JS. Некоторые компании его используют в связке с Unity3D и Unreal используя одну кодовую базу для клиента и сервера.


          1. AVL93
            11.12.2018 15:44

            Идея в этом конечно очень крутая, но чтобы реально использовать один код на разных платформах — надо очень хорошо понимать, где язык гарантирует одинаковую работу кода, а где нет. А он может не гарантировать этого даже в самых, на первый взгляд, простых ситуациях.


          1. Fengol
            11.12.2018 19:37

            Мне не известны случаи, когда какой-либо язык не привносил чего-то уникального в тот мир, для которого он создавался. Поэтому унификация всех языков за счет собственных абстракций-языковых конструкций (как например реализация структур данных) сведет на нет все преимущества языков. Есть такое устоявшееся мнение, что писать нужно не на языке, а с использованием языка. Эта фраза была сказана очень давно и на сегодняшний день уже не актуальна, так как с тех времен, многое изменилось, появились огромные корпорации, коммунити, которые разрабатывают-затачивают языки под свои конкретные задачи. Поэтому сейчас к выбору языка подходят также, как к выбору инструмента. Если язык абстрагирует работу, скажем с самым слабым местом, с i\o или же структурами данных, с помощью собственных реализаций, то он он просто нивелирует все плюсы. Поэтому сейчас, если кто-то ещё и держит в голове вышеупомянутую фразу, то её нужно как минимум переместить на другой архитектурный слой, а именно инфраструктурный. То есть, унификация в современном мире должна реализовываться за счет провайдеров\плагинов, в АОП ключе. Но насколько мне известно в haxe, этого нет. К тому же до ts, ему как до звезды. ts на сегодня один из лучших языков. синтаксические возможности haxe, это прошлый-прошлый-прошлый век.

            И мне сложно представить в чем смысл писать одну игру на unity и ue одновременно? Это очень похоже на глупость. Почему бы не писать сервер, на тех языках, на которых хочется и связывать это все при помощи микросервисов? Так делают все крутые игровые чуваки. А код на ue и unity разве может быть идентичным? Максимум какие-то утильки, из-за которых думать о выборе haxe, просто дольше, чем написать.


            1. andrew911
              11.12.2018 20:50

              В чем Haxe-у как до звезды TS и какие его возможности прошлый век?
              Я не писал, что одна игра и на UE и на Unity3D, это разные игры и разные компании.

              Мне не известны случаи, когда какой-либо язык не привносил чего-то уникального в тот мир, для которого он создавался. Поэтому унификация всех языков за счет собственных абстракций-языковых конструкций (как например реализация структур данных) сведет на нет все преимущества языков.

              Слишком громкая и слишком абстрактная фраза.


            1. dmitryhryppa
              11.12.2018 21:35
              +1

              Если язык абстрагирует работу, скажем с самым слабым местом, с i\o или же структурами данных, с помощью собственных реализаций, то он он просто нивелирует все плюсы.

              Вы о том, что какая-то операция на Си у вас займет 0.0003 секунды, а на Haxe 0.0008 секунд? Такого рода оптимизации не нужны для 95% софта. И тонны Electron приложений тому довозательство.
              Более того, такие игры как Northgard, Papers please, Dead Cells, Rymdkapsel, Evoland и многие другие, которые написаны на Haxe и работают в том числе и на консолях с вами не согласны. А в играх-то производительность — не последнее слово, ведь так?
              Более того, если уж говорить за возможности Haxe, то он позволяет писать платформозависимый код используя нативные конструкции конечного языка, в который он будет транслироваться, включая структуры данных. Включая вставки из этого языка (а-ка ассемблерные вставки в Си). Так что нет никакой проблемы написать узкое место «нативно».

              ts на сегодня один из лучших языков

              Ну камон :) Крайне спорное заявляение.

              К тому же до ts, ему как до звезды.

              Haxe компилируется в десяток раз быстрее, а JS код на выходе более оптимизированный, чем у TS за счет соответствующих возможностей: инлайн методы, конструкторы, статический анализатор кода и тд и тп.

              синтаксические возможности haxe, это прошлый-прошлый-прошлый век.

              У хакса действительно, не так много синтаксического сахара, по сравнению с котлином, например. Но вот про прошлый-прошлый-прошлый век — вообще с потолка :)


            1. pecheny
              12.12.2018 10:21
              +1

              Если язык абстрагирует работу, скажем с самым слабым местом, с i\o или же структурами данных, с помощью собственных реализаций, то он он просто нивелирует все плюсы.

              Язык предоставляет абстракции для обобщенной работы с I/O и структурами данных на разных платформах. Как один из инструментов.
              Кроме этого, он предоставляет много других инструментов: экстерны, абстракты и тайпдефы, которые позволяют писать обобщенный, и в то же время эффективный код.
              Из недавнего: писал абстракцию над промисами для шарпов и js. При компиляции в js оно превращалось в работу со встроенными промисами, а на шарпах использовало библиотеку RSG.Promise. АПИ у них отличается принципиально, но в сгенерированном коде нет прослоек, один и тот же хаксовый код превращается на каждой платформе в прямые обращения к собственным платформенным классам.
              Почему бы не писать сервер, на тех языках, на которых хочется и связывать это все при помощи микросервисов?

              Сам сервер можно писать на чем угодно, но есть большие куски логики, которые бывает очень удобно использовать независимо на клиенте и сервере.
              Если их писать на haxe, то даже без микросервисной архитектуры можно использовать эту логику в совершенно разных стеках (В частности, менять стеки, не меняя логику). Мне известны успешные примеры использования haxe c серверной стороны, например, в стеках node.js, java, php.
              А код на ue и unity разве может быть идентичным?

              Я верю, что можно написать такие прослойки, которые позволят запускать один и тот же код на обоих движках, хоть это будет и не самым эффективным/целесообразным.
              Тем не менее, большая часть кода может быть написана с использованием абстракций, что позволит переносить наработки между платформами независимо.
              Вот эти ребята использовали оба движка с хаксом
              www.youtube.com/watch?v=WKs8QRuMC3k
              и в каком-то из докладов я слышал, что чать наработок успешно перекочевала.

              Кроме того, есть Kha, который предоставляет абстракции для работы с графическими АПИ, и позволяет писать достаточно низкоуровневые вещи типа шейдеров, корые можно компилировать под OpenGL, DirectX, Metal, Vulkan, WebGl, канвас и т.д (в том числе, для запуска внутри готовых движков типа анрила).
              Так делают все крутые игровые чуваки.

              Ну тут я даже не знаю, как и возразить. Такая уверенность завораживает.


        1. YuriHx
          11.12.2018 15:44

          Всегда нужно выбирать технологии в зависимости от задач.
          И в любом случае нужно знать API платформы, для которой выполняешь задачу, кэп.
          Когда пишешь на том же C# под Unity или для другой платформы тебе нужно знать API или другой платформы, но это никак на влияет на оценку C#.


          1. AVL93
            11.12.2018 22:07

            на том же C# под Unity
            Я могу взять довольно крупный проект на Unity, который сейчас таргетирован на windows, закомментировать платформозависимые куски кода, и скомпилировать под WebGL (asm.js). И работать он будет точно так же как и win-версия, несмотря на то что целевая платформа javascript и я не внес ни строки кода, зависящего от специфичного для платформы api.
            Заголовок спойлера
            А вот Haxe так не умеет, в чем и было мое самое большое разочарование относительно этого языка.


            1. andrew911
              11.12.2018 22:28

              Haxe так умеет посредством фреймворков OpenFL, NME, Kha


              1. AVL93
                11.12.2018 22:36

                Фреймворки перекрывают API, однако остается тот факт что многие базовые конструкции языка могут вести себя по разному. Например, стандартный Int на некоторых таргетах будет переполняться через 32 бита, а на некоторых — вести себя как float.


                1. dmitryhryppa
                  11.12.2018 23:05

                  Например, стандартный Int на некоторых таргетах будет переполняться через 32 бита, а на некоторых — вести себя как float

                  Нет, это не так. И никогда так не было. Int будет работать консистентно на всех платформах и уж тем более не будет вести себя как float.


                  1. AVL93
                    11.12.2018 23:11

                    Как раз таки это даже документировано: haxe.org/manual/types-overflow.html
                    Где-то переполняется, где-то теряет точность на больших числах. И да, можно использовать Int32, но что делать если фреймворк который я использую, внутри использует Int? И опять же, это не единственный фактор, просто первый вспомнившийся пример.


                    1. dmitryhryppa
                      12.12.2018 00:18

                      Как раз таки это даже документировано: haxe.org/manual/types-overflow.html

                      Я оспариваю не то, что документировано, а вашу риторику, что у вас все начнет переполняться, только от того, что Int, вдруг, везде разный. Речь идет за 32-ух битный Int. Он везде будет вести себя одинаково и до тех пор пока вы не запиеште туда значение больше, чем 32-ух битный Int может вмещать. То, как себя поведет переполнение уже и зависит от платформы, если не использовать специальные типы, которые это предотвращают.

                      Тот проект, который у вас работает отлично, скажем, на C++ таргете, будет 1 в 1 работать и на JS таргете, с таким же поведением Int'a и ничего у вас не переполнится. Аналогично вашему примеру с Юнити.

                      А если вы в Int пишете значение больше 2^32, не используя для этого Int64 — это уже вопрос к вам.


                      1. AVL93
                        12.12.2018 00:27

                        Я могу спокойно работать с большими Int на js таргете, и наткнуться на проблемы при переносе кода на C++. И наоборот, я могу построить вполне себе нормальный алгоритм, опираясь на то что в C++ int гарантированно и предсказуемо переполняется, и получить проблемы при переносе на js. В приведенном примере с Unity — такого не наблюдается, код на C# скомпилированный в js будет работать именно так как описано в спецификации языка C#.
                        И, да, я понимаю что это осознанное решение разработчиков языка — пожертвовать универсальностью ради производительности. Но я считаю что это надо более явно и подробно описывать в документации, с большими флагами «ТУТ UNDEFINED BEHAVIOUR!!!».


                        1. dmitryhryppa
                          12.12.2018 01:18

                          Я могу спокойно работать с большими Int на js таргете, и наткнуться на проблемы при переносе кода на C++

                          Вы с этим столкнетесь даже если вручную будете портировать код, потому что нельзя впихнуть больше, чем «обычный» int позволяет. Вам придется использовать для этого другой тип. Например, long в С++.
                          Я искрине не понимаю, в чем тут принципиальная проблема. Потому что там, где нужен большой инт, там используют для этого специальный тип, объявляющий большой инт.

                          И наоборот, я могу построить вполне себе нормальный алгоритм, опираясь на то что в C++ int гарантированно и предсказуемо переполняется, и получить проблемы при переносе на js.

                          Если железно нужен Int32, используйте Int32 и все будет консистентно.


                          1. AVL93
                            12.12.2018 01:27

                            в чем тут принципиальная проблема
                            Напомню, что эта ветка обсуждения началась с того, что при использовании C# в Unity и компиляции его в js мне ровным счетом ничего не нужно знать про особенности js. А при использовании Haxe — нужно. Неконсистентность Int — всего лишь один из таких факторов.
                            Любой кроссплатформенный язык имеет как строго описанное в спецификации поведение, так и UB определяемые целевой платформой. В haxe же таких UB очень много (да и спецификации языка как таковой нет).
                            В целом, я понимаю вашу точку зрения, и знаю что перечисленные мной недостатки (или то что я считаю недостатками) можно обойти. Но для этого надо понимать как сам Haxe, так и целевой язык на довольно высоком уровне.


                  1. rafuck
                    12.12.2018 01:40

                    Я думаю, тут имеется в виду, что в JS вообще нет int, там есть только double.


    1. dmitryhryppa
      11.12.2018 16:22
      +1

      … не зная сам язык, написать ничего не получится.

      И да и нет, и не совсем. На TS->JS писать, ведь, ничего никому не мешает. В чем тогда проблема писать на Haxe->JS? Более того, Haxe имеет некоторые преимущества перед конкурентами:
      github.com/damoebius/HaxeBench

      К тому же, его возможности можно считать доисторическими.

      А о каких именно возможностях речь? Синтаксис?


  1. AVL93
    11.12.2018 13:13

    С первого взгляда мне этот язык очень понравился, даже на работе агитировал за то чтобы некоторые новые проекты на нем делать… Но потом столкнулся с тем что:
    — он на самом деле не является строго типизированным, строгость типизации полностью зависит от целевой платформы
    — в стандартной библиотеке мало документации и много багов
    Так что я перестал стремиться его использовать для хоть сколько-то важных проектов, разве что мелкие вспомогательные инструменты иногда на нем пишу.


    1. YuriHx
      11.12.2018 15:53

      — он на самом деле не является строго типизированным, строгость типизации полностью зависит от целевой платформы
      Полностью? Вы серьёзно? Не могли бы вы раскрыть эту мысль? Как, например, влияет платформа на типизацию на этапе компиляции?
      в стандартной библиотеке мало документации и много багов
      Можете дополнить это утверждение ссылками на issue c багами в стандартной библиотеке, которые серьёзно осложняют вашу работу?


      1. AVL93
        11.12.2018 16:16

        Как, например, влияет платформа на типизацию на этапе компиляции?
        На этапе компиляции есть какая-то проверка типов. Однако никто не запрещает присвоить например Dynamic в Int, даже явный каст не потребуется. На статических таргетах — ошибка выполнения, на динамических — как будто все хорошо. И получается что один и тот же простой код на разных таргетах может дать 3 разных результата.
        В моем понимании, «строгая» типизация не должна такого позволять ни в коем случае. Если я не прав, то что же тогда понимается под словами «строго типизированный»?
        дополнить это утверждение ссылками на issue c багами в стандартной библиотеке
        Давно не писал на haxe ничего сложнее сотни строк, так что вспомню только например вот это — github.com/HaxeFoundation/neko/issues/167. Помню еще, что несколько раз сталкивался с тем что например поддержка ssl — согласно документации, есть, а в коде там одно большое TODO. А окончательно я разочаровался в языке, посмотрев на то как реализован HashMap.


        1. andrew911
          11.12.2018 16:22

          По поводу Dynamic, тут вопрос в качестве кода писавшего — не используйте его и будет все в порядке, а возможность отстрелить себе ногу даст любой язык.


          1. AVL93
            11.12.2018 16:27

            Ситуация была примерно такая: получаю JSON, использую стандартный парсер из стандартной библиотеки, получаю на выходе объект описанного мной класса, все поля строго типизированы — красота!!! (я надеялся что оно работает примерно так же как например gson). А потом внезапно (после пары часов отладки) обнаруживаю, что оказывается в Int поле спокойно можно записать строку. А что именно получится — либо просто строка, либо число получившееся после ее парсинга, либо ошибка выполнения — зависит от таргета.
            P.S. В стандартном парсере json тоже баги были, но я сейчас точно не вспомню с чем именно связанные.


            1. andrew911
              11.12.2018 17:04

              Для строгой типизации есть другие варианты, помимо JSON, да и для него должны быть варианты.


            1. pecheny
              12.12.2018 08:00

              Зато haxe позволяет написать 30 строк макроса, который позволяет сгенерировать безопасный десериализатор для всех интовых полей классов, отмеченых метой.
              Довольно изящно работая с узлами AST через pattern matching (к слову об устаревшем синтаксисе)
              try-haxe.mrcdk.com/#4a425
              Вот пример, сам макрос на закладке Source 2, можно посмотреть, как работает на js, и какой код генерирует.


        1. bromzh
          11.12.2018 16:36

          В моем понимании, «строгая» типизация не должна такого позволять ни в коем случае. Если я не прав, то что же тогда понимается под словами «строго типизированный»?

          Типизация может быть строгой (сильной), но при этом динамической (как в Python). Может быть статической, но слабой (неявной), как в C++ и C.
          Под строгой подразумевается типизция без неявного приведения типов. То есть, чтобы сложить число со строкой, нужно явно сделать из числа строку или наоборот. В питоне нельзя сделать так: a = 1 + '2'
          Под нестрогой (слабой) подразумевается типизация с неявным преобразованием типов (да и вообще, с преобразованием типов без создания нового объекта). Например, в С++ есть reinterpret_cast, а в си некоторые численные типы могут неявно быть преобразованы. В другом слаботипизируемом языке возможны вещи вроде 1 + '2', !!1, const a = +'2'


        1. YuriHx
          11.12.2018 17:32

          никто не запрещает присвоить например Dynamic в Int, даже явный каст не потребуется
          Это очень плохой пример. Мягко говоря. А строго говоря (если уж вы за строгость типизации) это вообще не пример. Интересно, почему для подтверждения слов о строгой типизации вы выбрали именно пример с Dynamic? Это ведь тип специально для тех, кому не нужна типизация, кто хочет от неё отказаться, в конкретном месте, явно.
          Это же одно из важных свойств Haxe, что он даёт свободу выбора — нужна свобода и динамика — пожалуйста, использую Dynamic, untyped и т.д., нужна строгость — ок, не используй их и на этапе компиляции всё будет строго, включая выявленные типы.
          Ну и конкретно о статической типизации, которую вы видимо имели имели в виду под строгой. Вот подробная таблица по целевым платформам: haxe.org/documentation/introduction/compiler-targets.html где указано, где она поддерживается платформой(!), а где нет. А в контексте нашей с вами дискуссии важна строка под таблицей, которая явно говорит нам что «Haxe code itself is statically typed no matter what target it is compiled to.»
          Давно не писал на haxe ничего сложнее сотни строк, так что вспомню только например вот это — github.com/HaxeFoundation/neko/issues/167.
          Это ок, понятно, если вашей целевой платформой была neko, то я не удивлён вашим разочарованием. Хотя это уже про выбор платформы, а не язык. И одно из ключевых слов тут, возможно — «давно». Про neko ниже уже немного написали, уточню, что на момент эта платформа уже не актуальна, и будущего у неё нет, есть более современные решения, в том числе от того же разработчика. Последнее не имхо — те, кто следят за прогрессом Haxe, знают, что развивать neko дальше не будут.


          1. AVL93
            11.12.2018 18:02

            почему для подтверждения слов о строгой типизации вы выбрали именно пример с Dynamic?
            Просто потому что это самый простой пример который можно привести. Наткнулся я на это, ни разу не используя Dynamic в своем коде (чуть выше комментарий про json).

            В общем, спасибо за ответ, кажется я понял в чем было мое заблуждение относительно работы с Dynamic. У меня было очень стойкое убеждение, что если компилятор не требует явного приведения типов при присвоении — значит, либо сработает неявное (или не сработает и гарантированно упадет при запуске), либо вообще все в порядке и оно не требуется.


  1. dmitryhryppa
    11.12.2018 16:42

    Помню еще, что несколько раз сталкивался с тем что например поддержка ssl — согласно документации, есть, а в коде там одно большое TODO.

    SSL уже везде и давненько есть. Там, где его раньше не было, там надо было библиотеку использовать.

    Dynamic в Int, даже явный каст не потребуется

    Тип Dynamic — это ведь динамический тип, который может оказаться чем угодно в рантайме и риски с его использованием лежат исключительно на плечах программиста. Просто не стоит его использвать там, где ему не место и все. К слову, есть ведь typedef, который позволяет типизировать любой Dynamic, чтобы, случайно, не стрельнуть себе в ногу.

    Давно не писал на haxe ничего сложнее сотни строк, так что вспомню только например вот это — github.com/HaxeFoundation/neko/issues/167.

    Справедливости ради, Neko — не совсем показатель, ибо через чур эзотерический и потому, даже рядом не стоит с Haxe -> JS, C++, PHP и другими.


    1. AVL93
      11.12.2018 17:02

      риски с его использованием лежат исключительно на плечах программиста
      Все знакомые мне строго типизированные языки в таких случаях требуют делать явный каст (и я как программист прописывая явный каст, понимаю что тут есть риск падения). И если тип в рантайме не соответствует ожидаемому — вот он сработавший риск, ошибка выполнения.


      1. Cerberuser
        12.12.2018 06:22

        TypeScript — строго типизированный или нет? Если да — то что там делает any, которое приводится в любой тип без явного каста?