PHP
Haxe
Comments 25
0
Хороший язык. Вот честно сказать еще лет 10 назад выглядел как сейчас Rust на замену C/C++, только для всякой скриптовщины. На за все 10 лет что я его периодически мониторю, он так и не взлетел. И мне интересно почему.
+4
Не могу согласиться про скриптовщину, если правильно понял, о чем речь. Haxe никогда не позиционировался ни как «легковстраиваемый рантайм», ни как «shell-ориентированный интерпретатор». Если рассматривать кросс-компиляцию в другой скриптовый язык, то это всегда будет усложнением системы — даже при наличии своих плюсов, не панацея.

А «не взлетел» он, скорее всего, потому, что нет того, что у HaxeFoundation нет продавана. Самый заметный продаван – Джошуа, но он продвигает OpenFL, из-за чего, к сожалению, Haxe ассоциируется именно с ним.

Язык мощный, но у него своя ниша. Не всегда там, где он мог бы быть полезен, про него знают/понимают.
0
В PHP тоже нет автоматическое преобразование типов, если использовать declare(strict_types=1); в начале файла.
0
Все немного не так. При использовании директивы получим TypeError при несоответствии типов. Без нее как раз будет попытка приведения. Приведение там довольно своеобразное. Можем передавать число вместо строки, int вместо float, или наоборот, но не более.
0
во-вторых, можно объединять несколько условий с помощью | (а не дублировать ключевое слово case)

Кошмар какой. Это с какой версии? Давно не в теме. Раньше же использовалась запятая вместо | ( old.haxe.org/ref/syntax?lang=ru#switch ). Что за помутнение заставило Канасье такое запилить?
Судя по try.haxe.org/#D4A66 даже оборачивание в скобки не помогает.
0
Скорее всего с третьей версии, которая вышла в 2013 году. Так что довольно давно.
0

Насколько я помню, этот синтаксис появился одновременно с запятыми или даже чуть раньше. Потому что он позаимствован из окамла (на котором пишет Канасье — создатель языка), где в паттерн-матчинге используется именно вертикальная черта для разделения вариантов.


Что касается вашего примера, то не понятно, чему не помогает оборачивание в скобки?
Math.random() возвращает Float в пределах от 0 до 1. Поэтому case 1 | 2 никогда не совпадёт с его результатом.

+1
Haxe компилятор не анализирует диапазон Math.random() — это так для примера вставил.
 case ((1 | 2)): trace("1|2");
преобразуется в
case 1:case 2:
		console.log("1|2");
		break;

по крайней мере для js таргета, что имхо сильно противоречивое решение. Было бы логично, если бы сгенерировалось
case 3:
		console.log("1|2");
		break;

для варианта со скобками.
+1
я добавлю, со стороны геймдева, что у Haxe есть хорошая игровая либа HaxeFlixel, на которой можно писать игры под веб, десктоп, мобилы. Я писал на ней до 2016, под Android получались очень шустрые и компактные игры. Потом я пересел на Java, на LibGDX по ощущения скорость и требовательность приложений была не лучше или ненамного лучше — простые двухмерные игры шустро шли и на планшетах 2011 года выпуска (что я потерял при переходе на написание исключительно на HTML5 ))

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

update: на волне ностальгии прогуглил — похоже, у HaxeFlixel есть хороший конкурент — мультиплатформенный Kha, который показывает в BunnyMark удивительные рекорды



(источник скриншота)

Правда, я бы советовал смотреть не на количество спрайтов на экране при 60 fps, а на развитость фреймворка, документированность и коммюнити. ah, here we go again )
0
посмотрел и в контексте с вышеприведенным BunnyMark повторю — high performance в играх и приложениях является критическим в узком сегменте, да и там часто тормоза возникают не из-за того, что язык или платформа плохо выводит спрайты, а потому что
— используются живые частицы там, где достаточно спрайтовых анимаций
— при заходе в дом продолжает рендериться весь игровой мир (еще в Серьезном Сэме мододелы боролись с этим, вручную закрывая двери после захода в комнату)
— из-за запутанной архитектуры для мелких частных действий вызывается куча перерасчетов в массе объектов, которые вообще никак не должны реагировать
— разработчик платформы оптимизировал ее под определенные тесты (или писал тесты под платформу), а в вашей игре совсем другие требования и оптимизация разработчика только все усложняет — лучше бы он писал более абстрактно
— дизайнер игры нарисовал такое, что плохо ложится на платформу в плане скорости

наибольшая проблема performance — это performance самой разработки )
+1
Но он это сделал не потому, что Haxe плохой, а просто потому, что у него свое видение развития языка. Имхо, конечно, но мне кажется, что его язык применим только в ограниченом типе проектов и имеет абсолютно другую философию, т.к. это своего рода очередной D без GC.

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

В общем, языки с абсолютно разными целями. Вот :)
0
Я давно мечтаю перевести HaxeFlixel на Kha и получить Khaxel :)
+1

А можете описать свой воркфлоу с Haxe? Что использовали, какая интеграция с IDE и есть ли различные анализаторы (статические, динамические)?

0
workflow был очень прост — FlashDevelop с минимумом подсказок + Android SDK

это сейчас я избалован продуктами от JetBrains, а тогда я смело набирал без всяких интеллектуальных подсказок и думал, что все хорошо ))

PS: говорят, что есть хорошая интеграция с Visual Studio и там есть даже плагин специальный, но я не проверял.
+1
Вот со студией как раз вообще никакой интеграции нет. У MS есть совершенно отдельный кроссплатформенный редактор VSCode – речь о нем. Для нее MS придумали очень классную штуку – поддержку language server, который позволяет всю интеллектуальную поддержку языка вынести наружу и легко интегрировать. В случае с Haxe так и сделано: сам компилятор, который знает все о типах (даже тех, которые генерируются макросами в процессе компиляции), обеспечивает поддержку языка. Поэтому в VSCode, наравне с другими редакторами, поддерживающими lang серверы, поддержка haxe на уровне.
FlashDevelop, который сейчас также известен как HaxeDevelop, вроде бы тоже имеет интеграцию компиляторной помощи; а так же много всяких удобных штук для haxe. Он продолжают развиваться.
Ну и наконец, люди, избалованные JetBrains, могут поставить отличный haxe-плагин, у которого как раз на днях вышел новый релиз. Я пользуюсь именно этим вариантом.
+4
Забавно. Такой хелловолд из руководства:
class Main {
    static function main() {
        trace("hello world");
    }
}

для Lua генерирует такую портянку:
Заголовок спойлера
-- Generated by Haxe 4.0.0-rc.3+e3df7a4
local _hx_array_mt = {
  __newindex = function(t,k,v)
    local len = t.length
    t.length =  k >= len and (k + 1) or len
    rawset(t,k,v)
  end
}

local function _hx_tab_array(tab,length)
  tab.length = length
  return setmetatable(tab, _hx_array_mt)
end

local function _hx_anon_newindex(t,k,v) t.__fields__[k] = true; rawset(t,k,v); end
local _hx_anon_mt = {__newindex=_hx_anon_newindex}
local function _hx_a(...)
  local __fields__ = {};
  local ret = {__fields__ = __fields__};
  local max = select('#',...);
  local tab = {...};
  local cur = 1;
  while cur < max do
    local v = tab[cur];
    __fields__[v] = true;
    ret[v] = tab[cur+1];
    cur = cur + 2
  end
  return setmetatable(ret, _hx_anon_mt)
end

local function _hx_e()
  return setmetatable({__fields__ = {}}, _hx_anon_mt)
end

local function _hx_o(obj)
  return setmetatable(obj, _hx_anon_mt)
end

local function _hx_new(prototype)
  return setmetatable({__fields__ = {}}, {__newindex=_hx_anon_newindex, __index=prototype})
end

local _hxClasses = {}
local Int = _hx_e();
local Dynamic = _hx_e();
local Float = _hx_e();
local Bool = _hx_e();
local Class = _hx_e();
local Enum = _hx_e();

local Array = _hx_e()
__lua_lib_luautf8_Utf8 = _G.require("lua-utf8")
local Main = _hx_e()
local Math = _hx_e()
local String = _hx_e()
local Std = _hx_e()
__haxe_Log = _hx_e()
__lua_Boot = _hx_e()

local _hx_bind, _hx_bit, _hx_staticToInstance, _hx_funcToField, _hx_maxn, _hx_print, _hx_apply_self, _hx_box_mr, _hx_bit_clamp, _hx_table, _hx_bit_raw
local _hx_pcall_default = {};
local _hx_pcall_break = {};

Array.new = function() 
  local self = _hx_new(Array.prototype)
  Array.super(self)
  return self
end
Array.super = function(self) 
  _hx_tab_array(self, 0);
end
Array.prototype = _hx_a();
Array.prototype.concat = function(self,a) 
  local _g = _hx_tab_array({}, 0);
  local _g1 = 0;
  local _g2 = self;
  while (_g1 < _g2.length) do 
    local i = _g2[_g1];
    _g1 = _g1 + 1;
    _g:push(i);
  end;
  local ret = _g;
  local _g3 = 0;
  while (_g3 < a.length) do 
    local i1 = a[_g3];
    _g3 = _g3 + 1;
    ret:push(i1);
  end;
  do return ret end
end
Array.prototype.join = function(self,sep) 
  local tbl = ({});
  local _gthis = self;
  local cur_length = 0;
  local i = _hx_o({__fields__={hasNext=true,next=true},hasNext=function(self) 
    do return cur_length < _gthis.length end;
  end,next=function(self) 
    cur_length = cur_length + 1;
    do return _gthis[cur_length - 1] end;
  end});
  while (i:hasNext()) do 
    local i1 = i:next();
    _G.table.insert(tbl, Std.string(i1));
  end;
  do return _G.table.concat(tbl, sep) end
end
Array.prototype.pop = function(self) 
  if (self.length == 0) then 
    do return nil end;
  end;
  local ret = self[self.length - 1];
  self[self.length - 1] = nil;
  self.length = self.length - 1;
  do return ret end
end
Array.prototype.push = function(self,x) 
  self[self.length] = x;
  do return self.length end
end
Array.prototype.reverse = function(self) 
  local tmp;
  local i = 0;
  while (i < Std.int(self.length / 2)) do 
    tmp = self[i];
    self[i] = self[(self.length - i) - 1];
    self[(self.length - i) - 1] = tmp;
    i = i + 1;
  end;
end
Array.prototype.shift = function(self) 
  if (self.length == 0) then 
    do return nil end;
  end;
  local ret = self[0];
  if (self.length == 1) then 
    self[0] = nil;
  else
    if (self.length > 1) then 
      self[0] = self[1];
      _G.table.remove(self, 1);
    end;
  end;
  local tmp = self;
  tmp.length = tmp.length - 1;
  do return ret end
end
Array.prototype.slice = function(self,pos,_end) 
  if ((_end == nil) or (_end > self.length)) then 
    _end = self.length;
  else
    if (_end < 0) then 
      _end = _G.math.fmod((self.length - (_G.math.fmod(-_end, self.length))), self.length);
    end;
  end;
  if (pos < 0) then 
    pos = _G.math.fmod((self.length - (_G.math.fmod(-pos, self.length))), self.length);
  end;
  if ((pos > _end) or (pos > self.length)) then 
    do return _hx_tab_array({}, 0) end;
  end;
  local ret = _hx_tab_array({}, 0);
  local _g = pos;
  local _g1 = _end;
  while (_g < _g1) do 
    _g = _g + 1;
    local i = _g - 1;
    ret:push(self[i]);
  end;
  do return ret end
end
Array.prototype.sort = function(self,f) 
  local i = 0;
  local l = self.length;
  while (i < l) do 
    local swap = false;
    local j = 0;
    local max = (l - i) - 1;
    while (j < max) do 
      if (f(self[j], self[j + 1]) > 0) then 
        local tmp = self[j + 1];
        self[j + 1] = self[j];
        self[j] = tmp;
        swap = true;
      end;
      j = j + 1;
    end;
    if (not swap) then 
      break;
    end;
    i = i + 1;
  end;
end
Array.prototype.splice = function(self,pos,len) 
  if ((len < 0) or (pos > self.length)) then 
    do return _hx_tab_array({}, 0) end;
  else
    if (pos < 0) then 
      pos = self.length - (_G.math.fmod(-pos, self.length));
    end;
  end;
  len = Math.min(len, self.length - pos);
  local ret = _hx_tab_array({}, 0);
  local _g = pos;
  local _g1 = pos + len;
  while (_g < _g1) do 
    _g = _g + 1;
    local i = _g - 1;
    ret:push(self[i]);
    self[i] = self[i + len];
  end;
  local _g2 = pos + len;
  local _g3 = self.length;
  while (_g2 < _g3) do 
    _g2 = _g2 + 1;
    local i1 = _g2 - 1;
    self[i1] = self[i1 + len];
  end;
  local tmp = self;
  tmp.length = tmp.length - len;
  do return ret end
end
Array.prototype.toString = function(self) 
  local tbl = ({});
  _G.table.insert(tbl, "[");
  _G.table.insert(tbl, self:join(","));
  _G.table.insert(tbl, "]");
  do return _G.table.concat(tbl, "") end
end
Array.prototype.unshift = function(self,x) 
  local len = self.length;
  local _g = 0;
  local _g1 = len;
  while (_g < _g1) do 
    _g = _g + 1;
    local i = _g - 1;
    self[len - i] = self[(len - i) - 1];
  end;
  self[0] = x;
end
Array.prototype.insert = function(self,pos,x) 
  if (pos > self.length) then 
    pos = self.length;
  end;
  if (pos < 0) then 
    pos = self.length + pos;
    if (pos < 0) then 
      pos = 0;
    end;
  end;
  local cur_len = self.length;
  while (cur_len > pos) do 
    self[cur_len] = self[cur_len - 1];
    cur_len = cur_len - 1;
  end;
  self[pos] = x;
end
Array.prototype.remove = function(self,x) 
  local _g = 0;
  local _g1 = self.length;
  while (_g < _g1) do 
    _g = _g + 1;
    local i = _g - 1;
    if (self[i] == x) then 
      local _g2 = i;
      local _g11 = self.length - 1;
      while (_g2 < _g11) do 
        _g2 = _g2 + 1;
        local j = _g2 - 1;
        self[j] = self[j + 1];
      end;
      self[self.length - 1] = nil;
      self.length = self.length - 1;
      do return true end;
    end;
  end;
  do return false end
end
Array.prototype.indexOf = function(self,x,fromIndex) 
  local _end = self.length;
  if (fromIndex == nil) then 
    fromIndex = 0;
  else
    if (fromIndex < 0) then 
      fromIndex = self.length + fromIndex;
      if (fromIndex < 0) then 
        fromIndex = 0;
      end;
    end;
  end;
  local _g = fromIndex;
  local _g1 = _end;
  while (_g < _g1) do 
    _g = _g + 1;
    local i = _g - 1;
    if (x == self[i]) then 
      do return i end;
    end;
  end;
  do return -1 end
end
Array.prototype.lastIndexOf = function(self,x,fromIndex) 
  if ((fromIndex == nil) or (fromIndex >= self.length)) then 
    fromIndex = self.length - 1;
  else
    if (fromIndex < 0) then 
      fromIndex = self.length + fromIndex;
      if (fromIndex < 0) then 
        do return -1 end;
      end;
    end;
  end;
  local i = fromIndex;
  while (i >= 0) do 
    if (self[i] == x) then 
      do return i end;
    else
      i = i - 1;
    end;
  end;
  do return -1 end
end
Array.prototype.copy = function(self) 
  local _g = _hx_tab_array({}, 0);
  local _g1 = 0;
  local _g2 = self;
  while (_g1 < _g2.length) do 
    local i = _g2[_g1];
    _g1 = _g1 + 1;
    _g:push(i);
  end;
  do return _g end
end
Array.prototype.map = function(self,f) 
  local _g = _hx_tab_array({}, 0);
  local _g1 = 0;
  local _g2 = self;
  while (_g1 < _g2.length) do 
    local i = _g2[_g1];
    _g1 = _g1 + 1;
    _g:push(f(i));
  end;
  do return _g end
end
Array.prototype.filter = function(self,f) 
  local _g = _hx_tab_array({}, 0);
  local _g1 = 0;
  local _g2 = self;
  while (_g1 < _g2.length) do 
    local i = _g2[_g1];
    _g1 = _g1 + 1;
    if (f(i)) then 
      _g:push(i);
    end;
  end;
  do return _g end
end
Array.prototype.iterator = function(self) 
  local _gthis = self;
  local cur_length = 0;
  do return _hx_o({__fields__={hasNext=true,next=true},hasNext=function(self) 
    do return cur_length < _gthis.length end;
  end,next=function(self) 
    cur_length = cur_length + 1;
    do return _gthis[cur_length - 1] end;
  end}) end
end
Array.prototype.resize = function(self,len) 
  if (self.length < len) then 
    self.length = len;
  else
    if (self.length > len) then 
      local _g = len;
      local _g1 = self.length;
      while (_g < _g1) do 
        _g = _g + 1;
        local i = _g - 1;
        self[i] = nil;
      end;
      self.length = len;
    end;
  end;
end

Main.new = {}
Main.main = function() 
  __haxe_Log.trace("hello world", _hx_o({__fields__={fileName=true,lineNumber=true,className=true,methodName=true},fileName="Main.hx",lineNumber=3,className="Main",methodName="main"}));
end

Math.new = {}
Math.isNaN = function(f) 
  do return f ~= f end;
end
Math.isFinite = function(f) 
  if (f > -_G.math.huge) then 
    do return f < _G.math.huge end;
  else
    do return false end;
  end;
end
Math.min = function(a,b) 
  if (Math.isNaN(a) or Math.isNaN(b)) then 
    do return (0/0) end;
  else
    do return _G.math.min(a, b) end;
  end;
end

String.new = function(string) 
  local self = _hx_new(String.prototype)
  String.super(self,string)
  self = string
  return self
end
String.super = function(self,string) 
end
String.__index = function(s,k) 
  if (k == "length") then 
    do return __lua_lib_luautf8_Utf8.len(s) end;
  else
    local o = String.prototype;
    local field = k;
    if ((function() 
      local _hx_1
      if ((_G.type(o) == "string") and ((String.prototype[field] ~= nil) or (field == "length"))) then 
      _hx_1 = true; elseif (o.__fields__ ~= nil) then 
      _hx_1 = o.__fields__[field] ~= nil; else 
      _hx_1 = o[field] ~= nil; end
      return _hx_1
    end )()) then 
      do return String.prototype[k] end;
    else
      if (String.__oldindex ~= nil) then 
        if (_G.type(String.__oldindex) == "function") then 
          do return String.__oldindex(s, k) end;
        else
          if (_G.type(String.__oldindex) == "table") then 
            do return String.__oldindex[k] end;
          end;
        end;
        do return nil end;
      else
        do return nil end;
      end;
    end;
  end;
end
String.fromCharCode = function(code) 
  do return __lua_lib_luautf8_Utf8.char(code) end;
end
String.prototype = _hx_a();
String.prototype.toUpperCase = function(self) 
  do return __lua_lib_luautf8_Utf8.upper(self) end
end
String.prototype.toLowerCase = function(self) 
  do return __lua_lib_luautf8_Utf8.lower(self) end
end
String.prototype.indexOf = function(self,str,startIndex) 
  if (startIndex == nil) then 
    startIndex = 1;
  else
    startIndex = startIndex + 1;
  end;
  local r = __lua_lib_luautf8_Utf8.find(self, str, startIndex, true);
  if ((r ~= nil) and (r > 0)) then 
    do return r - 1 end;
  else
    do return -1 end;
  end;
end
String.prototype.lastIndexOf = function(self,str,startIndex) 
  local i = 0;
  local ret = -1;
  if (startIndex == nil) then 
    startIndex = __lua_lib_luautf8_Utf8.len(self);
  end;
  while (true) do 
    local startIndex1 = ret + 1;
    if (startIndex1 == nil) then 
      startIndex1 = 1;
    else
      startIndex1 = startIndex1 + 1;
    end;
    local r = __lua_lib_luautf8_Utf8.find(self, str, startIndex1, true);
    local p = (function() 
      local _hx_1
      if ((r ~= nil) and (r > 0)) then 
      _hx_1 = r - 1; else 
      _hx_1 = -1; end
      return _hx_1
    end )();
    if ((p == -1) or (p > startIndex)) then 
      break;
    end;
    ret = p;
  end;
  do return ret end
end
String.prototype.split = function(self,delimiter) 
  local idx = 1;
  local ret = _hx_tab_array({}, 0);
  local delim_offset = (function() 
    local _hx_1
    if (__lua_lib_luautf8_Utf8.len(delimiter) > 0) then 
    _hx_1 = __lua_lib_luautf8_Utf8.len(delimiter); else 
    _hx_1 = 1; end
    return _hx_1
  end )();
  while (idx ~= nil) do 
    local newidx = 0;
    if (__lua_lib_luautf8_Utf8.len(delimiter) > 0) then 
      newidx = __lua_lib_luautf8_Utf8.find(self, delimiter, idx, true);
    else
      if (idx >= __lua_lib_luautf8_Utf8.len(self)) then 
        newidx = nil;
      else
        newidx = idx + 1;
      end;
    end;
    if (newidx ~= nil) then 
      local match = __lua_lib_luautf8_Utf8.sub(self, idx, newidx - 1);
      ret:push(match);
      idx = newidx + __lua_lib_luautf8_Utf8.len(delimiter);
    else
      ret:push(__lua_lib_luautf8_Utf8.sub(self, idx, __lua_lib_luautf8_Utf8.len(self)));
      idx = nil;
    end;
  end;
  do return ret end
end
String.prototype.toString = function(self) 
  do return self end
end
String.prototype.substring = function(self,startIndex,endIndex) 
  if (endIndex == nil) then 
    endIndex = __lua_lib_luautf8_Utf8.len(self);
  end;
  if (endIndex < 0) then 
    endIndex = 0;
  end;
  if (startIndex < 0) then 
    startIndex = 0;
  end;
  if (endIndex < startIndex) then 
    do return __lua_lib_luautf8_Utf8.sub(self, endIndex + 1, startIndex) end;
  else
    do return __lua_lib_luautf8_Utf8.sub(self, startIndex + 1, endIndex) end;
  end;
end
String.prototype.charAt = function(self,index) 
  do return __lua_lib_luautf8_Utf8.sub(self, index + 1, index + 1) end
end
String.prototype.charCodeAt = function(self,index) 
  do return __lua_lib_luautf8_Utf8.byte(self, index + 1) end
end
String.prototype.substr = function(self,pos,len) 
  if ((len == nil) or (len > (pos + __lua_lib_luautf8_Utf8.len(self)))) then 
    len = __lua_lib_luautf8_Utf8.len(self);
  else
    if (len < 0) then 
      len = __lua_lib_luautf8_Utf8.len(self) + len;
    end;
  end;
  if (pos < 0) then 
    pos = __lua_lib_luautf8_Utf8.len(self) + pos;
  end;
  if (pos < 0) then 
    pos = 0;
  end;
  do return __lua_lib_luautf8_Utf8.sub(self, pos + 1, pos + len) end
end

Std.new = {}
Std.string = function(s) 
  do return __lua_Boot.__string_rec(s) end;
end
Std.int = function(x) 
  if (not Math.isFinite(x) or Math.isNaN(x)) then 
    do return 0 end;
  else
    do return _hx_bit_clamp(x) end;
  end;
end

__haxe_Log.new = {}
__haxe_Log.formatOutput = function(v,infos) 
  local str = Std.string(v);
  if (infos == nil) then 
    do return str end;
  end;
  local pstr = Std.string(Std.string(infos.fileName) .. Std.string(":")) .. Std.string(infos.lineNumber);
  if (infos.customParams ~= nil) then 
    local _g = 0;
    local _g1 = infos.customParams;
    while (_g < _g1.length) do 
      local v1 = _g1[_g];
      _g = _g + 1;
      str = Std.string(str) .. Std.string((Std.string(", ") .. Std.string(Std.string(v1))));
    end;
  end;
  do return Std.string(Std.string(pstr) .. Std.string(": ")) .. Std.string(str) end;
end
__haxe_Log.trace = function(v,infos) 
  local str = __haxe_Log.formatOutput(v, infos);
  _hx_print(str);
end

__lua_Boot.new = {}
__lua_Boot.isArray = function(o) 
  if (_G.type(o) == "table") then 
    if ((o.__enum__ == nil) and (_G.getmetatable(o) ~= nil)) then 
      do return _G.getmetatable(o).__index == Array.prototype end;
    else
      do return false end;
    end;
  else
    do return false end;
  end;
end
__lua_Boot.printEnum = function(o,s) 
  if (o.length == 2) then 
    do return o[0] end;
  else
    local str = Std.string(Std.string(o[0])) .. Std.string("(");
    s = Std.string(s) .. Std.string("\t");
    local _g = 2;
    local _g1 = o.length;
    while (_g < _g1) do 
      _g = _g + 1;
      local i = _g - 1;
      if (i ~= 2) then 
        str = Std.string(str) .. Std.string((Std.string(",") .. Std.string(__lua_Boot.__string_rec(o[i], s))));
      else
        str = Std.string(str) .. Std.string(__lua_Boot.__string_rec(o[i], s));
      end;
    end;
    do return Std.string(str) .. Std.string(")") end;
  end;
end
__lua_Boot.printClassRec = function(c,result,s) 
  if (result == nil) then 
    result = "";
  end;
  local f = __lua_Boot.__string_rec;
  for k,v in pairs(c) do if result ~= '' then result = result .. ', ' end result = result .. k .. ':' .. f(v, s.. '	') end;
  do return result end;
end
__lua_Boot.__string_rec = function(o,s) 
  if (s == nil) then 
    s = "";
  end;
  if (__lua_lib_luautf8_Utf8.len(s) >= 5) then 
    do return "<...>" end;
  end;
  local _g = type(o);
  if (_g) == "boolean" then 
    do return tostring(o) end;
  elseif (_g) == "function" then 
    do return "<function>" end;
  elseif (_g) == "nil" then 
    do return "null" end;
  elseif (_g) == "number" then 
    if (o == _G.math.huge) then 
      do return "Infinity" end;
    else
      if (o == -_G.math.huge) then 
        do return "-Infinity" end;
      else
        if (o == 0) then 
          do return "0" end;
        else
          if (o ~= o) then 
            do return "NaN" end;
          else
            do return tostring(o) end;
          end;
        end;
      end;
    end;
  elseif (_g) == "string" then 
    do return o end;
  elseif (_g) == "table" then 
    if (o.__enum__ ~= nil) then 
      do return __lua_Boot.printEnum(o, s) end;
    else
      if ((_hx_wrap_if_string_field(o,'toString') ~= nil) and not __lua_Boot.isArray(o)) then 
        do return _hx_wrap_if_string_field(o,'toString')(o) end;
      else
        if (__lua_Boot.isArray(o)) then 
          local o2 = o;
          if (__lua_lib_luautf8_Utf8.len(s) > 5) then 
            do return "[...]" end;
          else
            local _g1 = _hx_tab_array({}, 0);
            local _g11 = 0;
            while (_g11 < o2.length) do 
              local i = o2[_g11];
              _g11 = _g11 + 1;
              _g1:push(__lua_Boot.__string_rec(i, Std.string(s) .. Std.string(1)));
            end;
            do return Std.string(Std.string("[") .. Std.string(_g1:join(","))) .. Std.string("]") end;
          end;
        else
          if (o.__class__ ~= nil) then 
            do return Std.string(Std.string("{") .. Std.string(__lua_Boot.printClassRec(o, "", Std.string(s) .. Std.string("\t")))) .. Std.string("}") end;
          else
            local fields = __lua_Boot.fieldIterator(o);
            local buffer = ({});
            local first = true;
            _G.table.insert(buffer, "{ ");
            local f = fields;
            while (f:hasNext()) do 
              local f1 = f:next();
              if (first) then 
                first = false;
              else
                _G.table.insert(buffer, ", ");
              end;
              _G.table.insert(buffer, Std.string(Std.string(Std.string("") .. Std.string(Std.string(f1))) .. Std.string(" : ")) .. Std.string(__lua_Boot.__string_rec(o[f1], Std.string(s) .. Std.string("\t"))));
            end;
            _G.table.insert(buffer, " }");
            do return _G.table.concat(buffer, "") end;
          end;
        end;
      end;
    end;
  elseif (_g) == "thread" then 
    do return "<thread>" end;
  elseif (_g) == "userdata" then 
    local mt = _G.getmetatable(o);
    if ((mt ~= nil) and (mt.__tostring ~= nil)) then 
      do return _G.tostring(o) end;
    else
      do return "<userdata>" end;
    end;else
  _G.error("Unknown Lua type",0); end;
end
__lua_Boot.fieldIterator = function(o) 
  if (_G.type(o) ~= "table") then 
    do return _hx_o({__fields__={next=true,hasNext=true},next=function(self) 
      do return nil end;
    end,hasNext=function(self) 
      do return false end;
    end}) end;
  end;
  local tbl = (function() 
    local _hx_1
    if (o.__fields__ ~= nil) then 
    _hx_1 = o.__fields__; else 
    _hx_1 = o; end
    return _hx_1
  end )();
  local cur = _G.pairs(tbl);
  local next_valid = function(tbl1,val) 
    while (__lua_Boot.hiddenFields[val] ~= nil) do 
      val = cur(tbl1, val);
    end;
    do return val end;
  end;
  local cur_val = next_valid(tbl, cur(tbl, nil));
  do return _hx_o({__fields__={next=true,hasNext=true},next=function(self) 
    local ret = cur_val;
    cur_val = next_valid(tbl, cur(tbl, cur_val));
    do return ret end;
  end,hasNext=function(self) 
    do return cur_val ~= nil end;
  end}) end;
end
_hx_bit_clamp = function(v)
  if v <= 2147483647 and v >= -2147483648 then
    if v > 0 then return _G.math.floor(v)
    else return _G.math.ceil(v)
    end
  end
  if v > 2251798999999999 then v = v*2 end;
  if (v ~= v or math.abs(v) == _G.math.huge) then return nil end
  return _hx_bit.band(v, 2147483647 ) - math.abs(_hx_bit.band(v, 2147483648))
end

-- require this for lua 5.1
pcall(require, 'bit')
if bit then
  _hx_bit = bit
else
  local _hx_bit_raw = _G.require('bit32')
  _hx_bit = setmetatable({}, { __index = _hx_bit_raw });
  -- lua 5.2 weirdness
  _hx_bit.bnot = function(...) return _hx_bit_clamp(_hx_bit_raw.bnot(...)) end;
  _hx_bit.bxor = function(...) return _hx_bit_clamp(_hx_bit_raw.bxor(...)) end;
end

_hx_array_mt.__index = Array.prototype

local _hx_static_init = function()
  __lua_Boot.hiddenFields = {__id__=true, hx__closures=true, super=true, prototype=true, __fields__=true, __ifields__=true, __class__=true, __properties__=true}
  
end

_hx_print = print or (function() end)

_hx_wrap_if_string_field = function(o, fld)
  if _G.type(o) == 'string' then
    if fld == 'length' then
      return _G.string.len(o)
    else
      return String.prototype[fld]
    end
  else
    return o[fld]
  end
end

_hx_static_init();
Main.main()

0
похоже на реализацию некоторых функций, которых нет (или якобы нет) в Lua

в JavaScript похожая штука с полифиллами и библиотеками — но Hello World там пишется намного чище

пожалуй, наиболее близкая аналогия — Kotlin, еще один траспайлерный язык, который при переводе в JavaScript добавляет еще свой рантайм — несмертельно большой, но видимый

тут надо смотреть на рабочих проектах и вообще надо смотреть — новые функции это хорошо или плохо?
0
Да, часто языки, имеющие таргетами другие языки, тащат за собой рантайм и std-либу, которые могут весить очень много. Когда-то давно смотрел, что scala-js выдавала helloworld на несколько мегов.
В случае Haxe, ему приходится обеспечивать одинаковую работу строк, массивов, трейсов и прочего на всем заопарке целевых платформ (а заопарк впечатляющий).
Поэтому рантайм в пару десятков кб – довольно скромно. Это не множитель к размеру, а слагаемое. На helloworld-ах его вклад, конечно, наиболее заметен.
У Haxe в отличие от многих транспайлеров есть отличный dce, который вычищает почти весь неиспользуемый код, поэтому в результат попадает лишь необходимый минимум стандартной библиотеки.
0

Вот почему у меня Haxe не начался. Во-первых, почему-то основная среда разработки кросс-платформенного языка Windows-only. Во-вторых, на Linux нельзя поставить решение "из коробки" из репозитория. Захотел я попробовать Haxe, а из репозиториев можно только вим с плагином поставить. В-третьих, при заходе на Discord для получения помощи надо пройти регистрацию. К тому же сам дискорд не всем нравится (почему бы не сделать транспорт из IRC или matrix). В-четвертых, почему-то качество туториалов довольно низкое. Вот, к примеру, введение.


Вроде бы это всё и мелочи, а желание разбираться с Haxe и разработкой игр не нём пропало.

+1
Что такое «основная среда», и о какой среде речь? Выше в ветке были названы три распространенных варианта, два из которых кроссплатформенные. Этак и до плюсов докапаться можно из-за студии. Какое вообще отношение язык имеет к дистрибьюции VSCode или Intellij IDEA?
Документация по самому языку довольно неплохо написано, много хороших и интересных примеров можно найти в разделе cookbook.
Что до стартовых туториалов, особенно в контексте разработки игр – с haxe слишком много вариантов того, как начать, и в какую сторону двигаться. Гида по этим вариантам, действиетльно, не хватает. А сами туториалы есть не только у языка, но и у игровых движков; для старта может оказаться полезным смотреть на них. Каналов для общения хватает: есть и официальны форум, гитхаб, сообщества игровых движков. В русскоязычном сегменте есть скайп и телеграм-чаты.
Чтобы было более понятна ситуация приведу пример с шарпом, на котором тоже можно делать игры. Делать можно на юнити или на моногейм, а Introduction to the C#с MSDN не слишком поможет стартануть.
0
Что такое «основная среда», и о какой среде речь?

Я про Haxedevelop.


Этак и до плюсов докапаться можно из-за студии. Какое вообще отношение язык имеет к дистрибьюции VSCode или Intellij IDEA?

Самое прямое — чем легче начать использовать язык или фреймворк, тем больше вероятность его распространения. Чем легче и интереснее туториалы, тем выше вероятность того, что языком человек заинтересуется. Взять, к примеру, godot-engine. В его туториалах с первых же шагов делают игру! Чтобы начать им пользоваться, надо просто скачать и распаковать бинарник. Я сам с удовольствием прошёл этот туториал. А в Haxe сначала надо выбрать среду разработки (я не хочу устанавливать на личном компьютере софт не из репозиториев), потом выбрать движок, потом учиться на мануалах, а не на туториалах. И вот даже выбрал я HaxeFlixel, открываю туториал, а там говорится, что надо установить FlashDevelop, а он Windows-only.


Что до стартовых туториалов, особенно в контексте разработки игр – с haxe слишком много вариантов того, как начать, и в какую сторону двигаться. Гида по этим вариантам, действиетльно, не хватает.

Вот мне не удалось даже начать, при этом с Godot начать удалось, с libsdl тоже, а вот с Haxe оказалось сложнее.

+1

Для различных дистрибутивов Linux есть пакеты в официальных репозиториях дистрибутивов: https://haxe.org/download/linux/ — Ubuntu, Debian, CentOS, OpenSUSE, Arch. Даже для Fedora есть.


В качестве основной IDE для Haxe сейчас использую VSCode, и хаксовый плагин там в отличном состоянии. Работает на Windows, Linux, OSX.


В документации действительно есть пробелы, хотя в последнее время ситуация постепенно улучшается.
Но раз уж вы упомянули, что хотели в геймдев, то в таком случае стоит скорее обращать внимание на документацию фреймворков.
Вот, к примеру, Heaps (который в Dead Cells используется): https://heaps.io/documentation/home.html
Вот OpenFL (использовался в Papers Please): https://books.openfl.org/openfl-developers-guide/
HaxeFlixel: https://haxeflixel.com/documentation/
Вполне подробные доки.


Что касается Discord, то это уже вопрос вкуса. К любым каналам общения у кого-нибудь находятся претензии. Тут, к сожалению, всем не угодишь. Сейчас ещё появился Discourse: https://community.haxe.org/

0

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


Взять тот же heaps, смотрим его туториал Hello World. Сначала создать xml-конфиг, добавить текст программы, потом создать build task в vscode (что делать пользователям других IDE?) — уже на этом этапе часть пользователей подумает, что фреймворк излишне запутанный (не сложный). В нормальных случаях для того, чтобы запустить Hello World, надо выбрать соответствующий пример из базы примеров и нажать 'Run'.


Я уверен, что Haxe это сочетание отличной идеи и отличной реализации, только вот быть хорошим продуктом недостаточно, необходимы еще, как минимум, хорошие туториалы и низкий порог вхождения (потому что у конкурентов он достаточно низкий).

Only those users with full accounts are able to leave comments. , please.