Skip to content

RFC-033: Оператор рефлексии ^^ ​

Ссылки:

Резюме ​

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

Мотивация ​

Зачем нужна эта возможность? ​

  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 — обычный record type, возможно обычное сопоставление с образцом
  • [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/     │
│  (Оконча-   │    │ (Остаётся   │
│  тельный    │    │  на месте)  │
│   дизайн)   │    │             │
└─────────────┘    └─────────────┘