lua для чего используется

lua — практическое применение?

Луа, будучи, очень простым и компактным языком — легко встраиваться. Включаете пару десятков чистых сишных файлов в проект — и вуаля — у вас встроеный язык. Еще, настраиваемость — по большому счету, в плане библиотек, луа это скорее скелет языка, чем полноценный язык програмирования. Иногда при встраивание вообще выкидвают большую часть (или всю) «стандартную» библиотеку, заменяя ее специализированной под домейн, фактически создавая специализированный язык. Еще один плюс — компактность. Я как-то давно, проверял возможность запускать луа-интерпретатор в качестве отладочного модуля на встроенном чипе (я не говорю про смартфоны, а про «жесткий» embedded). Так вот, виртуальная машина луа (правда почти без библиотек и без интерпретатора, кормить ей надо было уже байткод) занимала 15кб (!) RISC кода. Оказалось, что вполне реально запустить было на том железе, хотя в конце эту идею зарубили как слишком сумашедшую («интепретатор в нашем RT?!»). Идем дальше, Луа можно использовать в качестве декларативного языка, но с «плюшкой» в виде динамичности и читаемости человеком, в отличии скажем от статических декларативных систем, например XML. Я как-то делал декларативную систему описания автоматических тестов на луа, получилось по-моему, неплохо. 🙂 А из более простых примеров такого применения — это файлы конфигурации. Простые файлы var=value легко распарсить вручную, на зато на луа можо сделать вот так:
width = 100
height = width*1.2
positions[0] =

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

Вообщем давайте просуммируем: если нужен легко встраиваемый, компактный, настраиваемый и быстрый скриптовый язык, чтобы расширить функциональность вашей программе — луа отлично для это подходит. Но если нужный полноценный самостоятельный язык, c богатой библиотекой и возможность писать приложения от начала до конца, то лучше посмотреть в сторону «серьёзных» собратьев, скажем Пайтона (Perl, Ruby, whatever). Их, кстати, тоже можно встроить в качество скриптового языка, просто это далеко не всегда оправданно там, где можно ограничится луа.

ЗЫ: JavaScript в чем-то похож на луа тем, что он тоже почти никогда не используется как «самостоятельный» язык.

Странная мотивация. Игры Движки игр требуют быстроты — вот движки игр и пишут на C/C++/etc. Логика игр не требует быстроты, но требует чтоб её мог писать непрограммист — вот и Lua, который не обязательно быстрый.

Источник

Встраиваемые языки: почему Lua?

Этот материал продолжает серию публикаций, основанных на докладах, которые мы сделали на конференции Games Gathering 2017 в декабре прошлого года. В одном из докладов была затронута тема выбора встраиваемого скриптового языка.

Что такое и зачем нужны скриптовые языки

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

Таким образом, есть потребность в средстве для описания несложной, но всё-таки логики, без привлечения тяжёлой артиллерии программистов. Сделаем вывод — что такое для нас скриптовый язык? Это средство, которое позволит сделать разработку игр быстрее и дешевле.
Сразу возникает вопрос, а почему бы нам просто не использовать что-то вроде XML? Дело в том, что для наших целей нам часто нужны управляющие конструкции — ветвление и циклы, в то время как XML это декларативное описание.

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

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

Сформулируем требования к идеальному скриптовому языку.

Python

Python — динамический язык, который пользуется немалой популярностью. Он характеризуется достаточно пологой кривой обучения, его довольно просто выучить. Однако изучить его как следует уже не так-то просто. Как результат, хорошие Python-программисты встречаются редко и дорого стоят. Это противоречит нашему желанию ускорить и удешевить разработку игровой логики.

Python обладает широкими возможностями, отличается хорошей производительностью. Его проблемой является неконсистентная система библиотек. Ещё одна его проблема, которая играет для нас важную роль, заключается в том, что он, на самом деле, не является встраиваемым языком. Это язык, из которого удобно вызывать библиотеки, написанные на C или C++.

По поводу возможностей по встраиванию Python можно сказать, что, например, существует Maya, где используется именно Python. Но тот, кто видел изнутри плагины для Maya, написанные на Python, согласится с нами в том, что выглядят они не очень хорошо.

В итоге можно сказать, что Python, при всех его сильных сторонах, нам не подходит. Теперь рассмотрим JavaScript.

JavaScript

JavaScript — это, без преувеличений, великий язык, который буквально захватил мир.

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

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

В компании SocialQuantum есть собственный интерпретатор JavaScript, который проходит 98% тестов, мы планируем перевести этот проект в разряд опенсорсных.

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

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

Может быть, нас устроит ActionScript или какой-нибудь другой скриптовый язык?

ActionScript

Если формально проанализировать ActionScript на соответствие вышеозначенным требованиям, то может показаться, что идеальный скриптовый язык найден. На его стороне динамическая природа, популярность, лёгкость изучения, хорошие возможности, производительность, наличие библиотек, лёгкость встраивания. Этот язык любят и помнят в игровой индустрии, на нём написано огромное количество замечательных Flash-игр. Главная проблема ActionScript заключается в том, что язык этот почти мёртв. Поэтому нас он тоже не устраивает.

Читайте также:  что делать влюбленным дома

AngelScript, Squirrel и другие

Помимо ActionScript существует множество скриптовых языков, таких, как AngelScript, Squirrel и другие. Среди них можно найти такие, которые, формально, почти полностью удовлетворяют нашим требованиям, но обычно это — языки, которые привязаны к их разработчику, в них бывают какие-то застарелые проблемы, которые годами не исправляются. Они, скорее всего, не слишком популярны, недостаточно хорошо документированы, по ним мало учебных материалов, у них не очень большие сообщества. Одним из следствий такого положения дел является тот факт, что их сложно изучать — хотя бы потому, что не до конца ясно — что они собой представляют и как работают.

Как видно, идеального встраиваемого языка мы пока не нашли. Что если создать собственный язык?

Создание собственного языка

Вполне возможно, что язык, разработанный внутри компании, будет идеально соответствовать её нуждам и его будет легко изучать. Но, скорее всего, такой язык не станет популярным. У такого языка либо будет минимальное количество библиотек, либо их не будет вовсе. Кроме того, сложно поверить, что в современных условиях можно создать нечто такое, что будет работать лучше, что будет обладать большей производительностью и будет проще встраиваться чем что-то, что уже есть на рынке.

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

Рассмотрев существующие языки программирования, претендующие на роль встраиваемых и обсудив идею разработки собственного языка, перейдём к Lua.

Lua — встраиваемый язык, который выбрали мы

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

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

Например, вот как выглядит наша рабочая среда на основе IDE CLion от JetBrains. Здесь можно видеть созданный нами механизм автодополнения для Lua, который планируется сделать опенсорсным. Опенсорсным мы собираемся сделать и отладчик.

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

Возражения по поводу использования Lua

Lua предназначен для C а не для С++

Никто не спорит с тем, что Lua — отличный встраиваемый язык. Главное, что считают его минусом, заключается в том, что он создан для использования с языком C, а не C++. Из-за этого, пытаясь применить в Lua что-то такое, что есть в C++ и нет в C, мы сталкиваемся с проблемами. Однако тут надо понимать, что проблемы эти решало множество довольно умных людей. Среди средств, решающих проблемы встраивания Lua в C++-проекты, можно отметить такие, как Luabind, Luabridge, toLua++, SQLuaHost. Это — далеко не полный список. Они обладают разными достоинствами и недостатками, но, тем не менее, скорее всего, всё, что вам может потребоваться, уже реализовано в одном из этих решений.

Рассмотрим, например SQLuaHost. Это — биндинг, который сделан внутри компании SocialQuantum, и который планируется сделать опенсорсным. Это решение представляет наше видение того, как должен биндиться Lua. Поэтому, вполне возможно, что если вы не нашли то, что вам нужно в существующих биндерах, вы найдёте это в SQLuaHost.

Lua — это медленно

Нам часто приходится сталкиваться с мнением, в соответствии с которым Lua — это очень медленный язык. Во-первых — это не так. Lua — это стековая машина, и там, на самом деле, просто нечему тормозить. К тому же надо понимать, что в скриптовый язык мы обычно отдаём игровую логику, бизнес-логику, а не какие-то действительно тяжёлые вещи. В результате, если Lua-скрипты заставляют игру тормозить, то проблема, возможно, кроется в неоптимальном биндинге или в нерациональном использовании каких-то функция языка. Мы, например, проводили синтетические тесты, на которых LuaJIT работает быстрее, чем Mono. При этом никто не мешает писать примерно такой вот неоптимальный код:

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

Lua подходит только для маленьких проектов

Следующее возражение заключается в том, что Lua сделан для того, чтобы писать какие-то маленькие вещи и что-то большое на этом языке написать невозможно. С одной стороны это правда. Но у этого языка высокая модульность. И из множества маленьких блоков можно делать достаточно большие и сложные системы. А если вспомнить то, что было уже сказано о мультипарадигменности и об ООП, то окажется, что ООП подталкивает разработчика к тому, чтобы создавать маленькие модули, которые можно использовать при создании больших и сложных конструкций.

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

Другие аргументы против Lua

Критикуя Lua, говорят о том, что язык это древний, что он, что называется, «из коробки», не поддерживает ООП, что нумерация элементов в его таблицах начинается не с 0, как можно было бы ожидать от любого приличного языка, а с 1.

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

Читайте также:  какой кабель взять для сварочного аппарата

Итоги

Подведём итоги. Если ваша задача — с минимальными усилиями обзавестись встраиваемым языком — возьмите Lua. В то же время, если у вас есть время и ресурсы на разработку собственного языка или собственных биндингов — опять же — обратите внимание на Lua. Почему и в первом и во втором случаях мы рекомендуем Lua?

В первом случае, выбрав Lua, вы выберете язык, который очень просто встраивать и использовать. Существует ровно одна обучающая книга по этому языку, написанная его автором. Других книг нет просто потому, что в первой рассказано абсолютно всё, что нужно знать о Lua, и рассказывать о нём больше нечего. Lua — не идеальный и не самый распространённый в мире язык, но, по сумме критериев, это, определённо, один из лучших языков для встраивания. Он — лучший из того, что есть в нашем распоряжении прямо сейчас. К тому же, существует множество стандартных инструментов для Lua, которые сильно облегчают жизнь тем, кто им пользуется.

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

Источник

Язык программирования Lua: возможности разработки для непрофессиональных программистов

Разработчиком этого языка является подразделение Tecgraf из Бразилии. Появился Lua в 1993 году. Авторами являются Роберту Иерузалимски, Вальдемар Селиш и Луиш Энрике ди Фигейреду. Язык имеет открытый код, то есть каждый желающий может внести свою лепту в его развитие. Важной особенностью создания этого языка является то, что он появился в Бразилии, стране, которая ни до этого ни после особенно не отличалась в плане разработки.

Прародителями Lua являются два языка разработки – SOL и DEL. Они также разработаны Tecgraf в период с 1992 по 1993 гг. Причем заказчиком выступала известная компания Petrobras. На сегодняшний день последней версией языка является 5.4.0. Обновление вышло летом 2020 года.

Как видно, Луа, наряду со многими современными языками программирования, имеет длительную историю. При этом, проводятся регулярные обновления, что говорит о том, что Lua пользуется популярностью в определенных кругах и имеет довольно серьезное сообщество.

Главная особенность Луа заключается в том, что он может использоваться как в качестве отдельного, так и встроенного скриптового языка. Уже в процессе создания разработчики поставили себе цель – сделать компактный и простой инструмент, который мог бы с легкостью работать в различных исполняющих средах и обеспечивать при этом должный уровень производительности.

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

Lua относится к языкам программирования ООП. Благодаря встроенным средствам параллельного программирования, разработчики могут создавать многопоточные приложения без обращения к внешним библиотекам или API. При этом, в языке эффективно реализованы возможности межъязыкового взаимодействия.

Где применяется язык Lua? Несмотря на достаточно широкое применение в промышленности (не будем забывать, что язык изначально разрабатывался для нужд нефтяной компании Petrobras), более активно Луа сегодня используется при разработке компьютерных игр.

Связано это с тем, что Lua позволяет довольно легко запрограммировать поведение так называемых NPC (от англ. Non-playable characters). Также, с помощью этого языка программируются и другие персонажи, поведение которых можно впоследствии быстро менять, не оказывая влияния на движок.

Наиболее известным игровым продуктом, в котором применяется язык Lua является World of Warcraft. Здесь язык использовался при написании интерфейса. Также, Lua активно использовался и при создании других известных игровых шедевров, таких как Цивилизация 5, Crysis, Sim City, Far Cry, Stalker.

Помимо игрового применения, Луа также подходит для написания ботов для Телеграм, например. Также, Википедия планирует использовать данный язык разработки для встраивания в MediaWiki.

Наконец, применяется Lua и в обсерваториях, которые занимаются исследованиями космоса. Язык также используется различными университетами. А в самой Бразилии его применяют повсеместно. То есть он стал чем-то вроде государственного языка программирования.

Источник

Основы декларативного программирования на Lua

Луа (Lua) — мощный, быстрый, лёгкий, расширяемый и встраиваемый скриптовый язык программирования. Луа удобно использовать для написания бизнес-логики приложений.

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

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

Пример

В качестве наивного примера возьмём код создания диалогового окна с текстовым сообщением и кнопкой в императивном стиле:

function build_message_box ( gui_builder )

local my_dialog = gui_builder:dialog ( )

my_dialog:set_title ( «Message Box» )

local my_label = gui_builder:label ( )

my_label:set_text ( «Hello, world!» )

local my_button = gui_builder:button ( )

В декларативном стиле этот код мог бы выглядеть так:

build_message_box = gui:dialog «Message Box»

Гораздо нагляднее. Но как сделать, чтобы это работало?

Основы

Чтобы разобраться в чём дело, нужно знать о некоторых особенностях языка Луа. Я поверхностно расскажу о самых важных для понимания данной статьи. Более подробную информацию можно получить по ссылкам ниже.

Динамическая типизация

Важно помнить, что Луа — язык с динамической типизацией. Это значит, что тип в языке связан не с переменной, а с её значением. Одна и та же переменная может принимать значения разных типов:

Таблицы

Таблицы (table) — основное средство композиции данных в Луа. Таблица — это и record и array и dictionary и set и object.

Для программирования на Луа очень важно хорошо знать этот тип данных. Я кратко остановлюсь лишь на самых важных для понимания деталях.

Создаются таблицы при помощи «конструктора таблиц» (table constructor) — пары фигурных скобок.

Создадим пустую таблицу t:

Запишем в таблицу t строку «one» по ключу 1 и число 1 по ключу «one»:

Содержимое таблицы можно указать при её создании:

Читайте также:  какой максимальный оборот у ип при усн

Таблица в Луа может содержать ключи и значения всех типов (кроме nil). Но чаще всего в качестве ключей используются целые положительные числа (array) или строки (record / dictionary). Для работы с этими типами ключей язык предоставляет особые средства. Я остановлюсь только на синтаксисе.

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

Следующие две формы записи эквивалентны:

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

При создании таблицы следующие две формы записи эквивалентны:

Аналогично для индексации при записи…

Функции

Функции в Луа — значения первого класса. Это значит, что функцию можно использовать во всех случаях, что и, например, строку: присваивать переменной, хранить в таблице в качестве ключа или значения, передавать в качестве аргумента или возвращаемого значения другой функции.

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

function make_multiplier ( coeff )

return function ( value )

return value * coeff

local x5 = make_multiplier ( 5 )

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

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

function mul ( lhs, rhs ) return lhs * rhs end

mul = function ( lhs, rhs ) return lhs * rhs end

Вызов функции без круглых скобок

В Луа можно не ставить круглые скобки при вызове функции с единственным аргументом, если этот аргумент — строковый литерал или конструктор таблицы. Это очень удобно при написании кода в декларативном стиле.

print ( «Shopping list:» )

for name, qty in pairs ( items ) do

Цепочки вызовов

Как я уже упоминал, функция в Луа может вернуть другую функцию (или даже саму себя). Возвращённую функцию можно вызвать сразу же:

chain_print ( 1 ) ( «alpha» ) ( 2 ) ( «beta» ) ( 3 ) ( «gamma» )

В примере выше можно опустить скобки вокруг строковых литералов:

chain_print ( 1 ) «alpha» ( 2 ) «beta» ( 3 ) «gamma»

Для наглядности приведу эквивалентный код без «выкрутасов»:

local tmp1 = chain_print ( 1 )

local tmp2 = tmp1 ( «alpha» )

local tmp3 = tmp2 ( 2 )

local tmp4 = tmp3 ( «beta» )

local tmp5 = tmp4 ( 3 )

Методы

Объекты в Луа — чаще всего реализуются при помощи таблиц.

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

Луа предоставляет специальный синтаксический сахар для объявления и вызова методов — двоеточие. Двоеточие скрывает первый аргумент метода — self, сам объект.

Следующие три формы записи эквивалентны. Создаётся глобальная переменная myobj, в которую записывается таблица-объект с единственным методом foo.

function myobj:foo ( b )

function myobj.foo ( self, b )

myobj [ «foo» ] = function ( self, b )

print ( self [ «a_» ] + b )

Примечание: Как можно заметить, при вызове метода без использования двоеточия, myobj упоминается два раза. Следующие два примера, очевидно, не эквивалентны в случае, когда get_myobj() выполняется с побочными эффектами.

Чтобы код был эквивалентен варианту с двоеточием, нужна временная переменная:

local tmp = get_myobj ( )

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

Реализация

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

build_message_box = gui:dialog «Message Box»

Что же там написано?

Приведу эквивалентную реализацию без декларативных «выкрутасов»:

local tmp_1 = gui : label ( «Hello, world!» )

local tmp_2 = gui : button ( «OK» )

local button = tmp_2 ( < >)

local tmp_3 = gui : dialog ( «Message Box» )

Интерфейс объекта gui

Как мы видим, всю работу выполняет объект gui — «конструктор» нашей функции build_message_box(). Теперь уже видны очертания его интерфейса.

Опишем их в псевдокоде:

Декларативный метод

В интерфейсе объекта gui чётко виден шаблон — метод, принимающий часть аргументов и возвращающий функцию, принимающую остальные аргументы и возвращающую окончательный результат.

Для простоты, будем считать, что мы надстраиваем декларативную модель поверх существующего API gui_builder, упомянутого в императивном примере в начале статьи. Напомню код примера:

function build_message_box ( gui_builder )

local my_dialog = gui_builder:dialog ( )

my_dialog:set_title ( «Message Box» )

local my_label = gui_builder:label ( )

my_label:set_text ( «Hello, world!» )

local my_button = gui_builder:button ( )

Попробуем представить себе, как мог бы выглядеть метод gui:dialog():

return function ( element_list )

return function ( gui_builder )

local my_dialog = gui_builder:dialog ( )

element_list [ i ] ( gui_builder )

Ситуация с [gui_element] прояснилась. Это — функция-конструктор, создающая соответствующий элемент диалога.

Функция build_message_box() создаёт диалог, вызывает функции-конструкторы для дочерних элементов, после чего добавляет эти элементы к диалогу. Функции-конструкторы для элементов диалога явно очень похожи по устройству на build_message_box(). Генерирующие их методы объекта gui тоже будут похожи.

Напрашивается как минимум такое обобщение:

function declarative_method ( method )

return function ( self, name )

return function ( data )

return method ( self, name, data )

Теперь gui:dialog() можно записать нагляднее:

gui.dialog = declarative_method ( function ( self, title, element_list )

return function ( gui_builder )

local my_dialog = gui_builder:dialog ( )

element_list [ i ] ( gui_builder )

Реализация методов gui:label() и gui:button() стала очевидна:

gui.label = declarative_method ( function ( self, text, parameters )

return function ( gui_builder )

local my_label = gui_builder:label ( )

if parameters.font_size then

gui.button = declarative_method ( function ( self, title, parameters )

return function ( gui_builder )

local my_button = gui_builder:button ( )

— Так сложилось, что у нашей кнопки нет параметров.

Что же у нас получилось?

Проблема улучшения читаемости нашего наивного императивного примера успешно решена.

В результате нашей работы мы, фактически, реализовали с помощью Луа собственный предметно-ориентированный декларативный язык описания «игрушечного» пользовательского интерфейса (DSL).

Благодаря особенностям Луа реализация получилась дешёвой и достаточно гибкой и мощной.

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

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

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

Полностью работающий пример можно посмотреть здесь.

Источник

Сказочный портал