1

Тема: Static typed QLua?

У [Q]Lua есть несколько темных сторон, которые почему-то практически не обсуждаются в рунете.
Хочу их тут осветить. А также обсудить, как с ними бороться.

Недостатки [Q]Lua:
1. Lua - довольно низкоуровневый язык, поэтому часто приходится изобретать велосипеды.  Многие сторонние библиотеки либо дублируют функционал, либо несовместимы (примеры - реализация ООП, функции для работы со строками, регулярными выражениями, таблицами (map, reduce, etc.)).
2. по-умолчанию переменные - глобальные.
3. слишком минималистичные структуры данных - tables, которые как бы заменяют и массивы и структуры (record) и хеш-таблицы, но не на 100%. Известные багофичи - массивы с отрицательными/дробными индексами, с пропусками в нумерации.
4. динамическая типизация, с одной стороны, упрощает программирование, а с другой - ошибки с неправильным типом переменной или опечаткой в названии поля ловятся только во время выполнения скрипта, что для торговых алгоритмов чревато серьезными последствиями. Неоднозначная логика true|anytype/false|nil может давать побочные эффекты в выражениях x and y or z.  Раз уж ввели тип boolean, следовало ограничить тип выражений в if, while только этим типом.

  Для небольших разовых скриптов это не критично, но для предметной области QLua создает эффект разложенных вокруг граблей. Сюда же добавляются специфические проблемы Qlua/Quik:

5. Lua хорош как конструктор при наличии исходных кодов, когда автор программы может добавить любую С-библиотеку.  Но с квиком ситуация другая - исходный код Qlua закрыт, разработчики решили свои проблемы - выставили API Quik в Qlua, а остальное - проблемы пользователей.

6. как следствие - сторонние модули lua c dll, не работают без пересборки, нет дебаггера ну и с тестированием скриптов есть проблемы.  Без вспомогательных библиотек наподобие QL сделать элементарные вещи - сформировать/выставить/передвинуть заявку, проверить её исполнение/частичное исполнение/снятие - нетривиальная задача.

Что делать?
Гораздо лучше для всех было, если бы в квике использовалась стандартная lua dll, а qlua api было реализовано как preloaded lua модуль при инициализации интерпретатора. Да и без странного 2-поточного интерпретатора можно было обойтись. Лично я склоняюсь к мысли, что Lua в качестве языка для торгового терминала - не слишком удачный выбор. Гораздо лучше бы тут подошел какой-нибудь static typed скриптовый язык, который отлавливает большинство ошибок и опечаток во время компиляции. Из того, что я смотрел, мне понравились Angelscript, Pike, Dao.

Что можно сделать здесь и сейчас с QLua?
Вот что я насобирал на http://lua-users.org/wiki и в интернете:

1. LuaLint (название раздела в wiki)- проводит статистический анализ глобальных переменных в скриптах lua. Сообщает о всех обращениях к необъявленным глобальным переменным, которые часто появляются из-за опечаток в именах переменных
2. DetectingUndefinedVariables - примеры скриптов, которые делают то же самое в рантайме (выводят ошибку при обращении к необъявленной глобальной переменной).
3. StrictStructs - аналогичная проверка корректности имен полей в таблицах.
Я делал похожий скрипт, но более простой - цепляем к любой таблице мета-таблицу с функциями __newindex, __index выкидывающие ошибки и всё - при обращении к несуществующему полю таблицы тут же получаем номер строки с ошибкой, а не непонятный "nil value" совершенно в другом месте.
4. LuaTypeChecking - проверка типов в рантайме (assert/decorators).

5. Очень многообещающий проект typedlua на гитхабе. Насколько я понял, авторы из того же бразильского университета что Р.Иерусалимский. Идея такая же как в typescript/javascript - typedlua компилируется в lua со статическим анализом типов. Можно в отдельных файлах описывать дескрипторы и структуры lua и с-библиотек. Они используются для статического анализа вызовов функций и обращения к структурам данных. Например, есть дескрипторы для всех стандартных lua-библиотек.  Можно так же описать qlua API и qlua-таблицы!  В общем, может заменить все вышеперечисленные костыли.

p.s. не совсем по теме, но ещё один любопытный язык, компилируемый в lua - moonscript. Синтаксис напоминает python и функциональные языки.

2

Re: Static typed QLua?

Хороший разбор, обстоятельный очень!

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

Хотелось бы пару моментов уточнить, потому что они, на мой взгляд, не связаны с Lua/QLua как таковым.

reader пишет:

как следствие - сторонние модули lua c dll, не работают без пересборки

Это я не понял о чем. Могли бы вы уточнить подробнее?

reader пишет:

нет дебаггера

Есть ведь декода.

reader пишет:

ну и с тестированием скриптов есть проблемы

Вы имеете ввиду тестеры стратегий?

3

Re: Static typed QLua?

reader, занимательный пост.

Переформулированная фраза от admin:
На Lua пишут сценарии миллионы людей для различных приложений (и как-то не жалуются).

Сразу писать торговую программу (без знания языка и его особенностей) не разумно. Что вам мешает проверить критичные блоки на ошибки типизации?
Да, Lua требует внимания, приходится с этим мириться.
А от логических ошибок и отладчик не поправит и не подскажет в какой строке косяк закрался.

Без вспомогательных библиотек наподобие QL сделать элементарные вещи - сформировать/выставить/передвинуть заявку, проверить её исполнение/частичное исполнение/снятие - нетривиальная задача

Вот умора, какая там версия багфиксов у QL? Если вы считаете элементарные вещи нетривиальными, ну тогда ХЗ, рынок это не для вас, он сам по себе не тривиален.

admin: наезды скорректированы, впредь просьба писать аккуратнее; я делаю так: выдыхаю, закрываю топик, а через какое-то время возвращаюсь, получается продуктивнее, на мой взгляд smile

4

Re: Static typed QLua?

reader пишет:

3. StrictStructs - аналогичная проверка корректности имен полей в таблицах.
Я делал похожий скрипт, но более простой - цепляем к любой таблице мета-таблицу с функциями __newindex, __index выкидывающие ошибки и всё - при обращении к несуществующему полю таблицы тут же получаем номер строки с ошибкой, а не непонятный "nil value" совершенно в другом месте.

Пример можете привести?

5

Re: Static typed QLua?

По поводу QL и её пользы я бы сказал так: подобрать все нужные параметры для того, чтобы банально подать заявку - крайне нетривиальная вещь, тем более, что примеров ARQA практически не приводит. К тому же параметры зависят и рынка. Да, когда эти параметры раз подобрал - это становится просто, но первый раз... Хотя, вероятно, тут зависит от "бэкграунда": если ранее писали роботов для QUIK другими средствами автоматизации - то какие необходимо подставить параметры заявок и какие именно - много проще сообразить, конечно.

Но первый раз пробить это - довольно не просто для новичка (хотя казалоь бы, самая простая операция должна быть: подать заявку), и в этом смысле QL даёт нам готовый базис для этого, в который легко подсмотреть.


kalikazandr пишет:

Что вам мешает проверить критичные блоки на ошибки типизации?

Поделитесь, какую методику вы для этого используете? для меня тоже иногда бывает проблемой.
И тогда я вспоминаю про почти забытую ныне "венгерскую нотацию" - и начинаю массово её использовать в скриптах.

6

Re: Static typed QLua?

korovin пишет:

Это я не понял о чем. Могли бы вы уточнить подробнее?

Посмотрите соседние темы про визуальные библиотеки. Кроме VCLua ничего толком не работает. И та периодически ломается в новых версиях quik.

korovin пишет:

Есть ведь декода.

Честно говоря, не пробовал.  По отзывам на этом форуме с ней были проблемы в 13 году.  Для моих скриптов хватало message box и логов.  Проблема в поддержке lua в самом квике.  Кроме кнопки запуска нет ничего. Даже порядок скриптов в списке нельзя исправить. Пример нормальной реализации макроязыка - VBA в Excel. Есть и редактор и отладчик. Можно записать макрокоманду вручную а потом посмотреть как это реализуется программным кодом.
Тупо прилинковать lua к сишной программе и я могу (делал в 99 году простейший генератор отчетов с lua).

reader пишет:

Вы имеете ввиду тестеры стратегий?

Ну этого и сам квик не умеет.  А вот эмулировать выставление заявок в тестовом режиме было бы полезно.

7

Re: Static typed QLua?

korovin пишет:

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

Очень просто. Берете любую функцию из QLUA.CHM, вызываете ее и выводите результат в сообщении:
local res = funQLUA ()
message(type(res))
Смотрите, что получилось и приводите свои переменные к этому типу или наоборот.

8 (2015-10-28 11:35:49 отредактировано kalikazandr)

Re: Static typed QLua?

admin: наезды скорректированы, впредь просьба писать аккуратнее; я делаю так: выдыхаю, закрываю топик, а через какое-то время возвращаюсь, получается продуктивнее, на мой взгляд smile
Согласен, принял близко к сердцу))

9

Re: Static typed QLua?

admin: эмоциональное вступление и особо ударные места удалил.
не надо, горячие финские парни.
давайте по делу


kalikazandr пишет:

На Lua пишут сценарии миллионы людей для различных приложений (и как-то не жалуются).

Привираете.  Как считали? Всех пользователей WOW приплюсовали?
Lua не входит в топ-20 самых популярных языков по версии tiobe.  На 20 месте pascal c 1%.  Значит lua используют меньше 1% программистов.  Так что его популярность - ноль целых хрен десятых.  Можно посчитать по другому -
на конец 14 года на гитхабе активных проектов Lua - 8123. На luarocks - меньше 1000 проектов. Ну и чтобы два раза не вставать - не подскажете сколько вакансий программистов на Lua в мире и сколько за него платят з/п?

kalikazandr пишет:

Сразу писать торговую программу (без знания языка и его особенностей) не разумно. Что вам мешает проверить критичные блоки на ошибки типизации?
Да, Lua требует внимания, приходится с этим мириться.
А от логических ошибок и отладчик не поправит и не подскажет в какой строке косяк закрался.

С чего вы сделали такой вывод?
Я 20 лет себе на жизнь программированием зарабатываю. Работал с десятком языков программирования. Ещё пару десятков смотрел, пробовал из любопытства. Есть с чем сравнивать. С Lua знаком с 99 года с версии 4.0.  Как альтернатива bash, awk, perl, python в некоторых случаях годится. Как универсальный язык на все случаи жизни - однозначно нет.  Как раз мой пост - не жалобы на жизнь, а о том что с этим делать. Про логические ошибки ни слова не было.

p.s. adminу респект, оперативно модерирует.  Разозлил меня калеказандр, ну да ладно.  Больше не буду на его выпады отвечать.

admin: QLua - та данность, которая у нас есть.
предлагаю продолжать исключительно в русле "что нам с этим теперь делать, какие инструменты для облегчения жизни использовать", что и было задано первым постом.

10 (2015-10-28 13:26:41 отредактировано reader)

Re: Static typed QLua?

CyberTrader пишет:
reader пишет:

3. StrictStructs - аналогичная проверка корректности имен полей в таблицах.
Я делал похожий скрипт, но более простой - цепляем к любой таблице мета-таблицу с функциями __newindex, __index выкидывающие ошибки и всё - при обращении к несуществующему полю таблицы тут же получаем номер строки с ошибкой, а не непонятный "nil value" совершенно в другом месте.

Пример можете привести?

Легко. Сначала хотел назвать модуль struct или strict, но такие уже есть в lua, поэтому назвал collar (ошейник).
Описание функций:
match - сравнивает структуру(ключи) таблицы с эталоном с опциональной проверкой типов значений
update - обновляет содержимое таблицы из другой только для существующих ключей
merge  - обновляет содержимое таблицы из другой (update or insert)
mix - назвал так чтобы не было путаницы с конструкторами. По сути не создается новый объект, а меняются свойства существующей таблицы (set metatable).  В некоторых ООП это называется mix up.  Идеальный вариант для таблиц, возвращаемых qlua api. Метаметоды вызываются только в случае обращения к несуществующим в таблице полям, что в 99% случаев означает ошибку (опечатку).

-- collar.lua  usage:  collar = require("collar")
local collar={}

collar.pp = function (t)    -- pretty print table
    print(t,"{")
    for k,v in pairs(t) do
        print('',k,v)
    end
    print("}")
end

collar.match = function (t,etalon,type_check)
    -- keys etalon is subset of keys t
    type_check = type_check or false
    local x = 0
    for k,v in pairs(etalon) do
        x = rawget(t,k)
        if x == nil then
            return false
        end
        if type_check and type(x) ~= v then
            return false
        end
    end
    return true
end

collar.update = function (t,tt) -- update only existing keys
    local ttk = 0
    for k,v in pairs(t) do
        ttk = tt[k]
        if ttk and ttk ~= v then rawset(t,k,ttk) end
    end
end

collar.merge = function (t,tt) -- update or insert {keys=values}
    for k,v in pairs(tt) do
        rawset(t,k,v)
    end
end

local function _ni(t,k,v)
    error("Error __newindex: wrong field name '"..tostring(k).."'")
end

local function _in(t,k)
    error("Error __index: wrong field name '"..tostring(k).."'")
end

-- attach methods to metatable
collar.mix = function(t) return setmetatable(t,{__newindex=_ni, __index=collar, }) end
-- metatable for collar
setmetatable( collar, { __index=_in, })
return collar

Тест: collar_test.lua. Если раскомментировать строки помеченные -- typo, в них будет ошибка. Сравните с результатом без collar.

collar=require("collar")
collar.pp(collar)

local t={account=10000000000,client_id="APL"}
collar.mix(t)

collar.pp(t) -- same as t:pp()
print("collar.match:", collar.match( t, { account="number", client_id="string"})) -- true
print("collar.match(typed):", collar.match( t, { account="number", client_id="string", new_field="number"}, true)) -- false

--if t.acount then -- typo
if t.account then
   print( 'account:', t.account)
else
   print('wrong thing')
end

--t.client_id="A".. tostring(t.clinet_id) .. "E" -- typo
t.client_id="A".. tostring(t.client_id) .. "E"
collar.pp(t)

t:update {account=1234567890, client_id="GOOGLE", junk=false}
collar.pp(t)

t:merge {account=9876543210, junk=true, any='field'}
t:pp()

p.s. Тестировал в Lua.  В qlua не проверял. 
p.p.s. 2admin что-то у вас с раскраской кода не то.  Если в первой строке кода нет require с кавычкой - красит весь код коричневым.

admin: стоит модуль автоопределения языка для раскраски, не редко он, увы, ошибается; вероятно как-нибудь заменю на что-то другое.

11

Re: Static typed QLua?

Я себя вообще не считаю программистом, что не помешало мне за этот год, используя Qlua, заработать на жизнь даже своим праправнукам. Поэтому думайте себе там что хотите.

admin: остальное удалено.

12 (2015-10-28 13:55:31 отредактировано swerg)

Re: Static typed QLua?

CyberTrader пишет:
reader пишет:

3. StrictStructs - аналогичная проверка корректности имен полей в таблицах.
Я делал похожий скрипт, но более простой - цепляем к любой таблице мета-таблицу с функциями __newindex, __index выкидывающие ошибки и всё - при обращении к несуществующему полю таблицы тут же получаем номер строки с ошибкой, а не непонятный "nil value" совершенно в другом месте.

Пример можете привести?

Чисто для иллюстрации, можно сделать такой пример:

_test_meta = {}
_test_meta.__index =
    function (table, key)
        print("Invalid key '" .. tostring(key) .. "'")
    end

t = {"AA","BB","CC"}

setmetatable(t, _test_meta)

print(t[1])
print(t[88])

Причем setmetatable(наша_таблица, _test_meta) можно вызвать для любой (и для всех) таблиц в нашем скрипте, т.е. одной _test_meta достаточно на всё.

В результате такого скрипта получим:

AA                       <<====  значение t[1] = "AA"
Invalid key '88'         <<====  диагностика про обращение в несуществующему элементы в  t[88] 
nil                      <<====  результат выполнения print(t[88]), он никуда не делся

Можно в проверочную функцию добавить аварийную остановку скрипта при обнаружении проблем.

Я вот только не сумел придумать как напечатать имя таблицы, к которой было обращение,  а если бы еще номер строки - вообще супер.
Может кто подскажет?

13 (2015-10-28 17:52:29 отредактировано reader)

Re: Static typed QLua?

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

стандартная функция error(str) выдает трассировку стека с именами функций и номерами строк:

D:\Lua\5.1\lua.EXE: .\collar.lua:47: Error __index: wrong field name 'clinet_id'
stack traceback:
    [C]: in function 'error'
    .\collar.lua:47: in function <.\collar.lua:46>
    collar_test.lua:6: in main chunk
    [C]: ?

то же самое без завершения работы - print( debug.traceback())

14

Re: Static typed QLua?

Попалась на хабре статья, в ней автор ровно про тоже самое переживает. Там довольно многословно, говоря кратко, получаем следующее:

  • можно сделать свои обёрточки проверки типов аргументов и не забывать вызывать из в начале каждой функции (есть готовый код), но это же в run-time каждый раз будет выполняться!; sad

  • для таблиц - собственно те же метатаблицы прикручивать для контроля;

  • рассмотрены разные готовые библиотеки, но с ними надо разбираться, синтаксис с Metalua и "types"  получается и вовсе экзотическим для Lua, зато решаем задачу контроля типов (но опять в run-time?)

http://habrahabr.ru/post/76001/