ADR-0008: use導入構文とreflectionベースextern解決の採用
This content is not available in your language yet.
Status
Section titled “Status”Accepted (partially superseded by ADR-0017)
ADR-0017 supersedes the use resolution rules in this ADR. In particular,
use UnityEngine;, use UnityEngine.Debug;, use UnityEngine.Debug.Log;,
use VRC.SDKBase.VRCPlayerApi;, and use System; are no longer external API
imports. use no longer falls back to CLR namespaces, CLR types, static CLR
methods, the extern catalog, or the legacy Debug -> UnityEngine.Debug
compatibility symbol. External APIs are resolved only by the extern keyword.
The reflection catalog, Udon-exposed filtering, extern-signature formatting,
rejected-candidate tracking, overload selection, and in-memory caching decisions
remain active and are reused by ADR-0016’s extern expressions.
Context
Section titled “Context”Sobakasu は Udon-first の言語であり、C# 互換そのものを目的にしない。 一方で Unity / VRC / TMPro / System 由来 API を扱うためには、コンパイル時に名前空間・型・静的関数を安全に導入し、最終的に Udon extern として解決できる呼び出しだけを採用する必要がある。
既存実装では Debug.Log のような一部 API を hardcoded な表で扱っており、次の問題があった。
- frontend と backend の責務境界よりも、特定 API の知識が実装に埋め込まれやすい
- import のような compile-time 名前解決機構がない
- reflection で候補を見つける設計になっておらず、将来の拡張性が低い
- Udon で本当に解決可能な extern だけを採用する判定が設計上明確でない
Sobakasu では runtime 機能としての module system を今すぐ導入するのではなく、Binder に閉じた compile-time 名前解決として use を成立させる必要がある。
Decision
Section titled “Decision”Sobakasu v1 では、compile-time only の use 導入構文と、reflection ベースの extern candidate discovery を採用する。
use は runtime 効果を持たず、Binder の名前解決にのみ影響する。
path は . 区切りで解釈し、v1 で導入対象にできるのは 名前空間 / 型 / 静的関数 のみとする。
v1 のサポート構文は以下に限定する。
use UnityEngine;use UnityEngine.Debug;use UnityEngine.Debug.Log;use UnityEngine.Debug as D;use UnityEngine.Debug.Log as log;use は top-level member としてパースし、Binder はファイル全体の use を先に収集して order-independent に扱う。
Binder の名前解決優先順位は以下とする。
- ローカル / パラメータ
use ... as aliasによる alias 導入useによる direct importuseによる namespace import を起点にした部分解決- グローバル名前空間
- 互換維持のための限定的 fallback
互換維持のための fallback は Debug -> UnityEngine.Debug のみを残し、広い implicit import は採用しない。
extern 候補の発見は compile-time / Editor domain 側で reflection ベースに行う。 ただし、reflection で見つかった任意の CLR public method をそのまま callable にする設計は採用しない。 reflection は candidate discovery にのみ使い、Binder はその候補の中から Udon extern として解決可能なものだけを callable として選択する。
候補モデルは少なくとも以下の情報を持つ。
- declaring type
- method name
- parameter CLR types
- return CLR type
- computed extern signature
- Udon exposed かどうか
reflection で見つけた候補のうち、Udon extern として解決可能なものだけを ExternMethodSymbol として採用する。
reflection 上は存在しても Udon extern として表現・解決できない候補は rejected candidate として保持し、呼び出し時に明示的診断を出す。
extern 解決責務は backend ではなく Binder に置く。 backend は Binder が確定した extern signature を emit するだけにする。
overload 解決は v1 では保守的に行う。
- exact match を最優先する
- 既存 primitive conversion policy に沿う widening のみを考慮する
- extern call applicability のために internal な
System.Objectcatch-all conversion を許可する - user-defined conversion は許可しない
- 曖昧な解決は失敗とし、明示的診断を出す
import collision も暗黙優先しない。 alias 衝突、import による曖昧参照、candidate 不在、rejected-only、overload ambiguity はすべて診断として可視化する。
reflection 結果は毎回フルスキャンせず、Editor domain 内でキャッシュ可能な構造を採用する。 v1 では in-memory cache のみを採用し、disk cache は導入しない。
v1 で見送るものは以下とする。
- glob import
- nested import
{}による grouping import*- relative import
- ユーザー定義 module import
- namespace alias
- property / field import
- instance member import
- 拡張メソッド
- 高度な generic binding
Alternatives
Section titled “Alternatives”-
hardcoded extern table を拡張し続ける 特定 API の最小実装としては簡単だが、対象拡張のたびに compiler 実装へ知識が埋まり、保守性が低い。
-
reflection で見つけた public CLR method をそのまま callable にする 実装は単純になるが、Udon で実際に extern として解決できる保証がなく、安全側に倒せない。
-
backend で最後に extern 解決する frontend / backend の責務分離が崩れ、曖昧解決や失敗が後段まで遅延する。
-
C# と同等の import / using 解決を再現する v1 の小さな文法・Binder 実装に対して過剰であり、Sobakasu の Udon-first 方針とも一致しない。
Rationale
Section titled “Rationale”この設計は、Rust 風の導入宣言という使い勝手を取り入れつつ、Sobakasu を C# clone にしないための境界を明確にする。
use を Binder 専用の compile-time 機構に限定することで、runtime semantics を増やさずに名前解決だけを拡張できる。
また、reflection と Udon exposed filtering を分離することで、「見つかった」ことと「呼べる」ことを同一視しない安全な設計になる。
extern を Binder で確定させることで、曖昧さや衝突を早期に検出でき、backend は選択済み signature の emission に集中できる。 これは既存 ADR の frontend / backend 分離方針とも整合する。
Consequences
Section titled “Consequences”Positive
Section titled “Positive”useにより namespace / type / static function の compile-time 導入が可能になるDebug.Log("Hello")やlog("Hello")のような短い呼び出しを安全に解決できる- reflection ベースの候補発見により hardcoded API 表の中核依存を減らせる
- Udon extern として本当に解決可能な候補だけを callable にできる
- Binder で曖昧さと衝突を確定できるため、backend が単純化する
Negative
Section titled “Negative”- Editor domain での reflection catalog 構築コストが発生する
- v1 では namespace alias や property / field / instance member import を扱えない
- overload 解決は保守的であり、C# と同じ解決結果にはならない
- cache は in-memory のみで、domain reload ごとの再構築は残る