CUE allows fields to be given a value which is used only if unification results in no other value being provided.
This guide demonstrates CUE’s default value syntax.
Specifing defaults
Specify a default by marking one element of a disjunction with an asterisk prefix:
// field 'a' has a default value of "A".
// it can also be set to any other value,
// through unification
a: *"A" | _
If a field’s value is not provided through unification then the default is used.
If a regular field has a value provided elsewhere, through unification, then that value is used instead:
package example
a: *"A" | _
b: *"B" | _
package example
a: "some value"
$ cue export .:example
{
"a": "some value",
"b": "B"
}
Such a default will only have an effect if the field is also unified with a regular field.
If this unification occurs, the default behaves as demonstrated in this guide.
The purpose of the disjunction
If a default is provided, it must take the form of a single element of a valid disjunction - that is, a disjunction containing at least 2 elements.
If the field has a value provided elsewhere, through unification, then at least one of the disjunction’s elements must unify with the field’s concrete value. The concrete value provided through unification may be the same as the default value:
package example
a: *"A" | string
b: *5 | int
package example
a: "A"
$ cue export .:example
{
"a": "A",
"b": 5
}
If no element unifies with the value that has been provided, a disjunction resolution error results:
package example
a: *"A" | string
b: *5 | int
package example
b: "a string"
b: 2 errors in empty disjunction:
b: conflicting values "a string" and 5 (mismatched types string and int):
./data.cue:3:4
./policy.cue:4:5
b: conflicting values "a string" and int (mismatched types string and int):
./data.cue:3:4
./policy.cue:4:9
Defaults are usually specified as concrete values
Defaults are used by the CUE evaluator when a field’s value needs to be used in a concrete context, but where no specific value has been provided elsewhere, through unification.
Therefore, in order to be useful, defaults need to evaluate to a concrete value. If CUE needs to use a default but the value provided is not concrete, an error results:
package example
a: *"A" | _
b: *string | _
b: incomplete value string:
./in.cue:4:5
Defaults can include references
Defaults are commonly specified as explicit concrete values, but if CUE can resolve a default to a concrete value via references then the result can be successfully used as a default:
package example
a: 5
b: *( a + 10) | int
c: "hello"
d: *( c + ", world!") | string
{
"a": 5,
"b": 15,
"c": "hello",
"d": "hello, world!"
}
Defaults can be complex values
Defaults are often specified as primitive types (bool
, string
, number
,
int
or float
) but they can also take complex types.
These values can either be provided inline, or by reference.
In this example, both defaults for the field a
are equivalent:
package example
a: string | *_s
a: string | *{
x: "value"
y: [
"hello",
"world",
]
}
_s: {
x: "value"
y: [
"hello",
"world",
]
}
{
"a": {
"x": "value",
"y": [
"hello",
"world"
]
}
}
Specifying multiple defaults is usually not useful
A single field may have multiple defaults specified in parallel, provided that all the defaults unify successfully:
package example
a: *"A" | _
a: *string | _
{
"a": "A"
}
If multiple defaults are provided but they do not unify successfully, then CUE treats the field as if no defaults were provided. If unification then finishes without a concrete value being specified elsewhere, or without sufficient information being provided to resolve the disjunction, then the result is an error:
package example
a: *"A" | _
a: *int | _
a: incomplete value "A" | int | _
However, even if multiple defaults are provided and they unify successfully, doing so is usually not a useful technique as it often leads to unclear CUE. There are specific, nuanced, situations where this advice might not hold true but, in general, using multiple compatible defaults is unnecessary, and risks confusing the reader.
Defaults provide only a single preference layer
As demonstrated above, if a field has multiple defaults provided but they do not all unify successfully, then CUE behaves as if no default had been provided.
For this reason, defaults cannot be used as a system of multi-layered, overriding values.