# Constraints and Defaults A constraint describes a range that a value must satisfy. ```dcdl Int String >= 1 <= 65535 /Hello! .*/ ``` Constraints can be composed with `&`. ```dcdl Port = Int & >= 1 & <= 65535; NarrowedPort = Port & > 443; ``` The result is the range that satisfies both sides. Incompatible constraints produce a conflict. ```dcdl Int & String # conflict > 10 & < 5 # conflict Int & > 10 & < 11 # conflict: integer candidate does not exist ``` ## Primitive and comparison constraints The built-in primitive ranges are: ```dcdl String Int Float Bool ``` Composing different primitive types with `&` produces a conflict. Numeric comparison constraints combine as bounds and conflict if they form an empty range. ```dcdl Int & >= 1 & <= 65535 & > 443 ``` Comparison constraints for `Int` use integer literals. Comparison constraints for `Float` may use either integer or float literals. ## Unknown `Unknown` is the top range containing every Decodal value. It is not an `Any` that disables checking and erases concrete information; it means that the value's range has not yet been narrowed. ```dcdl Int & Unknown # Int 42 as Unknown # 42 Unknown as Int # conflict ``` `Unknown` has no concrete value of its own and therefore cannot be materialized. It must be narrowed by a concrete value or given a `default`. ```dcdl Unknown default {} ``` ## Regex constraints A regex literal is a string constraint. ```dcdl Host = /^api-[0-9]+$/; ``` When several regex constraints are composed, a concrete string must match all of them. ```dcdl String & /^a/ & /z$/ ``` The intersection of regex constraints is not determined during composition. The following range therefore does not conflict when composed, but fails when a concrete value is validated. ```dcdl String & /^a$/ & /^b$/ ``` In the Rust runtime, enable the regex engine with the `regex` feature. Without that feature, validating a regex constraint against a concrete value produces an unsupported-feature diagnostic. ## Array constraints Write an array constraint as `[...T]`; it applies `T` to every element. The element constraint is required. ```dcdl Names = [...String]; PositiveInts = [...(Int & > 0)]; ``` When composed with a concrete array, each element is refined against `T` using the same rules as `as`. An empty array satisfies every array constraint. If the element constraint is an object range, fields present only on the right remain abstract in every element. A field present only on the left is outside the right-hand field domain and produces a conflict. ## Associative-array and object rest constraints Write an associative-array constraint as `{...T}`; it applies `T` to every field value in an object. ```dcdl Services = {...{ port = Int; enabled = Bool default true; }}; ``` Keys are not enumerated, and an empty object is allowed. Writing `...T` at the end of an object with named fields applies `T` only to fields that were not named explicitly. ```dcdl { enabled = Bool default true; ...Unknown } ``` A rest constraint does not generate fields. It only validates additional fields that actually exist. ## default `default` is not a constraint. It is a fallback used only when no concrete value exists during materialization. ```dcdl Port = Int & >= 1 & <= 65535; Service = { port = Port default 8080; }; ``` When an explicit value has been composed into the range, that value is used and `default` is not evaluated. ```dcdl Config = { port = 9000; } as Service; ``` Without an explicit value, materialization selects `8080` and verifies that it satisfies `Port`. ## Default composition - If only one side of `&` has a `default`, that `default` is preserved. - If both sides of `&` have different defaults, they conflict. - If `&` between a constraint and a concrete value succeeds, the result is concrete and does not retain the `default`. - Because `//` is right-biased, the right-hand value or `default` replaces the left-hand one for the same field. - `as` does not inject a right-hand `default` into the left side. A field that exists only on the right, however, remains abstract in the result together with its `default`. A `default` expression is evaluated when materialization requires it and must satisfy the constraints of the same range.