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

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



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


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

    Почему вообще возникает потребность в скриптовых языках? Как говорится, «в игровой индустрии нет сложных проблем, незачем требовать сложных решений» . Помимо опытных (и дорогих!) программистов, решающих сложные задачи, нам нужны люди (много людей!), которые будут заниматься, скажем, квестами. И, если честно, нам бы хотелось, чтоб эти программисты были не такие дорогие, а в идеале и вовсе не программисты, а непосредственно геймдизайнеры и сценаристы.

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

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

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


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

    • Динамический. В нашем понимании идеальный скриптовый язык должен быть динамическим.
    • Популярность. Под популярностью языка мы понимаем наличие у него достаточно большого сообщества, готового отвечать на вопросы на специализированных ресурсах наподобие StackOverflow.
    • Пологая кривая обучения. Мы хотим взять, условно говоря, практически любого человека, и быстро обучить его до уровня, который позволит этому человеку продуктивно работать над нашими задачами.
    • Широкие возможности. Язык должен быть мощным и обладать достаточно широкими возможностями, должен поддерживать разные парадигмы программирования. Профессиональный программист, которому предложат писать на таком языке, сможет делать это с комфортом и с удовольствием.
    • Высокая производительность. Производительность — это один из краеугольных камней игровой индустрии.
    • Большое количество библиотек. Очень часто мы, в ходе решения встающих перед нами задач, не создаём принципиально новый код, а пользуемся тем, что уже кто-то написал. Чем больше стабильных, хорошо поддерживаемых библиотек мы можем задействовать, применяя некий язык — тем лучше.
    • Лёгкость встраивания. Речь идёт о встраиваемых языках, поэтому при выборе скриптового языка возможность его встраивания играет важную роль.

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

    Python


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

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

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

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

    JavaScript


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

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

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

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

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

    Haxe


    Тут надо отметить, что когда заходит разговор о 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. При этом никто не мешает писать примерно такой вот неоптимальный код:

    function myGame:onUpdate()
        local tex = Texture::new(name)
        self.background:setTexture(tex)
    end

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

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


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

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

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


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


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

    Итоги


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

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

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

    Comments 73

      +4
      Тернарный оператор в Lua и не нужен. (cond? true_val: false_val) в Lua выглядит так: (cond and true_val or false_val)
        +4
        А если cond == true и true_val вычисляется в false, код, вычисляющий false_val будет выполнен?
          0
          Будет выполнен и всё выражение будет равно его значению, вне зависимости от возврата false_val. Отличный способ сделать себе неочевидную проблему. Но, надо заметить, в lua не так много значений тождественны false: это сам false и nil. Всё остальное тождественно true.
          +1
          function condition()
             return true
          end
          
          print(condition() and false or true)

          Happy debugging.
            +1
            print(not condition())
              +1
              Как это отменяет тот факт, что and-or идиома — это не тернарное условие? :)
                +1
                Никак :)

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

              Это ещё можно решить:


              print(not condition() and true or false)

              А вот это?


              print(condition() and nil or false)
                0

                По идее, всегда false выведет, потому что nil приравнивается к false, а значит "... and nil" всегда false.

                  0

                  Всё верно. Задача в том чтобы минимально переделать это выражение так чтобы в зависимости от condition возвращалось nil или false.

                    0
                    интересно посмотреть на задачу, где нужно различать nil и false. это, кажется, не самое полезное занятие (кроме случаев, когда куда-то был явно записан false, но там можно сделать проверку на равенство).

                    а с небольшим оверхедом (за счет читаемости, скорости работы и чутка памяти) это задачу можно решить так:
                    print( ({[true]=false})[not condition() or false] )
            +2
            В нашем понимании идеальный скриптовый язык должен быть динамическим.
            Почему? Динамически типизированный код на порядок хуже поддается оптимизации, а в играх (особенно под мобильные устройства не последних поколений) это может быть заметно.
              0

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

                0
                AngelScript многократно медленнее LuaJIT. По крайней мере год назад так было.
                  0

                  А я не говорю, что он лучше, я лишь о том, что скриптовые языки со строгой статической типизацией существуют.

                    +1
                    Это вкусовщина, пожалуй. Но я за статическую типизацию: избавляет от целого класса багов, когда в переменную по ошибке записывается несовместимый тип.
                  +3
                  Интересно было бы послушать аргументацию. «Не нужно» — это не аргумент, а вкусовщина.

                  Часто сталкиваюсь со предубеждением, что «статическая типизация» требует избыточных аннотаций и замусоривает код. Ради красоты кода в жертву приносятся скорость исполнения, качество автокомплита, статические проверки и прочие важные вещи. Однако с помощью вывода типов даже в языках с сильной статической типизацией может быть очень легковесный синтаксис: достаточно взглянуть на F#, Crystal, Nim и множество других примеров.
                  +4
                  В любой программе, в том числе и в играх, много некритичного к производительности кода, который не имеет смысла оптимизировать.
                  Но вот устойчивость к ошибками при использовании статической типизации значительно выше, что позволило бы использовать менее опытных программистов. Очень жаль, что статической типизации так боятся.
                    +1
                    Дело не только в оптимизации, они не поддаются средствам статического анализа: страдает качество кода, страдает автокомплит, стоимость разработки увеличивается из-за этого.

                    Плюсов не вижу. Сначала подумал про более низкий уровень вхождения для новичков, но потом понял, что сравниваю динамическую типизацию со статической без выведения типов, а это некорректно.
                      +1
                      Единственный плюс динамической типизации — в простоте реализации наивного интерпретатора и наивной поддержки метапрограммирования. Все остальное, наоборот, получается гораздо сложнее.
                    +3

                    У Lua, на мой взгляд, есть ещё одно преимущество. С помощью luaL_newstate() наплодить только независимых интерпретаторов Lua со всем окружением, сколько нужно. В итоге у вас может быть один интерпретатор, который обрабатывает скрипты пользователя, и другой, который скриптует UI, и они никак друг на друга не влияют и никак друг о друге не знают.

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

                      Ну это как-бы надумано. API биндинга на C, но это не значит что этот API невозможно удобно завернуть для C++ практически с 0-выми издержками. Есть очень хорошая биндинговая либа sol2 (C++14). А вообще биндить Lua совсем не сложно.


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

                      Lua интерпретатор, наверное да. А LuaJIT по скорости мало уступает коду сгенерированному из C.


                      Критикуя Lua, говорят о том, что язык это древний, что он, что называется, «из коробки», не поддерживает ООП

                      Странно об этом слышать, когда в документации, ООП возможности хорошо рассматриваются.


                      Даже множественное наследование возможно.

                        +8
                        От программистов на С/С++ вообще странно слышать про «древний язык»
                        +3
                        Поправьте, если ошибаюсь, но ведь при выборе скриптового языка для игр Lua уже очень много лет вариант по умолчанию…
                          +3
                          Lua — лучший выбор, но при этом вы написали свою IDE, чтобы иметь возможность писать на нем с хоть минимальным комфортом? Неплохо, неплохо.
                            +1

                            Zero Brain Studio
                            Eclipse (ldt)


                            Мaло-ли кто и что пишет? Почему-бы не написать ещё один IDE?

                              +2
                              Это Clion, с плагином EmmyLUA
                                0
                                Эм точно? А то пишут у нас свое. Не EmmyLUA как-то слабо похоже.
                            +2
                            А JIT внезапно стал возможен на ios? Насколько я помню, ios запрещает ставить флаг исполняемости на data сегментах памяти.
                              –1
                              Так оно же не напрямую выполняется, а интерпретируется самой игрой. Примерно как аудио декодируется и стримится в аудиовывод также и скрипт гоняет некоторую логику. Так что 755 там и не нужен.
                                +2

                                "не напрямую выполняется, а интерпретируется" — это уже не JIT.

                                  –2
                                  Парсится lua-файл и перегоняется в специфичный байт-код, то бишь jit-ится. Дальше происходит побайтовая интерпретация команд этого байт-кода на условной lua-vm.
                                  В общем lua на ios точно есть и вполне себе работает в составе игр.
                                    +2

                                    Нет, речь судя по всему шла про LuaJIT, разновидность Lua с JIT в привычном смысле: код на Lua "перегоняется" не в байткод, а машинный для текущей платформы.

                                      +1
                                      Нет, слово «jit-ится» означает не то что вы назвали.
                                  +1
                                  Запрет iOS на испольнение не технический, а юридический.

                                  dev.hel.fi/paatokset/media/att/9a/9aa5692b91f2b538eeb352c425b3e66c09e6b1a5.pdf

                                  3.3.2
                                  Except as set forth in the next paragraph, an Application may not download or install executable code. Interpreted code may only be used in an Application if all scripts, code and interpreters are packaged in the Application and not downloaded. The only exceptions to the foregoing are scripts and code downloaded and run by Apple's built-in WebKit framework or JavascriptCore, provided that such scripts and code do not change the primary purpose of the
                                  Application by providing features or functionality that are inconsistent with the intended and
                                  advertised purpose of the Application as submitted to the App Store.


                                  т.е. интерпретировать можно только то что уже есть в пакете приложения.
                                    0
                                    По крайней мере во времена 2.0.4 JIT-часть была отрублена для iOS, сейчас вряд ли что-то поменялось. Но там и сам интерпретатор быстрее, чем в ванильной луа.

                                    Edit: нет, в голове тоже выключено.
                                    +5
                                    Интересно, что не так с python? Почему система библиотек неконсистентная? В чем проблема встраивания в с\с++?
                                      +1

                                      Само встраивание простое, но интерпретатор в отличии от Lua или V8 не имеет отдельного стейт-хендлера, т.е. более одного интерпретатора в код не внедришь (не всем это кстати нужно). Python большой и медленный (относительно Lua), порог вхождения выше.


                                      В "танках" вроде питон всторен, если не ошибаюсь.

                                        0
                                        ИМХО, единое состояние на приложение — это единственный аргумент, но как вы упомянули, и то всегда :).

                                        Большой — вероятно, но как я ответил в коменте, легко обрезается, так же «большой» может быть преимуществом перед «маленьким» lua, когда ситуация требует нечто больше возможности прокинуть куски с с++ и как то заскриптовать их.

                                        Скорость — так себе аргумент, даже относительно luajit. Обычно в скрипты выносят простую логику, а не сложные вычисления, так что даже на самом медленном языке надо постараться, что бы значительно увеличить нагрузку на cpu или время кадра.

                                        Порог вхождения — для кого? Для тех, кто будет писать скрипты, или тех, кто будет встраивать язык в основное приложение? Для первых — если эта группа людей не знает ни питон, ни lua, выучить базовый синтаксис любого языка будет просто; + python более популярен(человека разбирающегося по минимуму в python найти в сто раз проще); учить api, предоставляемое основной программой учить придется в любом случае. Для вторых — не очень знаком с lua, но не думаю что объем кода биндингов будет сильно отличатся, но я практически уверен, что для lua существуют инструменты для значительного упрощения процесса биндинга(для python существует).

                                        Не подумайте, что я топлю за python в каждом приложении где нужен скриптинг. Просто статья по смыслу выглядит для меня так — «нам нужны скрипты, мы тут полазили, посмотрели, что то нам ничего не подошло, а почему? А потому что нам понравился lua, посмотрите какой он как будто бы и плохой, но по настоящему он очень хороший. Мы даже свою IDE для него написали. Всем рекомендуем.»
                                        Все аргументы против других языков вообще не выглядят убедительно, и как будто бы приведены для того, что бы оправдать выбор lua; реального сравнения нет, и часть про другие языки вообще лишней кажется.
                                        К основной части по lua претензий почти нет, кроме одной — где конкретный ответ на вопрос «почему lua?», а не другой ЯП в контексте сравнения с другими языками(а его нет, потому что сравнения то и не было :))?
                                          +1
                                          Я не автор статьи. Вы не туда зпостили. Думаю им действительно просто понравился Lua.
                                            0
                                            Ну это только последняя часть не к вам(и даже не думал писать с претензией конкретно к вам). Это я просто резюмировал свое отношение.
                                        +5
                                        Чересчур мощная интроспекция — python невозможно посадить в песочницу. Конечно, зависит от задачи, но в игровых скриптах возможность делать что-то такое мне видится нежелательной:

                                        [x for x in ().__class__.__base__.__subclasses__() if x.__name__ == 'Popen'][0]('calc.exe')
                                          +1
                                          python относительно легко «кастрируется», и всякие Popen и компанию можно легко вырезать, оставив безобидный сабсет функций, необходимый для скриптинга. Но это требует определенных знаний и времени. Собственно, как и реализация необходимого функционала для Lua. Так что тут зависит от ситуации, что кому нужно.
                                            0
                                            python относительно легко «кастрируется»
                                            Вот уж нет, совершенно точно не «легко». 10 лет назад один дядька сделал штуку, которая по задумке должна была закрывать возможность писать в файлы (github.com/tav/scripts/blob/master/safelite.py)
                                            и попросил найти в ней уязвимости. Конец немного предсказуем: tav.espians.com/a-challenge-to-break-python-security.html

                                            Ещё были попытки у pysandbox, но там также признали поражение:
                                            so many restrictions have needed to be added, pysandbox cannot be used for anything «more complex than evaluating '1+(2*3)'». Basic language constructs like «del dict[key]» have been removed because they can be used to modify __builtins__ and break out of the restricted namespace
                                            lwn.net/Articles/574215
                                            lwn.net/Articles/574323
                                            nedbatchelder.com/blog/201206/eval_really_is_dangerous.html

                                            В стандартной библиотеке был модуль rexec, но он также признан опасным и удалён в 3 версии
                                            docs.python.org/2/library/rexec.html

                                            PyPy пытались, но их sandbox «is not actively maintained. You will likely have to fix some issues yourself».

                                            Наверное, единственный работающий способ — переписать интерпретатор и где-то внизу перехватывать системные вызовы (ZeroVM Python), но это совсем не имеет смысла, проще уже в контейнер засунуть.
                                              –1
                                              Все эти попытки — это попытки изолировать код на Питоне от другого кода на Питоне. Но в условиях, когда любой код на Питоне считается недоверенным, и изолировать его нужно лишь от системы — достаточно почистить стандартную библиотеку, удалив лишнюю функциональность с концами.
                                        +1

                                        Поясните, пожалуйста, за интерпретируемость. В чём вообще смысл делать встраиваемые в игру языки интерпретируемыми? Игра ведь не сайт, она не должна грузиться за доли секунды, можно без проблем успеть скомпилировать и соптимизировать с -О3 все скрипты по ходу дела, может даже в отдельном треде, даже если они только что скачаны, а если не скачаны — то тем более, можно просто закэшировать результат компиляции(?) REPL для внутриигровой дебажной консольки вроде тоже ничему не противоречит(?)


                                        Дело в безопасности — произвольный бинарь сложнее контролировать? Дело просто в том что все компилируемые языки сложны? Будет ли полезен новый язык с такими свойствами — простой, контролируемый, легко встраиваемый, как lua, но при этом компилируемый? Или, может быть, ограниченная версия lua с чуть меньшей рефлексией но с компилируемостью?

                                          0
                                          Чтобы песочить моды. Смысл в том, чтобы можно было получить от стороннего разработчика код, и не бояться, что он добавит в игру синих орков, но заодно и стырит пароли из браузера. Скомпилированный кусок нельзя подключить, но ограничить в правах. Он будет иметь все права базового приложения.
                                            +2

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

                                              0

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

                                              +2
                                              Моды для iOS игр? Ну, не знаю)
                                              0
                                              на iOS/UWP не будет работать JIT (нельзя W и X одновременно на странице памяти).
                                              Плюс редактировать удобно. Могу представить себе тулинг в котором вы висите на условном бряке, и редактируете следующую строчку, отпускаете бряк и оно полетело дальше без каких либо приседаний.
                                              0
                                              У lua есть еще одно достоинство он маленький порядка 200кб.
                                              То что он написан на С позволяет собрать его под любую платформу.
                                              А что со www.squirrel-lang.org не так?
                                                +1
                                                А Lisp-подобные языки вы не рассматривали?
                                                  0
                                                  В реальности же придётся выбирать из двух подобных проектов — V8 и WebKit. И тот и другой имеют достаточно большие размеры

                                                  А как же Duktape или JerryScript, да и вообще можно здесь покопаться еще List of ECMAScript engines

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

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

                                                      0
                                                      Python, наверное, самый простой в освоении язык, что я знаю.

                                                      если так, то вы видимо не знаете Lua. проще языка я не встречал.
                                                      более того, я смог за пару вечеров освоить синтаксис С (после Java) и некоторые стандартные функции и писать на нем более-менее работающий код, а с питоном не смог, ибо слишком уж много сахара в питоне, который нужно знать (чтобы уметь прочитать чужой код).
                                                        0
                                                        А для скриптинга логики вы будете использовать кучу сахара и магию? Ведь не обязательно использовать все, что предоставляет язык, и скрипты в 99% случаев будут представлять подергивание api, предоставленного основным приложением. Если api простое — то не важно на чем его использовать, хоть на ассемблере. Если сложное — куча сахара это даже в плюс, так как с большой вероятностью поможет упростить api. Ведь в 100% случаев скрипты предоставляют свою собственную инфраструктуру, и магического от языка там ничего не останется, только магия за самим api, предоставляемого скриптам. Что вы думаете по этому поводу?
                                                          0
                                                          полностью согласен про API. но из этого вытекает вопрос: а зачем нужны все эти свистоперделки новомодных языков, если для скрипта достаточно нескольких базовых функций языка? остальное держится на API.
                                                          если API сделано реально хорошо, то можно писать и в императивном стиле (без использования ООП явного или неявного). примеры: медиа-библиотека allegro5 для C, игровой движок Love2D (Lua). там действительно хорошие API, название и действие функций если не знаешь, можно просто угадать.

                                                          просто есть скриптовые языки, в которых из коробки идут всякие возможности функциональных языков, явная поддержка ООП, только зачем это всё, если это всё не используется? ну или если надо, то можно реализовать через другие средства языка. в Lua это так. там есть минимум для реализации всего, что нужно. в Python напичкано всё подряд под предлогом «если тебе это не надо — не используй»
                                                            0
                                                            Я просто склоняюсь к мысли, что вообще не важно какой язык, lua, python, js, любую другую хрень можно прикрутить, основную роль будет играть api.

                                                            И тут уже критерии выбора могут быть другие — что lua может привнести в наш скриптовый мир, а что может принести другие языки(я имею в виду стандартную библиотеку языков, хоть api и решает, но иногда скриптовые языки впиливают не для программирования логики, а для расширения программы)? Сколько понадобится времени на поиск человека, который будет знать python + выучит наш api, и то же самое для lua, или js(по своему кругу общения не знаю никого кто бы писал на lua)?

                                                            пс: в частности про python, он не новомодный, в девяностых, кажется, начал разрабатыватся :)
                                                              0
                                                              выучить Lua — пара часов. выучить API — по времени это занимает почти всё, что отведено на вхождение в проект.
                                                              выучить Python — нифига не пара часов. основной синтаксис да, можно поднатаскать. но ох уж эти значащие отступы…

                                                              новомодность языка: это про то, что в него добавляют кучу всяких плюшек, которые изобретают/улучшают в новое время, а не когда-то давно.
                                                              Python старше Lua. но реализовать Lua в том виде, в котором он есть сейчас, можно было лет на 30 раньше. с Python такое не прокатило бы (наверное, я не то чтобы сильно компетентен в вопросах, связанных с Python)
                                                      0
                                                      Вот слегка устаревшее сравнение производительности встраиваемых языков: github.com/r-lyeh-archived/scriptorium
                                                        +2
                                                        Совсем забыл — есть ориентированный на встраивание язык TCL. Он древний, но вполне качественный. По эффективности — видел даже реализацию на JavaME.
                                                          +2
                                                          Спасибо. Понял, что главный аргумент — удобство встраивания языка в свой проект.
                                                            +1
                                                            О боже, есть даже Lua для JS в HTML! )
                                                            lua.vm.js

                                                            <script src="lua.vm.js"></script>
                                                            
                                                            <script type="text/lua">
                                                            js.global:alert('hello from Lua script tag in HTML!') -- this is Lua!
                                                            </script>
                                                            


                                                            ну все, держите меня семеро!
                                                              +4
                                                              github.com/vvanders/wasm_lua тут и семеро не удержат
                                                                0
                                                                Осталось прикрутить WebAssembly в качестве бекенда для LuaJIT — тогда уже ничто не удержит.
                                                            0
                                                            Если нам, для построения игрового движка, нужен какой-нибудь интерпретатор языка — мы можем найти множество таких интерпретаторов. В реальности же придётся выбирать из двух подобных проектов — V8 и WebKit
                                                            Классно.
                                                              0
                                                              Haxe, по сути, является не столько языком, сколько транс-компилятором в другие языки. А это не то, что нам нужно.

                                                              Кроме поддержки компиляции в натив через c++, под haxe с первого релиза была своя vm для байткода — neko
                                                              На смену ей сейчас пришел hashlink.haxe.org
                                                              Как использовать github.com/HaxeFoundation/hashlink/wiki/Embedding-HashLink

                                                              Хотя как по мне перспективнее всего встраивать js, так как в npm можно найти библиотеку для решения практически любой задачи.
                                                                0
                                                                В аргументации относительно скорости Lua вы незаслуженно обошли библиотеку FFI в LuaJIT, которая позволят выжать ещё больше скорости в критических местах и сильно упрощает использование C API внутри скриптов.
                                                                  +2

                                                                  У Lua есть одна проблема — версии 5.1, 5.2 и 5.3 между собой несовместимы ну просто никак. OpenResty работает на 5.1 и переходить не собирается.
                                                                  У Lua есть одно преимущество — язык реализует только то, что описано в стандарте С. Даже работы с файлами там нет. Всё остальное — через библиотеки. Как и C. Аналога libc на Lua правда нет.
                                                                  Ну и самое главное — это офигенный, сногсшибательный, гениальный дизайн, в котором всё направлено на удобство встраиваемости. Вот тут автор языка про это коротко рассказывает: https://queue.acm.org/detail.cfm?id=1983083

                                                                    0

                                                                    5.1 и 5.2 между собой совместимы (в 5.2 некоторые методы работы с таблицами депрецированные в 5.1 ещё не удалены, а в 5.3 уже удалены).


                                                                    Вот тут разница. В синтаксисе языка только добавления. Естественно код 5.2 с метаметодами в 5.1 работать не будет. Но код 5.1 будет работать в 5.2.


                                                                    A LuaJIT поддерживает диалекты 5.1/5.2. OpenResty нормально работает на LuaJIT-2.0.4/2.0.5 с поддержкой диалектов 5.1/5.2.


                                                                    Интересно, кому нужен Lua 5.3, без поддержки этого диалекта LuaJIT-ом?

                                                                    0
                                                                    Дело в том, что для наших целей нам часто нужны управляющие конструкции — ветвление и циклы, в то время как XML это декларативное описание.


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

                                                                    А механизм операторов условий описан в XSL.
                                                                      0
                                                                      спасибо за интересную статью

                                                                      Only users with full accounts can post comments. Log in, please.