Pull to refresh

Comments 120

Да, LUA — классная вещь. Когда-то в своём проекте мы использовали собственный небольшой язык. Но когда система комманд разраслась до десятков + добавилась необходимость хорошей математики и работы с внешней файловой системой решили перейти на что-то серьезное. Выбирали между Python и LUA. Выбрали LUA. Стыдно, правда, признаться почему — в комманде было несколько людей, активно игравших в WoW и писавших к нему плагины (как раз на LUA), а вот знатоков питона не было :)
А почему во внимание Angelscript не брали… имхо, гораздо лучше LUA
да, спасибо. Что-то задумался…
Для пользователей языка программирования D есть интерфейс с более человеческим лицом — LuaD

Вот пример использования:
import LuaD;
import tango.io.Stdout;

void main(char[][] args) {
    auto lua = new LuaState;

    lua["greet"] = (string name) {
        Stdout.format("Hello, {}!", name);
    };

    lua.doString(`greet("Terror")`);
}

Запускаем и видим «Hello, Terror!»
Я буду краток, но меток.
Автор — не мучай себя и других.
открой для себя luabind
быть может за те 4 года что я уже не работаю с луа придумали что-то иное, но…
… но я бы забил на луа и пересел на питон.
Статья обзорная, ознакомительная. Если будет интерес расскажу и про luabind и другие методы, упрощающие взаимодействие с Lua
Тут на вкус и цвет, конечно, но я использую LuaPlus. На мой неприхотливый взгляд он несколько удобнее по получаемому коду, чем luabind. Да и пришел я к нему после того как собственную обертку написал по всем заветам Саттера и Александреску.

Но, в любом случае, C++ и LUA вместе — это здорово!
Luabind, ИМХО, зло.

Если пишешь биндинги под себя, используй стандартный Lua C API. Если им проникнуться, лучшего средства нет.

Если нужны биндинги для какой-нибудь монструозной сторонней библиотеки, используй генератор биндингов (например tolua).
В принципе я использовал луабинд по минимуму.
Ибо он( и гиганский кусок буста ему потребный) замедлял компиляцию в десятки, а то и в сотни раз.
Вот я примерно про это и говорю. Рантайм оверхед тоже присутствует.
UFO landed and left these words here
Прям до стека дошли?
Почему не понравилось?
UFO landed and left these words here
1/13 от скорости сишника для JIT варианта lua.
Это я просто цифры привел. Это впечатляет.

Кстати питон + psyco дал 1/14. Вплотную приблизился.
А давно мерял скорость. Но там пример какую-то энтропию накручивал, не матесатическую задачу, подобрал примерное отношение управл. конструкций, как и в обычном софте.
Просто если посмотреть shootout.alioth.debian.org то Lua много где показывает себя с хорошей стороны.
У всех языков свои сильные/слабые стороны, и суть в том чтобы грамотно заиспользовать только все плюсы :)
И здесь как нельзя кстати возможности встраиваемости одного языка в другой.
Это Ваше личное мнение. Такое ощущение, что речь всё ещё про Луа 4.х. :-)

Моё личное мнение — более изящного, «некорявого», а, главное, сбалансированного языка чем Луа 5.1 я не встречал.

Ошибки скриптинга отлавливаются шикарно. Нужно просто уметь их ловить. Могу ответить на конкретные вопросы.

Бридж к ObjectiveC к Луа как к языку не имеет никакого отношения вообще. Чистый Луа предоставляет механизм для биндинга в plain C (и, на правах бедного родственника, в C++).

Всё, что сверх этого — надстройки, которые часто пишутся обычно для удовлетворения частных нужд разработчика.

Да, есть приличные бриджи (либо альтернативные реализации VM) в .Net, в Java, в Perl. Кое-какой бридж в Active script.

Если бридж ObjectiveC тёк, это — проблема бриджа а не языка. Можно написать свой.
с какими такими счетчиками ссылок?
UFO landed and left these words here
а… весьма ожидаемый результат…
UFO landed and left these words here
UFO landed and left these words here
мутная = отсутствующая?

можно о мелочах?

начало с единички?
UFO landed and left these words here
Пункты 1 и 2 — вкусовщина ИМХО. У меня лично никогда серьёзных проблем ни с тем ни с другим не было, всё шикарно обходится.

Пункт 3 — неправда. Луашные таблицы и есть массивы (и, одновременно, хеш-таблицы). Даже на низком уровне — то есть без пенальти по скорости. Наличие выделенного типа «массив» никаких бенефитов не даёт.
UFO landed and left these words here
1 — В своей практике серьёзных проблем не встречал. Вопрос в том, чтобы писать на Луа как на Луа, а не пытаться привнести собственные идиомы.

2 — Определение «левости» синтаксиса в студию. Либо конкретные примеры.

3 — Мы всё ещё про 5.x говорим? Если да, идём учить матчасть (в данном случае раздел 4).

Чувствую, что нужно уточнить про 1 и 2.

1. Современный Луа очень гибкий и поддерживает кучу разных подходов к написанию программ. В том числе и честный ООП. Если очень хочется его получить, welcome. Но, как с любым другим языком, на Луа лучше всего писать программы в его собственной, «луашной» стилистике.

В моей практике мне не хватало честного наследования всего пару раз. Утиная типизация вместе с метатаблицами решают.

2. Если смотреть с точки зрения mainstream-языков, таких как C++, C#, Java… в синтаксисе Луа действительно есть свои «странности». Нужно просто помнить, что Луа — другой язык, и всего лишь к ним привыкнуть.

Большинству «странностей» имеется серьёзное объяснение почему сделано именно так а не иначе. Объяснение с позиций сбалансированности всех аспектов языка, включая удобство пользователя, однозначность синтаксиса и максимальную простоту и скорость работы его реализации.

Много чего по теме можно почерпнуть из http://www.lua.org/doc/hopl.pdf и The implementation of Lua 5.0.
И ещё добавлю. Если не нравится синтаксис, его всегда можно исправить при помощи Metalua. ;-)
UFO landed and left these words here
1. Ну, может быть 100 KLOC C++ и 160 KLOC Луа и недостаточно сложно. Бывают программы намного больше и сложнее, согласен.

2. Читал, но конструктивной критики не увидел. Слово «дурацкий» в конструктив записать не могу, увы.

3. :-) Может быть Вы просто не умеете их готовить?
UFO landed and left these words here
Открывал. Вполне допускаю, что и пропустил в них что-то. О чём _конкретно_ речь?
UFO landed and left these words here
у вас не совсем правильные представления о реализации массивов в Lua.

та часть массива, которая не слишком разрежена[1], будет хранится именно как массив, а не как хэштаблица (т.е. чтение-запись будет бытрое)

конечно, при наличии дырок оператор # начнёт вести себя маразматически, но се ля ви.

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

[1] www.google.com/codesearch/p?hl=en&sa=N&cd=1&ct=rc#zXQJ5rQZsRM/lua-5.1.2/src/ltable.c&q=luaH_set&exact_package=ftp://ftp.sunfreeware.com/pub/freeware/SOURCES/lua-5.1.2.tar.gz&l=189
UFO landed and left these words here
UFO landed and left these words here
Утверждение некорректно как с точки зрения Луа как языка, так и с точки зрения конкретной реализации.

Если говорить о Луа как о языке, в Луа нет ни массивов ни хеш-таблиц. Есть один, универсальный тип данных — table (таблица). Его можно использовать как array, dictionary, set, list, queue, record и т.п. (прошу прощения, неуверен в русскоязычной терминологии). Table может быть как чем-то одним из этого списка, так и несколькими вещами сразу (например, в моём коде достаточно часто встречается комбинация array и record). Луашные таблицы — мощнейшее выразительное средство, один из краеугольных камней всего языка.

Если же говорить о конкретной реализации, то каждая луашная таблица одновременно содержит в себе как хеш-таблицу, так и массив. Виртуальная машина прозрачно и по достаточно чётко описанным правилам выбирает, куда класть данные. Если лень копаться в коде, всё написано доступным языком в двух абзацах четвёртого раздела The implementation of Lua 5.0, на который я уже давал ссылку.

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

Но оно того стоит, и с этим можно жить, и жить счастливо.

Смертельных проблем с JSON-ом я не вижу. Главное не пытаться использовать ipairs/table.concat/unpack/# и т.п. там, где этого не стоит делать. Если есть какой-то конкретный вопрос, готов помочь.

А, вообще, мне попадалось достаточно много готовых луашных библиотек для работы с JSON-ом. Вот, например: http://github.com/harningt/luajson

UFO landed and left these words here
1. Это зависит не от наличия или отсутствия ООП, а от программистов.

Копи-пейст (раз уж мы говорим об объёмах кода), например, у нас присутствовал в проекте в обычных (небольших) масштабах. И не из-за особенностей Луа, а из-за обычной программистской лени (либо авральности выполнения конкретной задачи). На плюсах или Яве было бы то же самое.

Другое дело, что, если бы, например, в Луа был ООП, но не было бы, скажем, замыканий и функций — значения первого класса, то было бы не 160 KLOC, а все 500.
* функций — значений первого класса
2. Это индивидуально.

Во-первых, кривая обучения языку и простота работы с ним, всё-таки, разные вещи. И синтаксис здесь далеко не первый вопрос.

Например, вне зависимости от синтаксиса, первые программы опытного PHP-шника на Луа не будут эффективными (обратное тоже верно) — языки слишком по-разному работают со строками.

У любого языка есть свои особенности. Пока человек не изучил их в достаточной степени, нельзя говорить, что он эффективно использует этот язык.

Во-вторых, мне, лично, разница в синтаксисе серьёзно помогает.

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

Можно попробовать писать в одном стиле, например, на плюсах и на Яве и не думать про переключение между языками. Только вот результат будет весьма посредственным.

Если уж так часто лезут эти ошибки — соответствующий статический валидатор кода на Металуа пишется достаточно тривиально.

Можно обойтись и рантайм-валидацией (я так делаю) — просто всегда проверять ассертом что self — это таблица. 80% опечаток это вылавливает.

Вот мой велосипед:

function foo:method(bar)
  method_arguments(
      self, 
      "number", bar
    )
end
1 — я могу назвать (гипотетическую) проблему: в теории отсутствие единого ООП должно рано или позно привести к трудностя со стыковкой библиотек использующих разные способы эмуляции ООП.

но на деле библиотеки чаще всего никакого явного ООП не используют (биндинги вообще пишутся в стиле «вот вам userdata с методами — делайте с ней, что хотите»), поэтому трудностей не возникает.

UFO landed and left these words here
насколько я слышал (сам не пользовался) существующий brige между objective-c и lua является куском гудрона. ну что ж поделать, просто его так написали… язык Lua тут не виноват.
UFO landed and left these words here
если честно, то я несовсем понимаю что значит «доверить». Lua ничего не знает и не может знать о ваших объектах, только вы знаете как и в каком порядке можно что-то удалять (или уменьшать счетчик ссылок) — надо строить очень аккуратную прослойку писать с учетом всех тонкостей семантики.
Никто и не обещал, что будет легко. Проблема скрещивания двух разных GC вообще вещь нетривиальная (хотя вот, например, нам, вроде бы, удалось скрестить луашку с AS3 без особых проблем).

В любом случае это не значит, что Луа вообще нельзя пользоваться :-)

Вот, кстати, недавно появился новый биндинг Lua-ObjectiveC (правда для айфона): Wax. Может быть там найдёте что-то полезное.
UFO landed and left these words here
Три причины:

1. (Главная и прагматическая) Реюз имеющегося специализированного луашного кода во флеше, чтобы не решать дважды одни и те же проблемы на клиенте (Флеш) и на сервере (Луа). (Довольно медленно, но для этих задач скорость не настолько важна.)

2. Некоторые флешеры (в частности, мой коллега по проекту) считают, что для части задач Actionscript слишком статичен. Луа — более динамический язык, на нём проще писать. Я — не флешер и люблю Луа, так что мне тяжело быть объективным в этом вопросе.

3. Пользовательский скриптинг (конструкторы игр; скриптуемые приложения на Air, в природе уже есть несколько на нашей технологии). Весь мой опыт говорит о том, что Луа более доступен неопытному пользователю чем язык типа Actionscript.
(Хочу заметить в скобках, что, ИМХО, всё-таки не эмуляции ООП, а его реализации.)

Если уж вдруг во внешнем интерфейсе луашного модуля так сильно нужен ООП… (Для чего? Высунуть «класс», чтобы можно было от него наследоваться? Зачем?)… И стоит задача сделать это максимально «стандартно» — пожалуйста, есть LOOP — «полуофициальная» реализация объектной модели на Луа.
я всё-таки склонен называть это эмуляцией… реализация с моей точки зрения должна быть встроена в язык, навязываться и её детали должны быть отгорожены «заслонкой» от внешнего мира… это исключительно моя точка зрения.

да я думал именно про интерфейсы, но как правило вместо интерфейсов используются обычные callback'и и потому всё хорошо.

спасибо, конечно, за предложение, но к тому времени когда LOOP появился, я уже к своей библиотечке привык, не переписывать же =)
Я вот не уверен, что интерфейсы в Луа имеют много смысла. Интересно обсудить юз-кейсы.

Всё-таки, мне кажется, утиная типизация должна снимать вопрос с интерфейсами.
интерфейсы исключительно имеют смысл как средство проверки «контракта» на месте создания объекта, а не в месте его использования… но я что-то затрудняюсь вообразить себе библиотеку, в которой я сам бы стал навязывать такую проверку…

Вот именно, это не библиотека получится, а фреймворк. А со фреймворками как раз обычно так и получается — нельзя использовать одновременно две штуки. :-)

Проверка контракта — да, полезно. Только в нашем случае к ООП не имеет особого отношения. Проверка должна быть не «наследуется от интерфейса», а «реализует указанный протокол».
Стек удобно отлаживать при помощи макросов.

Я использую вот это: lstack.h

Пример использования, например, здесь.
UFO landed and left these words here
Зато средств для их реализации достаточно.

Луа предоставляет не решения, но механизмы для их реализации.

Если нужно иметь всё из коробки — что ж, возможно Луа не для Вас. ;-)
UFO landed and left these words here
Каждому своё.

Я с Луа уже лет пять, написал приличное количество сложного кода — и мне вполне достаточно тех механизмов, что она мне даёт.

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

Опять же, нет желания писать самому — возьми у коллег. Для Луа сейчас доступно огромное количество открытого кода.

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

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

Но для себя, на данный момент, я вижу именно в Луа наилучшее сочетание качества (фичей) и цены (скорости написания кода и скорости работы этого кода) для написания бизнес-логики.
UFO landed and left these words here
Открытый код вообще не часто радует.

Мне кажется, что обычно, в режиме когда нет времени на изучение новой технологии, лучше эту технологию отложить на потом, и пользоваться «дедовскими методами». Потом обычно меньше негативных эмоций остаётся. ;-)
UFO landed and left these words here
Согласен по обоим пунктам.

Но Руби слишком медленный для моих задач, а для эрланга слишком тяжело найти программистов. Спасает то, что Луа — где-то между ними. :-)
UFO landed and left these words here
удобство? вот уж действительно на вкус и цвет товарищей нет…
Давайте не будем примешивать в наш топик холивар про Руби, ладно? ;-)
я вообще противник холиваров! =)
Давайте. Учитавя что ни Ruby, ни Lua, ни Python ни в какое сравнение с TCL в embedded не идут, предлагаю забыть обо всех них и обсудить крутость последнего ;)
UFO landed and left these words here
А что там с многопоточностью? Нет такой ахинеи с global interpreter lock как питоне?
С многопоточностью проблем не встречал. Пару лет назад, ради эксперемента, писал IVR приложение, где логика работы была вынесена в Lua. Среднее количество одновременных звонков было порядка 25, проблем не наблюдалось.
Это не количество, обсуждать стоит от 1000-и.
От 1000 тоже нормально работает (и в моей личной практике тоже).
UFO landed and left these words here
Имеется в виду не число ниток, а число одновременных запросов. С низким числом запросов высоки шансы, что ни один так и не выполнится одновременно с другим.
Если создать несколько luaVM и запустить исполнение в разных нитях — точно никаких проблем не будет.
И, наоборот, несколько нитей, использующий один lua_State * — плохая идея.
BOOL, TRUE, FALSE
Вы по MSDN учились программировать?)
Да, где-то там я это и подцепил :)
Это вызвано тем, что соглашения о вызовах в C отличаются от соглашений в C++.


Если быть точным: это вызвано разными соглашениями о манглировании имён, calling convention не отличается.
Если быть ещё чуточку более точным, это вызвано тем, что в C++ есть манглирование имён, в отличие от C.
В виндах ещё и calling convention другие. Так что можно сказать, что в виндах и C++ есть name mangling, в отличие от C :)
В D есть несколько режимов связывания: extern(D), extern(C++), extern© и extern(Windows) :)
Это так автотипографика пошутила?
Я вот все думаю написать про добавление к виндовым приложениям скриптинга на Javascript (ну и VBscript до кучи). Если кому-то это интересно будет, отпишитесь )
кстати lua отлично можно использовать и как standalone язык, а не только как скриптовый язык для встраивания. я сам большой фанат =)
Согласен, тем более, что для него есть куча готовых библиотек. практически под любые задачи. А чего нет — всегда можно дописать самостоятельно. :)
еще стоит упомянуть такую вещь как metalua, весьма интересная штучка
А можете подсказать, какой-нибудь материал, как Python в проект добавить? Ссылочку на материал там, ну или что-нибудь в этом роде, пожалуйста :)
Если в C++, то берите boost::python и не мучайтесь.
Как раз хотел изучать эту тему а тут и пост подоспел. Огромное спасибо.

Никто не замечал такую тенденцию: думаешь над какой-нибудь задачей, а тут раз и на следующий день топик или статья в журнале с примером реализации?
Заметил, на Хабре не раз с этим сталкивался, только задумался, а тут бац и статья на эту тему.
А я использую для скриптинга C# — в .Net есть вся необходимая инфраструктура, ничего самому писать не нужно. Пользователь может писать скрипты на C#, при этом его код выполняется прямо в среде классов моей системы. Если кому-нибудь интересно, могу написать статью об этом.
А как с кроссплатформенностью в этом случае?
Это я не исследовал. Возможно, в Mono это тоже сработает.
Некрасиво говорить за всех, конечно, но я думаю, что многие .NET-программисты не задумываются о кросс-платформенности.
Было бы интересно почитать.
Кто является пользователем в данном случае?

В моей практике писать скрипты на языке со статической типизацией можно заставить только достаточно ограниченный круг лиц. (Если пользователи — программисты на C#, тогда да, конечно, решение идеальное.)
В моём случае обычные пользователи (даже не программисты) легко могут скорректировать имеющийся скрипт — там часто нужно просто немного подправить.
Если что-нибудь более серьёзное — конечно, нужно немного знать программирование, и желательно чуть-чуть знать C#. Мои сотрудники из отдела поддержки прекрасно с этим справляются.
А так согласен — конечно, идеальных решений не бывает. Но это и хорошо — всегда есть куда совершенствоваться.
Для более удобной интеграции Lua в С++ программу, советую попользоваться luawrapper.
Это часть проекта Lua Server Pages.

Вот простейший пример применения:

#include "luawrapper.h"
#include <stdio.h>

int sum(lua_State* L)
{
    lua::stack st(L);
    
    double a=0,b=0;
    
    st.at(1,a);			// begin from 1
    st.at(2,b);
    
    st.push(a+b);
    
    return 1;			// number of return values (st.push)
}


int main(void)
{
    try
    {
	lua::vm vm;
	
	// initialize
	vm.initialize();
	
	// register CFunction
	vm.reg("sum",sum);

	// register package 'lib'
	static const luaL_Reg lib[]=
	{
	    {"sum",sum},
	    {0,0}
	};	
	vm.reg("lib",lib);
	
	// execute Lua statements
	vm.eval("print(\"5+6=\"..sum(5,6))");
	vm.eval("print(\"3+4=\"..lib.sum(3,4))");	
    }
    catch(const std::exception& e)
    {
	fprintf(stderr,"%s\n",e.what());
    }
    catch(...)
    {
	fprintf(stderr,"exception\n");
    }
    
    return 0;
}
Only those users with full accounts are able to leave comments. Log in, please.