RFC-033: ^^ リフレクション演算子
参考:
概要
本文書では、型や値のメタデータにアクセスするためのリフレクションエントリポイントとして ^^ 演算子の導入を提案する。^^T は型 T の静的メタデータオブジェクトを返し、^^obj は値 obj の動的型メタデータを返す。メタデータオブジェクトは通常の record type であり、名前、パラメータ、フィールドなどの情報を含み、コンパイル時とランタイムの両方で使用できる。
動機
なぜこの機能が必要なのか?
- シリアライズ/デシリアライズ:型のフィールド情報にアクセスし、シリアライズコードを自動生成する必要がある
- コンパイル時メタプログラミング:コンパイル時に型構造にアクセスし、コード生成や制約検証を行う必要がある
- ランタイムデバッグ/ツール:ランタイムで型情報を出力し、デバッグを補助する必要がある
- ランタイム型チェック:「obj は何型か?」のような型関係をランタイムで判定する必要がある
現状の問題点
現在の YaoXiang にはリフレクションメカニズムがなく、コンパイル時またはランタイムで型のメタデータにアクセスできない。.name、.fields を直接使用して型メタデータにアクセスすると、ユーザー定義のフィールドと衝突する:
yaoxiang
Person: Type = { name: String, age: Int }
# Person.name は型メタデータの名前か、それともフィールド name か?
# これは解析の困難と意味の混乱を引き起こす通常のフィールドの名前空間を侵さない型メタデータアクセス構文が必要である。
提案
基本設計
通常のコードとメタデータクエリを明確に区別するリフレクションエントリポイントとして ^^ 演算子を導入する。
2 つの使用方法:
- 静的リフレクション(型に作用):
^^Tは型Tの静的メタデータオブジェクトを返す - 動的リフレクション(値に作用):
^^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より 1 階層上位 - ジェネリクスとの相互作用:
^^Listと^^List(Int)の両方がサポートされる - 関数との相互作用:
^^addは関数のメタデータ(引数と戻り型を含む)を返す - 精化型との相互作用:
^^Positiveは精化型のメタデータ(精化式を含む)を返す
ランタイム動作
コンパイル時リフレクション:
^^Tはコンパイル時に完全に評価され、結果は定数としてインライン化される- 精化式はコンパイル時に利用可能
ランタイムリフレクション:
- デフォルトでは無効で、ゼロオーバーヘッド
--enable-runtime-reflectionコンパイルオプションで有効化- 有効化後、
^^objは動的型メタデータを返す - 精化式はランタイムで
Noneに消去される
オンデマンド生成 + treeshake:
^^が実際に使用される型のみメタデータが生成される- 参照されない型はメタデータが生成されない(treeshake)
コンパイラの修正
- 字句解析器:
^^を単一のトークンとして認識 - 構文解析器:
^^前置式のルールを追加 - 型システム:
TypeMeta、ParamMeta、FieldMetaの型定義を追加 - 型検査器:各型に対してメタデータインスタンスを生成
- コンパイル時エバリュエータ:
^^Tのコンパイル時評価をサポート - ランタイム(オプション):リフレクション対象の型に対して RTTI を生成
後方互換性
- ✅ 既存構文への影響なし:
^^は新演算子であり、既存構文と衝突しない - ✅ 既存型への影響なし:すべての型が自動的に
^^をサポート - ✅ 既存関数への影響なし:関数は
^^を使用できるが、必須ではない - ✅ コンパイル時述語への影響なし:
^^Tは述語内で通常の内容と同様に動作 - ✅ ランタイムへの影響なし:ランタイムリフレクションはデフォルトで無効、ゼロオーバーヘッド
トレードオフ
利点
- 統一性:関数、ジェネリクス、精化型を統一的に処理
- ゼロオーバーヘッド:コンパイル時リフレクションは完全に消去され、ランタイムリフレクションはオプション
- 既存システムとの統合:コンパイル時述語(RFC-027)とシームレスに統合
- 簡潔さ:
^^は純粋な記号であり、ユーザー定義の識別子と衝突しない - オンデマンド生成:treeshake 最適化により、未使用の型はゼロオーバーヘッド
欠点
- 学習曲線:
^^のセマンティクスとメタデータ構造を理解する必要がある - ランタイムオーバーヘッド:ランタイムリフレクションを有効にするとメモリオーバーヘッドが増加(インスタンスごとに 1 ポインタ)
- 実装の複雑さ:コンパイラの複数のコンポーネントを修正する必要がある
代替案
| 案 | 採用しない理由 |
|---|---|
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/ │
│ (正式設計) │ │ (元の場所) │
└─────────────┘ └─────────────┘