RFC-033: ^^ リフレクション演算子
参考:
概要
本稿では、型と値のメタデータを取得するためのリフレクションエントリポイントとして ^^ 演算子の導入を提案する。^^T は型 T の静的メタデータオブジェクトを返し、^^obj は値 obj の動的型メタデータを返す。メタデータオブジェクトは name: String、params: Array(ParamMeta)、fields: Array(FieldMeta) などの情報を持つ通常の 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) ではなく ^^(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/ │
│ (正式設計) │ │ (元の位置を保持) │
└─────────────┘ └─────────────┘