Skip to content

RFC-033: Оператор отражения ^^

Справочные материалы:

Краткое описание

В данном документе предлагается ввести оператор ^^ в качестве точки входа для рефлексии, позволяющей получать метаданные типов и значений. ^^T возвращает статический объект метаданных типа T, а ^^obj возвращает динамические метаданные типа значения obj. Объект метаданных представляет собой обычный тип записи, содержащий информацию о имени, параметрах, полях и т.д., и может использоваться как во время компиляции, так и во время выполнения.

Мотивация

Зачем нужна эта функциональность?

  1. Сериализация/десериализация: требуется доступ к информации о полях типа для автоматической генерации кода сериализации
  2. Метапрограммирование во время компиляции: требуется доступ к структуре типов во время компиляции для генерации кода или проверки ограничений
  3. Отладка/инструменты во время выполнения: требуется вывод информации о типах во время выполнения для помощи в отладке
  4. Проверка типов во время выполнения: требуется определение отношений типов во время выполнения, например, «какого типа obj?»

Текущие проблемы

В настоящее время YaoXiang не имеет механизма рефлексии и не позволяет получать метаданные типов ни во время компиляции, ни во время выполнения. Если напрямую использовать .name, .fields для доступа к метаданным типа, это приведёт к конфликту с пользовательскими полями:

yaoxiang
Person: Type = { name: String, age: Int }

# Если Person.name — это имя метаданных типа или поле name?
# Это приведёт к сложностям разбора и семантической неоднозначности

Необходим синтаксис, не затрагивающий обычное пространство имён полей, для доступа к метаданным типа.

Предложение

Основной дизайн

Вводится оператор ^^ в качестве точки входа для рефлексии, чётко разделяющий обычный код и запросы метаданных.

Два варианта использования:

  1. Статическая рефлексия (применяется к типам): ^^T возвращает статический объект метаданных типа T
  2. Динамическая рефлексия (применяется к значениям): ^^obj возвращает динамические метаданные типа значения obj

Структура метаданных:

yaoxiang
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.

Примеры

Базовое использование

yaoxiang
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"

Обобщённые типы

yaoxiang
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)         # []

Функции

yaoxiang
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

Уточнённые типы

yaoxiang
Positive: (x: Int) -> Type = { x > 0 }

# Во время компиляции: refinement имеет значение Some(Expr)
meta = ^^Positive
print(meta.name)           # "Positive"
print(meta.refinement)     # Some(AST(x > 0))

# Во время выполнения: refinement имеет значение None (стирание)

Использование в предикатах времени компиляции

yaoxiang
# Проверка наличия полей у типа
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  # ❌ Проверка не пройдена

Пример сериализации

yaoxiang
# Чистая функция времени компиляции: генерация 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)

Изменения в компиляторе

  1. Лексический анализатор: распознавание ^^ как единого токена
  2. Синтаксический анализатор: добавление правила для выражения с префиксом ^^
  3. Система типов: добавление определений типов TypeMeta, ParamMeta, FieldMeta
  4. Проверка типов: генерация экземпляра метаданных для каждого типа
  5. Вычислитель времени компиляции: поддержка вычисления ^^T во время компиляции
  6. Время выполнения (опционально): генерация RTTI для отражаемых типов

Обратная совместимость

  • ✅ Существующий синтаксис не затрагивается: ^^ — новый оператор, не конфликтующий с существующим синтаксисом
  • ✅ Существующие типы не затрагиваются: все типы автоматически поддерживают ^^
  • ✅ Существующие функции не затрагиваются: функции могут использовать ^^, но не обязаны
  • ✅ Предикаты времени компиляции не затрагиваются: ^^T в предикатах ведёт себя так же, как обычное содержимое
  • ✅ Время выполнения не затрагивается: рефлексия времени выполнения отключена по умолчанию, нулевые накладные расходы

Компромиссы

Преимущества

  • Единообразие: функции, обобщения, уточнённые типы обрабатываются унифицированно
  • Нулевые накладные расходы: рефлексия времени компиляции полностью стирается, рефлексия времени выполнения опциональна
  • Интеграция с существующими системами: бесшовная интеграция с предикатами времени компиляции (RFC-027)
  • Простота: ^^ — чистый символ, не конфликтующий с пользовательскими идентификаторами
  • Генерация по требованию: оптимизация treeshake, нулевые накладные расходы для неиспользуемых типов

Недостатки

  • Кривая обучения: необходимо понимать семантику ^^ и структуру метаданных
  • Накладные расходы во время выполнения: при включении рефлексии времени выполнения увеличиваются затраты памяти (один указатель на каждый экземпляр)
  • Сложность реализации: требуется модификация нескольких компонентов компилятора

Альтернативные решения

РешениеПочему не выбрано
Функция reflect(T)Добавляет лишний идентификатор в область видимости, может быть перекрыт пользователем
Функция type_info(T)То же
Один оператор ^Может конфликтовать с побитовыми операциями, в C++26 именно из-за конфликта и выбрали ^^
Символы @@, ## и др.Не имеют прецедентов, менее понятны, чем ^^

Этапы реализации

ЭтапСодержаниеЗависимости
Phase 1Разбор оператора ^^ времени компиляцииНет
Phase 2Определение структуры данных TypeMetaPhase 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 является обычным типом записи, можно использовать нормальное сопоставление с образцом
  • [x] Сравнение: поддерживается, объекты метаданных одного типа равны
  • [x] Затраты памяти: генерация по требованию + оптимизация treeshake

Приложения

Приложение A: Журнал архитектурных решений

РешениеВердиктДатаЗаписал
Область действия ^^Действует только на типы и значения, не на выражения2026-06-16晨煦
Цепной доступПоддерживается2026-06-16晨煦
Сопоставление с образцомПоддерживается2026-06-16晨煦
СравнениеПоддерживается, метаданные одного типа равны2026-06-16晨煦
Затраты памятиГенерация по требованию + treeshake2026-06-16晨煦
Взаимодействие с обобщениямиПоддерживаются как ^^List, так и ^^List(Int)2026-06-16晨煦
Хранение выражений уточненияДоступны во время компиляции, стираются в None во время выполнения2026-06-16晨煦

Приложение B: Глоссарий

ТерминОпределение
РефлексияСпособность доступа к метаданным типа во время выполнения или компиляции
МетаданныеИнформация, описывающая структуру типа (имя, поля, параметры и т.д.)
RTTIRun-Time Type Information — информация о типах времени выполнения
treeshakeОптимизация компилятора, удаление неиспользуемого кода
Уточнённый типТип с ограничивающими условиями, например Positive: (x: Int) -> Type = { x > 0 }

Список литературы


Жизненный цикл и судьба

┌─────────────┐
│   Черновик  │  ← Текущее состояние
└──────┬──────┘


┌─────────────┐
│ На рассмотрении │  ← Открыто для обсуждения сообщества и обратной связи
└──────┬──────┘

       ├──────────────────┐
       ▼                  ▼
┌─────────────┐    ┌─────────────┐
│   Принят    │    │   Отклонён  │
└──────┬──────┘    └──────┬──────┘
       │                  │
       ▼                  ▼
┌─────────────┐    ┌─────────────┐
│   accepted/ │    │    rfc/     │
│(официальный │    │ (оставлен   │
│   дизайн)   │    │   на месте) │
└─────────────┘    └─────────────┘