А в чём проблема? RTTI нужен только при передаче полиморфных параметров (в остальных случаях тип известен на этапе компиляции), а они всегда передаются по ссылке (либо это объект, либо boxed примитив). Ничто не мешает при выделении памяти под объект/боксинге положить туда ещё и указатель на дескриптор типа (всё равно там лежит ещё и длина области памяти, например).
Т.е. выходит код типа
struct object_header{ size_t size; type_t *rtti; ... // тут может быть прочий хлам, счётчик ссылок, например. };
Я тут размышлял вот на какую тему — язык, который одновременно может использоваться как достаточно низкоуровневый, так и как полностью высокоуровневый. И тут возникает проблема — высшие типы (объекты, умные указатели и т.д.) и типы примитивные — это как бы принципиально разные сущности, тогда как я искал модель, где высшие типы плавно расширяют примитивы. Т.е. суть в том, чтобы иметь возможность с реальными примитивами работать как с классами, а не маяться боксингом (это штука неплохая, но я о другой задаче думал).
В общем, это размышлизм об универсальном языке. С полиморфизмом уровня параметров...
Например, чтобы один раз написанная функция sort могла обрабатывать в т.ч. и массивы примитивных типов, лишь бы на типе был задан порядок.
Ну вот в C# (и вообще в языках для CLR) примитивные типы - частный случай типов-значений (value types), с методами и пропертями (но без возможности наследования, ес-сно).
Но это, конечно, не для низкого уровня.
Если говорить о дженерик-алгоритмах, то их, строго говоря, зачастую можно сделать, имея лишь указатели на функции. См. qsort в стандартной библиотеке C.
Но параметрический полиморфизм лучше, конечно. Причём если его делать без (а) боксинга, как в Java (тормоза) и (б) динамической генерации специализированного кода, как в .NET (ибо рантайм толстый), то остаются только макросы (типа шаблонов в C++ и D).
Вообще, D тут образцовый вариант, т.к. в нём можно и функции вызывать как методы (unified function call syntax, UFCS), т.е. эмулировать методы на примитивных типах (в С# тоже можно, но с дженериками это не поможет).
То-то и оно, что это не макросы получаются, а куда более контролируемая штука. И с кодогенерацией, по возможности, при определении, а не при специализации. Т.е. generic-код можно будет и динамически линковать.
А в чём проблема? 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 не любят использовать, когда даже единственный экземпляр каждого типа стоит слишком дорого, но это же не твой сценарий.
Я тут размышлял вот на какую тему — язык, который одновременно может использоваться как достаточно низкоуровневый, так и как полностью высокоуровневый. И тут возникает проблема — высшие типы (объекты, умные указатели и т.д.) и типы примитивные — это как бы принципиально разные сущности, тогда как я искал модель, где высшие типы плавно расширяют примитивы. Т.е. суть в том, чтобы иметь возможность с реальными примитивами работать как с классами, а не маяться боксингом (это штука неплохая, но я о другой задаче думал).
УдалитьВ общем, это размышлизм об универсальном языке. С полиморфизмом уровня параметров...
Например, чтобы один раз написанная функция sort могла обрабатывать в т.ч. и массивы примитивных типов, лишь бы на типе был задан порядок.
PS. Боксинг, в принципе, решает ту же задачу, но что-то мне кажется, вычислительный оверхед у него поболе будет.
УдалитьНу вот в C# (и вообще в языках для CLR) примитивные типы - частный случай типов-значений (value types), с методами и пропертями (но без возможности наследования, ес-сно).
УдалитьНо это, конечно, не для низкого уровня.
Если говорить о дженерик-алгоритмах, то их, строго говоря, зачастую можно сделать, имея лишь указатели на функции. См. qsort в стандартной библиотеке C.
Но параметрический полиморфизм лучше, конечно. Причём если его делать без (а) боксинга, как в Java (тормоза) и (б) динамической генерации специализированного кода, как в .NET (ибо рантайм толстый), то остаются только макросы (типа шаблонов в C++ и D).
Вообще, D тут образцовый вариант, т.к. в нём можно и функции вызывать как методы (unified function call syntax, UFCS), т.е. эмулировать методы на примитивных типах (в С# тоже можно, но с дженериками это не поможет).
То-то и оно, что это не макросы получаются, а куда более контролируемая штука. И с кодогенерацией, по возможности, при определении, а не при специализации. Т.е. generic-код можно будет и динамически линковать.
Удалить