# 制約と default この章では、制約と `default` の意味を定義する。 ## 制約 制約は、値が満たすべき条件を表す。 ```dcdl Int String >= 1 <= 65535 /Hello! .*/ ``` 制約は `&` により合成できる。 ```dcdl Port = Int & >= 1 & <= 65535; NarrowedPort = Port & > 443; ``` 制約合成の意味は、すべての制約を同時に満たすことである。 ```text A & B = A と B の両方を満たす値または制約 ``` 矛盾する制約はエラーになる。 ```dcdl Int & String # エラー >= 10 & <= 5 # エラーになりうる ``` ## 組み込み制約 最小の組み込み制約は以下である。 ```dcdl String Int Float Bool ``` 追加の述語制約はライブラリまたは組み込みとして提供できる。 ```dcdl IPv4Address ``` ## 正規表現制約 正規表現リテラルは文字列制約として使える候補である。 ```dcdl Host = /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/; ``` ただし、組み込み向け実装では正規表現エンジンを optional feature にできる。 軽量実装では代表的な制約を組み込み述語として提供してもよい。 ```dcdl Host = IPv4Address; ``` ## default `default` は制約ではない。 `default` は、最終評価時に明示値が存在しない場合だけ使われる fallback 値である。 ```dcdl port = NarrowedPort default 8080; ``` これは概念的には以下を表す。 ```text Abstract { constraints: [NarrowedPort] default: 8080 } ``` 明示値が合成された場合、`default` は採用されない。 ```dcdl MyConfig = { port = NarrowedPort default 8080; }; Config = MyConfig & { port = 8000; }; ``` この場合、最終値は `8000` である。 `8080` は評価されない、または評価されても採用されない。 明示値がない場合、最終 materialize 時に `default` が採用される。 採用された default 値は、同じフィールドに定義された制約を満たす必要がある。 ```text Abstract { constraints: [NarrowedPort] default: 8080 } finalize => 8080 が NarrowedPort を満たせば成功 ``` ## default の内部表現 `default` は abstract value に付随する fallback thunk として保持できる。 これにより、default 値自体も必要になるまで評価しない。 ```text RuntimeValue = Concrete(ConcreteValue) Abstract { constraints: Vec default: Option } ``` 明示値は `Concrete` として表現し、`default` を保持しない。 `Abstract & Concrete` が成功した場合、制約検証後に `Concrete` になり、default は消える。 ## default の合成 同じフィールドに複数の `default` が合成された場合の詳細規則は未確定である。 現時点の単純な方針は以下である。 - `&` による default 同士の衝突はエラーにする。 - 同一 default 値は許可してよい。 - `//` による patch では右辺 default が左辺 default を置き換える。 この方針により、`&` は制約を保った合成、`//` は上書き操作として説明できる。