Umka. Жизнь статической типизации в скриптовом языке



    В своё время посты на Хабре и Reddit о статически типизированном скриптовом языке Umka вызвали весьма активную дискуссию.

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

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

    Информация о типах во время исполнения программы (RTTI). Проект начинался с радикального отказа от хранения типов данных при исполнении программы. Вся информация о типах терялась после компиляции в байт-код виртуальной машины. В принципе, статическая типизация позволяет это сделать, а заодно избавляет от странных трюков вроде упаковки данных в NaN, к которой, например, прибегают создатели JavaScript и Wren ради увеличения быстродействия. Однако обнаружились два случая, в которых пришлось использовать RTTI:

    • Приведение интерфейсного типа данных к конкретному — прямой аналог «утверждения типа» (type assertion) в Go, а также, отчасти, оператора dynamic_cast в C++. Оно требуется и при сборке мусора, содержащегося в данных, приведённых к интерфейсному типу.
    • Сборка мусора, связанного с динамическими структурами данных вроде списков и деревьев.

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

    Пока полный набор тестов не готов, я могу поделиться лишь предварительными результатами замеров. В численных задачах (например, задаче многих тел) Umka надёжно опережает Python, а если в задаче активно используется цикл for, то Umka даёт выигрыш даже по сравнению с Wren, который позиционируется автором чуть ли не как самый быстрый скриптовый язык после LuaJIT. Наглядным примером служит перемножение больших матриц:


    Умножение матриц 400 x 400 (AMD A4-3300M @ 1.9 GHz, Windows 7)

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

    Задачи с интенсивной сборкой мусора (например, создание и обход двоичных деревьев) вызывают много сомнений по поводу эквивалентности сравниваемых алгоритмов. Например, известная реализация двоичных деревьев на Python возвращает содержимое узлов россыпью и выглядит так, будто в принципе допускает размещение всего дерева на стеке — вообще без использования кучи и сборки мусора. Однако она, по-видимому, требует динамической типизации и не может быть точно воспроизведена на Umka. Если же потребовать возвращать узлы в виде структур, как в Umka (а за неимением структур приходится требовать объекты), то быстродействие Python сразу же падает в 3-4 раза. Вариант на Umka вдвое отстаёт от первой реализации и вдвое опережает вторую. Какое сравнение корректнее — не знаю.

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


    Пример трёхмерной сцены, содержимое которой задаётся скриптом на Umka

    Обобщённые типы и функции (generics). Как только читатель улавливает сходство Umka с Go, пускай даже синтаксическое — следует вопрос о поддержке generic'ов. Работа в этом направлении пока не вышла из стадии обзора подходов. Конечно, хотелось бы воспользоваться предложениями разработчиков Go, однако сосуществование в их головах интерфейсов и «контрактов» всегда отпугивало, как странное дублирование понятий. К удивлению и радости, в только что вышедшей новой редакции черновика «контракты» исчезли — по тем же причинам, о которых размышлял и я. Пока generic'ов в Umka нет, остаётся пользоваться, как и в Go, пустыми интерфейсами interface{}.

    Документация. Полная спецификация Umka ещё в работе, но уже написана грамматика и расширен обзорный тур по основным возможностям языка.
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама

    Комментарии 9

      0
      Наконец, родился более реалистичный пример использования Umka по его основному назначению, т. е. как встраиваемого языка.
      На какой базовый ЯП (чтобы в него встраивать) ориентируетесь?
        0
        Сейчас это C/C++. Другие языки — при наличии совместимого ABI вызова динамических библиотек. Поскольку многие языки хотят так или иначе работать с DLL, это не должно быть препятствием.
          0
          Разумно… Может ваша шутка про интерес игроделов к скорости вашего ЯП не такая уж и шутка.

          Вы наверняка много знаете про проблемы и пути развития встраиваемых ЯП. В этом контексте кмк будет очень эффективно (и эффектно) делать пиар для Umka.
            0
            А кстати, как бы вы обозначили эти проблемы, помимо быстродействия? Для большинства программистов проблем, кажется, и вовсе нет, когда под рукой Lua/LuaJIT (с последним только та проблема, что Майк Полл перестал им заниматься).
              0

              Так что у вашего языка есть шанс: прикрутите MirJIT и будете вторым после LuaJIT (а это уже круто. Учитывая, какой противный язык Lua, многие мечтаю о вменяемой альтернативе).
              https://github.com/vnmakarov/mir

                0
                Интересный проект, не первый раз о нём слышу. Но беглый просмотр вызывает некоторые сомнения (поправьте, если я заблуждаюсь): документация скудная; нет разобранных примеров; нет готовых дистрибутивов в виде DLL; непонятно, откуда импортируются функции стандартной библиотеки C (нужно тянуть за собой libc/msvcrt?); непонятно, что делать с нетривиальными частями виртуальной машины — например, сборщиком мусора.
                +1
                Я не настоящий сварщик, поэтому просто читаю об этом 1, 2, 3, 4, 5
                  0
                  Спасибо, очень понравилась первая ссылка — взгляд на проблему с другой стороны баррикад. Хотя некоторые утверждения там весьма поверхностные:
                  Lua — это стековая машина, и там, на самом деле, просто нечему тормозить.
                  На самом деле, начиная с версии 5, Lua перешла от стековой машины к регистровой и получила от этого большой прирост быстродействия. У меня один и тот же численный алгоритм на Lua 5 работал в 2-3 раза быстрее, чем на Lua 4.
                  Добавим сюда всякие задержки на сборке мусора, поиску метода по цепочке наследования — и окажется, что тормозить там есть чему.
                    0
                    Да, это парадокс какой-то: вроде бы для целей встраиваемого ЯП скорость не должна быть критичной (обычно есть места вовне, где можно и поболее затормозить программу), но это и есть первый вопрос, который задают про эти ЯП ))

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

        Самое читаемое