Generics — 0.0.18
Одна функция или структура может работать с разными типами и фиксированными вместимостями. Для используемых сочетаний компилятор создаёт конкретные реализации: мономорфизация не вводит runtime-диспетчеризацию или представление типов.
pub struct Pair<T, U> {
pub first: T
pub second: U
}
pub fn identity<T>(value: T) -> T : pure {
return move value
}
fn main() -> u32 {
pair = Pair<u32, u64>(42, 100)
return identity(pair.first) - 42
}
Типы и вместимость
pub struct Buffer<T: copyable, N: u32> {
pub data: [T; N]
}
pub fn filled<T: copyable, N: u32>(value: T) -> Buffer<T, N> {
return Buffer<T, N>([copy value; N])
}
filled<u8, 64>(7) и filled<u8, 4096>(7) создают разные специализации.
N — целое u32, известное при компиляции. Аргумент вместимости — литерал
(включая hex) или параметр внешнего generic-объявления. Выражения над
вместимостями и runtime-значения в аргументах типов пока не поддерживаются.
В теле функции N является значением типа u32.
[value; N] вычисляет value ровно один раз, затем создаёт N независимых
логических копий. Даже при N=0 эффекты и traps инициализатора сохраняются.
Элемент должен быть копируемым. Нулевой массив допустим; индексация вызывает trap.
Произвольный T не получает неявного нулевого значения или конструктора.
Компилятор выводит параметры из типов аргументов и ожидаемого результата,
если решение однозначно. Например, identity(42) использует u32, а
identity<u64>(42) задаёт контекст литералу явно. Вместимость может выводиться
из типа массива. Если данных недостаточно, нужны явные аргументы или аннотация.
Проверка после подстановки
Тело проверяется для каждой используемой специализации обычными правилами типизации, владения, заимствования и эффектов. Неиспользованное generic-тело не обязано подходить всем возможным типам; синтаксис и разрешение имён модулей проверяются независимо от использования.
copyableразрешает явныйcopy.implicit_copyразрешает обычное копирование значения при чтении привязки.- Без ограничения допустимые операции определяются после подстановки.
identity<File>может передать владение;copy Fileотвергается.increment<u8>(255)с теломreturn value + 1сохраняет обязательный trap.- Чистая функция не может скрыть
ioчерез generic-вызов.
При ошибке диагностика показывает цепочку специализаций и исходную операцию. Неудачная проверка прекращает компиляцию до выдачи исполняемого IR.
Модули и идентичность
Идентичность специализации состоит из канонического объявления, аргументов типов и значений вместимости. Повторный и ромбовидный импорт одного объявления не создаёт новых типов. Разные объявления с одинаковыми полями остаются разными.
Права доступа определяются модулем объявления generic-функции. Подстановка типа из другого модуля не открывает его приватные поля. Экспорт generic-типа также не экспортирует приватные поля или конструктор автоматически.
Рекурсия и пределы
Рекурсивный вызов той же специализации разрешён и использует кеш. Полиморфная рекурсия с другими аргументами в одной цепочке сейчас отклоняется, в том числе потенциально конечная: это консервативное ограничение прототипа. Предел — 256 специализаций на программу и 32 вложенных инстанцирования. Превышение даёт диагностику вместо бесконечного роста компилятора.
Generic-таблица
examples/tables/value_table.liza содержит Table<T,N> с приватными слотами
и обычные функции empty, get, add, edit, del.
examples/generic_table.liza показывает их применение к записям соединений.
Начальное значение передаётся явно:
var table = tables.value_table.empty<Connection, 64>(Connection(0, 0))
added = tables.value_table.add(move table, Connection(42, 1))
Таблица принимает только копируемые значения. Удаление инвалидирует ID; последнее поколение выводит слот из обращения. Освобождённый слот сохраняет недоступное через API значение до следующего заполнения. Это не коллекция ресурсов и не обещание стирания секретных данных.
Мономорфизация сохраняет прежний анализ переиспользования хранилища.
В проверенном цикле edit таблиц на 64/4096/16384 записи нет полных копий;
независимый входной снимок сохраняется. Начальная копия перед циклом допустима.
Это свойство проверенного тракта, а не гарантия отсутствия копирования у всех
обобщённых алгоритмов.
Traits, пользовательские специализации, generic-enum, связанные методы, вариативные параметры, отдельная компиляция и runtime generics пока не входят в язык. Дальнейшие коллекции требуют отдельного контракта памяти и ресурсов.