RFC-033: Оператор рефлексии ^^
Ссылки:
Резюме
Настоящий документ предлагает ввести оператор ^^ в качестве точки входа в рефлексию для получения метаданных типов и значений. ^^T возвращает объект статических метаданных типа T, а ^^obj возвращает метаданные динамического типа значения obj. Объекты метаданных являются обычными record type и содержат информацию об имени, параметрах, полях и т. д., доступную как на этапе компиляции, так и во время выполнения.
Мотивация
Зачем нужна эта возможность?
- Сериализация/десериализация: требуется доступ к информации о полях типа для автоматической генерации кода сериализации
- Метапрограммирование на этапе компиляции: требуется доступ к структуре типа на этапе компиляции для генерации кода или проверки ограничений
- Отладка и инструментарий во время выполнения: требуется возможность выводить информацию о типе во время выполнения для помощи в отладке
- Проверка типов во время выполнения: требуется возможность определять отношения типов во время выполнения, например «какого типа obj?»
Текущая проблема
В текущей версии YaoXiang отсутствует механизм рефлексии, что делает невозможным доступ к метаданным типов как на этапе компиляции, так и во время выполнения. При попытке прямого использования .name, .fields для доступа к метаданным типа возникает конфликт с пользовательскими полями:
Person: Type = { name: String, age: Int }
# Если Person.name — это имя в метаданных типа или поле name?
# Это вызывает трудности разбора и семантическую путаницуТребуется синтаксис, который не вторгается в пространство имён обычных полей для доступа к метаданным типа.
Предложение
Основной замысел
Предлагается ввести оператор ^^ в качестве точки входа в рефлексию, чётко разделяющий обычный код и запросы метаданных.
Два варианта использования:
- Статическая рефлексия (применяется к типу):
^^Tвозвращает объект статических метаданных типаT - Динамическая рефлексия (применяется к значению):
^^objвозвращает метаданные динамического типа значенияobj
Структура метаданных:
TypeMeta: Type = {
name: String,
params: Array(ParamMeta),
fields: Array(FieldMeta),
return_type: Type,
refinement: Option(Expr) # На этапе компиляции Some(Expr), во время выполнения None
}
ParamMeta: Type = {
name: String,
type: Type
}
FieldMeta: Type = {
name: String,
type: Type
}Иерархия вселенных: если T: Type_n, то ^^T: Type_{n+1}, что соответствует стандартному правилу повышения уровня вселенной в теории типов.
Приоритет: ^^ — унарный префиксный оператор с наивысшим приоритетом. ^^T.name эквивалентно (^^T).name.
Примеры
Базовое использование
Point: Type = { x: Float, y: Float }
# Статическая рефлексия
meta = ^^Point
print(meta.name) # "Point"
print(meta.fields.len) # 2
print(meta.fields[0].name) # "x"
print(fields[0].type) # Float
# Динамическая рефлексия (требуется включённая рефлексия времени выполнения)
obj = Point(1.0, 2.0)
meta = ^^obj
print(meta.name) # "Point"Обобщённые типы
List: (T: Type) -> Type = { data: Array(T), length: Int }
# Рефлексия самого обобщённого типа
meta = ^^List
print(meta.name) # "List"
print(meta.params) # [{ name: "T", type: Type }]
# Рефлексия конкретного инстанцированного типа
meta = ^^List(Int)
print(meta.name) # "List(Int)"
print(meta.params) # []Функции
add: (a: Int, b: Int) -> Int = a + b
meta = ^^add
print(meta.name) # "add"
print(meta.params) # [{ name: "a", type: Int }, { name: "b", type: Int }]
print(meta.return_type) # IntУточнённые типы
Positive: (x: Int) -> Type = { x > 0 }
# На этапе компиляции: refinement равно Some(Expr)
meta = ^^Positive
print(meta.name) # "Positive"
print(meta.refinement) # Some(AST(x > 0))
# Во время выполнения: refinement равно None (стирается)Использование в предикатах времени компиляции
# Проверка наличия полей у типа
HasFields: (T: Type) -> Type = { ^^T.fields.len > 0 }
# Проверка типа поля
HasFloatField: (T: Type) -> Type = {
exists field in ^^T.fields: field.type == Float
}
# Использование
obj: HasFields(Point) = Point(1.0, 2.0) # ✅ Проверка пройдена
# obj: HasFields(Int) = 42 # ❌ Проверка не пройденаПример сериализации
# Чистая функция времени компиляции: генерация JSON-строки
to_json: (T: Type) -> ((obj: T) -> String) = {
meta = ^^T
parts: Array(String) = []
for field in meta.fields {
# Генерация кода доступа к полю на этапе компиляции
parts.push("\"${field.name}\": ${obj.${field.name}}")
}
return "{" + parts.join(", ") + "}"
}
# Использование
point_to_json = to_json(Point)
print(point_to_json(Point(1.0, 2.0))) # '{"x": 1.0, "y": 2.0}'Синтаксические изменения
| До | После |
|---|---|
| Нет механизма рефлексии | ^^T для получения метаданных типа |
| Нет механизма рефлексии | ^^obj для получения метаданных динамического типа значения |
Детальное проектирование
Влияние на систему типов
- Новые типы:
TypeMeta,ParamMeta,FieldMeta - Иерархия вселенных: тип, возвращаемый
^^T, на один уровень выше, чемT - Взаимодействие с обобщениями: поддерживаются и
^^List, и^^List(Int) - Взаимодействие с функциями:
^^addвозвращает метаданные функции (включая параметры и тип возврата) - Взаимодействие с уточнёнными типами:
^^Positiveвозвращает метаданные уточнённого типа (включая выражение уточнения)
Поведение во время выполнения
Рефлексия на этапе компиляции:
^^Tполностью вычисляется на этапе компиляции, результат встраивается как константа- Выражение уточнения доступно на этапе компиляции
Рефлексия во время выполнения:
- По умолчанию отключена, нулевые накладные расходы
- Включается опцией компилятора
--enable-runtime-reflection - При включении
^^objвозвращает метаданные динамического типа - Выражение уточнения стирается в
Noneво время выполнения
Генерация по запросу + treeshake:
- Метаданные генерируются только для тех типов, в которых фактически используется
^^ - Для неиспользуемых типов метаданные не генерируются (treeshake)
Изменения в компиляторе
- Лексер: распознавание
^^как единого токена - Парсер: добавление правила для префиксного выражения
^^ - Система типов: определение типов
TypeMeta,ParamMeta,FieldMeta - Средство проверки типов: генерация экземпляра метаданных для каждого типа
- Вычислитель времени компиляции: поддержка вычисления
^^Tна этапе компиляции - Среда выполнения (опционально): генерация RTTI для типов, к которым применяется рефлексия
Обратная совместимость
- ✅ Существующий синтаксис не затрагивается:
^^— новый оператор, не конфликтующий с существующим синтаксисом - ✅ Существующие типы не затрагиваются: все типы автоматически поддерживают
^^ - ✅ Существующие функции не затрагиваются: функции могут, но не обязаны использовать
^^ - ✅ Предикаты времени компиляции не затрагиваются:
^^Tв предикатах ведёт себя как обычное содержимое - ✅ Среда выполнения не затрагивается: рефлексия времени выполнения по умолчанию отключена, нулевые накладные расходы
Компромиссы
Преимущества
- Единообразие: единая обработка функций, обобщений, уточнённых типов
- Нулевые накладные расходы: рефлексия времени компиляции полностью стирается, рефлексия времени выполнения опциональна
- Интеграция с существующей системой: бесшовная интеграция с предикатами времени компиляции (RFC-027)
- Краткость:
^^— чистый символ, не конфликтующий с пользовательскими идентификаторами - Генерация по запросу: оптимизация treeshake, нулевые накладные расходы для неиспользуемых типов
Недостатки
- Кривая обучения: необходимо понимать семантику
^^и структуру метаданных - Накладные расходы во время выполнения: включение рефлексии времени выполнения увеличивает расход памяти (один указатель на каждый экземпляр)
- Сложность реализации: требуется модификация нескольких компонентов компилятора
Альтернативы
| Вариант | Почему не выбран |
|---|---|
Функция reflect(T) | Вводит дополнительный идентификатор в область видимости, может быть перекрыт пользователем |
Функция type_info(T) | Аналогично |
Одиночный оператор ^ | Возможен конфликт с побитовыми операциями; именно из-за конфликта C++26 выбрал ^^ |
Символы @@, ## и т. д. | Нет прецедента, ^^ легче объяснить |
Этапы реализации
| Этап | Содержание | Зависимость |
|---|---|---|
| Phase 1 | Разбор оператора ^^ времени компиляции | Нет |
| Phase 2 | Определение структур данных TypeMeta | Phase 1 |
| Phase 3 | Генерация метаданных на этапе компиляции | Phase 2 |
| Phase 4 | Поддержка рефлексии времени выполнения (опционально) | Phase 3 |
| Phase 5 | Интеграция с предикатами времени компиляции | Phase 3 |
Зависимости
Phase 1 (Разбор)
↓
Phase 2 (Структуры данных)
↓
Phase 3 (Метаданные времени компиляции)
↓
├────────────┐
↓ ↓
Phase 4 Phase 5
(Рефлексия (Предикаты времени
времени компиляции)
выполнения)Риски
- Конфликт при разборе:
^^может конфликтовать с существующим синтаксисом (анализ показывает отсутствие конфликтов) - Влияние на производительность: генерация метаданных времени компиляции может увеличить время компиляции (можно смягчить с помощью treeshake)
- Накладные расходы во время выполнения: включение рефлексии времени выполнения увеличивает расход памяти (смягчается генерацией по запросу)
Открытые вопросы
- [x] Область применения
^^: применяется только к типам и значениям, не к выражениям - [x] Цепочечный доступ: поддерживается, объект метаданных, возвращаемый
^^T, позволяет обычный доступ к атрибутам - [x] Сопоставление с образцом: поддерживается,
TypeMeta— обычный record type, возможно обычное сопоставление с образцом - [x] Сравнение: поддерживается, объекты метаданных одного типа равны
- [x] Накладные расходы по памяти: генерация по запросу + оптимизация treeshake
Приложения
Приложение A: Записи о проектных решениях
| Решение | Решение | Дата | Автор |
|---|---|---|---|
Область применения ^^ | Только к типам и значениям, не к выражениям | 2026-06-16 | Чэньсюй |
| Цепочечный доступ | Поддерживается | 2026-06-16 | Чэньсюй |
| Сопоставление с образцом | Поддерживается | 2026-06-16 | Чэньсюй |
| Сравнение | Поддерживается, метаданные одного типа равны | 2026-06-16 | Чэньсюй |
| Накладные расходы по памяти | Генерация по запросу + treeshake | 2026-06-16 | Чэньсюй |
| Взаимодействие с обобщениями | Поддерживаются и ^^List, и ^^List(Int) | 2026-06-16 | Чэньсюй |
| Хранение выражения уточнения | Доступно на этапе компиляции, стирается в None во время выполнения | 2026-06-16 | Чэньсюй |
Приложение B: Глоссарий
| Термин | Определение |
|---|---|
| Рефлексия | Возможность доступа к метаданным типа на этапе компиляции или во время выполнения |
| Метаданные | Информация, описывающая структуру типа (имя, поля, параметры и т. д.) |
| RTTI | Run-Time Type Information — информация о типе времени выполнения |
| treeshake | Оптимизация компилятора по удалению неиспользуемого кода |
| Уточнённый тип | Тип с условием-ограничением, например Positive: (x: Int) -> Type = { x > 0 } |
Ссылки
- RFC-010: Унифицированный синтаксис типов
- RFC-011: Проектирование системы обобщений
- RFC-027: Предикаты времени компиляции и унифицированная статическая верификация
- RFC-011a: Реализация интерфейсов и динамическая диспетчеризация
- Предложение по рефлексии в C++26
Жизненный цикл и судьба
┌─────────────┐
│ Черновик │ ← Текущее состояние
└──────┬──────┘
│
▼
┌─────────────┐
│ На рассмот- │ ← Открыто для обсуждения
│ рении │ сообществом и обратной связи
└──────┬──────┘
│
├──────────────────┐
▼ ▼
┌─────────────┐ ┌─────────────┐
│ Принято │ │ Отклонено │
└──────┬──────┘ └──────┬──────┘
│ │
▼ ▼
┌─────────────┐ ┌─────────────┐
│ accepted/ │ │ rfc/ │
│ (Оконча- │ │ (Остаётся │
│ тельный │ │ на месте) │
│ дизайн) │ │ │
└─────────────┘ └─────────────┘