# Array Expression An array expression represents an ordered sequence of values. ```dcdl [1, 2, 3] ["a", "b", "c"] ``` An array literal is a concrete value and does not require all elements to have the same type. ```dcdl ["api", 8080, true] ``` ## Array constraint Write an array constraint by placing an ellipsis immediately after `[`, followed by an element constraint. ```dcdl Names = [...String]; Ports = [...(Int & >= 1 & <= 65535)]; ``` `[...T]` represents an array of zero or more elements, all of which satisfy `T`. An empty array satisfies every array constraint. ```dcdl [...String] & [] [...String] & ["api", "worker"] ``` The element constraint can be an object range. A field with a default that exists only on the right remains abstract in every element when the array constraint is composed. Its default is selected only if the array is later materialized. ```dcdl Services = [...{ name = String; enabled = Bool default true; }]; Services & [{ name = "api"; }] ``` Applying an array constraint to a concrete array refines each element against the element range using the same rules as `as`. For an object element range, a field present only on the left produces an error, while a field present only on the right remains abstract. Decodal does not provide an abstract array type without an element constraint. The former `Array` primitive type is unavailable, and `T` is required in `[...T]`. `[String]` is not an array constraint; it is a concrete one-element array containing the unresolved `String` constraint. An array constraint describes only the element range. It has no length, positional tuple, or uniqueness constraints. ## Array concatenation `++` concatenates two concrete arrays. ```dcdl base = ["read", "write"]; extra = ["admin"]; roles = base ++ extra; ``` `roles` has the same value as: ```dcdl ["read", "write", "admin"] ``` `++` does not transform array elements. Elements from the right side follow those from the left.