ADR-0032: Add `maybe out` for Nullable Extern Output Parameters
This content is not available in your language yet.
Status
Section titled “Status”Accepted
Context
Section titled “Context”ADR-0026はsource-levelの不存在をcompiler専用型ではなく通常のgeneric enum Maybe<T>で表し、外部referenceのvalidity判定にはVRC.SDKBase.Utilities.IsValidを用いる方針を定めた。ADR-0030はこの方針を宣言的bindingのnormal returnへ適用するmaybe externを導入した。ADR-0031はCLR/Udonのref/out parameterをphysical ABI metadataとして保持し、通常returnとparameter宣言順のref/out outputをSobakasuのlogical returnへ投影する。
しかし、bool TryGet(out GameObject value)のように、normal returnとは独立してout valueがnullまたはinvalid referenceになり得るAPIを、logical return (bool, Maybe<GameObject>)として宣言する方法がない。raw outをすべて自動的にMaybe<T>へ変換すると、ADR-0026が維持するlow-level escape hatchを失い、physical overload selectionとlibrary policyも混同する。
Decision
Section titled “Decision”Extern ABI parameterにmaybe outを追加する
Section titled “Extern ABI parameterにmaybe outを追加する”ADR-0031の宣言的extern binding右辺に限り、次のparameter specificationを許可する。
fn try_get() -> (bool, Maybe<GameObject>) = extern External.TryGet( maybe out GameObject value, )maybeはこの位置だけで意味を持つcontextual keywordである。通常のfunction parameter、normal ABI parameter、refには導入しない。したがってmaybe ref、maybe T name、通常function parameterのmaybe outは不正とする。
Physical ABIとlogical output projectionを分離する
Section titled “Physical ABIとlogical output projectionを分離する”out Tとmaybe out Tは、どちらもphysical parameter mode/typeとしてはout Tである。maybeはoverload resolutionへ参加せず、同じCLR/Udon overloadを選択できる。Binderはphysical overloadを確定した後にlogical projectionを適用し、metadataで次を区別する。
PhysicalPassingMode: Normal | Ref | Out | InLogicalOutputProjection: Raw | Maybelogical outputは次のとおりである。
out T -> Tmaybe out T -> Maybe<T>normal returnを先頭に置き、その後へparameter宣言順のref/out outputを並べるADR-0031の規則は変更しない。refとoutを種類別に並べ替えない。output数の正規化も維持する。
0 outputs -> ()1 output -> T2+ outputs -> (T0, T1, ...)このためvoid Foo(maybe out GameObject value)のlogical returnはMaybe<GameObject>であり、(Maybe<GameObject>,)ではない。
既存のMaybe validity projectionを再利用する
Section titled “既存のMaybe validity projectionを再利用する”maybe out Tは、既存のmaybe externと同じ規則でvalidity check可能なreference-like external valueに限る。value type等へ適用した場合はBinder diagnosticとする。新しいnullable type分類は導入しない。
loweringはphysical out T temporaryを確保してextern callを一度だけ実行し、そのtemporaryをUtilities.IsValidとMaybe payloadの双方で再利用する。validならsingle-payload variant、invalidならunit variantを構築する。variantはvisibleなgeneric enum Maybe<T>の形状から、validity methodはextern catalogと既存resolverからBinderが解決する。
Maybe<T>はADR-0026どおり通常のgeneric payload enumであり、既存aggregate flatteningを用いる。Maybe専用runtime object、opcode、UASM signature文字列、variant名のbackend hard-code、backend-only nullability inferenceは追加しない。normal returnがboolであっても、その値とout valueのvalidityを結合する規則は設けない。
Alternatives
Section titled “Alternatives”- すべてのreference
outを自動的にMaybe<T>へ変換する。raw ABI accessを失い、将来のgenerator policyまでcompiler semanticsへ混在させるため採用しない。 out Maybe<T>としてphysical ABI型も変更する。実在するCLR/Udon overloadと一致しなくなるため採用しない。maybe refも同時に導入する。入力時と出力時のpresence semanticsを別途設計する必要があり、今回のnullable output projectionを越えるため採用しない。- normal returnの
boolをMaybetagとして使用する。API固有の成功条件とUnity/VRChat reference validityを誤って結合するため採用しない。
Rationale
Section titled “Rationale”physical mode/typeとlogical projectionを分離すれば、既存のreflection catalogとoverload resolverを唯一のphysical target選択経路として維持できる。BinderでMaybe enumとvalidity methodまで解決し、IR Lowererは解決済みprojectionを通常のcall、branch、aggregate constructionへ展開できるため、ADR-0003の責務分離も保たれる。
ADR-0026の通常のMaybe<T> policyとraw extern escape hatchを変更せず、ADR-0030のmaybe externを置き換えず、ADR-0031のref/out logical adaptationだけをparameter単位へ拡張する。
Consequences
Section titled “Consequences”Positive
Section titled “Positive”- nullableなextern
outをlogicalMaybe<T>として明示できる。 outとmaybe outは同じphysical overloadを使用する。- extern callは一度だけ実行され、out temporaryをvalidity判定とpayloadで共有する。
- 複数outputの宣言順とtuple flatteningを維持できる。
- backendへsource syntax、Maybe解決、nullable policyを持ち込まない。
Negative
Section titled “Negative”- ABI parameter metadataとloweringにparameter単位のprojection情報が増える。
maybe outにはvisibleな適切なMaybe<T>とcatalog-backedUtilities.IsValidが必要になる。- generatorがどのAPIを
maybe outにするかというpolicyは別途設計が必要であり、当面のdefault生成はrawoutのままとなる。
Non-goals
Section titled “Non-goals”maybe ref、T?、一般的なnullable reference type system- ownership、borrow、lifetime、通常functionの
ref/out - reference outputの自動nullable inferenceまたはpolicy configuration
- static classのtop-level function化、predicate命名変換、documentation URL生成