понедельник, 11 ноября 2013 г.

На полях: RTTI для статики

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

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

5 комментариев:

  1. А в чём проблема? RTTI нужен только при передаче полиморфных параметров (в остальных случаях тип известен на этапе компиляции), а они всегда передаются по ссылке (либо это объект, либо boxed примитив). Ничто не мешает при выделении памяти под объект/боксинге положить туда ещё и указатель на дескриптор типа (всё равно там лежит ещё и длина области памяти, например).

    Т.е. выходит код типа

    struct object_header{
    size_t size;
    type_t *rtti;
    ... // тут может быть прочий хлам, счётчик ссылок, например.
    };

    object_t *new_object(type_t *type, ...){
    struct object_header *ptr = malloc(type->getSize() + sizeof(struct object_header));
    ptr -> size = type->getSize();
    ptr->rtti = type;
    ...
    return (object_t*)((intptr_t)ptr + sizeof(object_header));
    }

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

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

    ОтветитьУдалить
    Ответы
    1. Я тут размышлял вот на какую тему — язык, который одновременно может использоваться как достаточно низкоуровневый, так и как полностью высокоуровневый. И тут возникает проблема — высшие типы (объекты, умные указатели и т.д.) и типы примитивные — это как бы принципиально разные сущности, тогда как я искал модель, где высшие типы плавно расширяют примитивы. Т.е. суть в том, чтобы иметь возможность с реальными примитивами работать как с классами, а не маяться боксингом (это штука неплохая, но я о другой задаче думал).

      В общем, это размышлизм об универсальном языке. С полиморфизмом уровня параметров...

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

      Удалить
    2. PS. Боксинг, в принципе, решает ту же задачу, но что-то мне кажется, вычислительный оверхед у него поболе будет.

      Удалить
    3. Ну вот в C# (и вообще в языках для CLR) примитивные типы - частный случай типов-значений (value types), с методами и пропертями (но без возможности наследования, ес-сно).

      Но это, конечно, не для низкого уровня.

      Если говорить о дженерик-алгоритмах, то их, строго говоря, зачастую можно сделать, имея лишь указатели на функции. См. qsort в стандартной библиотеке C.

      Но параметрический полиморфизм лучше, конечно. Причём если его делать без (а) боксинга, как в Java (тормоза) и (б) динамической генерации специализированного кода, как в .NET (ибо рантайм толстый), то остаются только макросы (типа шаблонов в C++ и D).

      Вообще, D тут образцовый вариант, т.к. в нём можно и функции вызывать как методы (unified function call syntax, UFCS), т.е. эмулировать методы на примитивных типах (в С# тоже можно, но с дженериками это не поможет).

      Удалить
    4. То-то и оно, что это не макросы получаются, а куда более контролируемая штука. И с кодогенерацией, по возможности, при определении, а не при специализации. Т.е. generic-код можно будет и динамически линковать.

      Удалить