Expressions



CUE has a variety of expressions for working with values.

Numerical Expressions

Mathematical Operations

Cue has the typical math operations for numbers. Multiplication also works for strings and lists.

math-ops.cue

// stdlib functions
import "math"

// mathematical!
n1: 3 + 2
n2: 3 - 2
n3: 3 * 2
n4: 3 / 2

// Truncated division
q: quo(-5, 2)
r: rem(-5, 2)

// Euclidean division
d: div(-5, 2)
m: mod(-5, 2)

// imported functions
f: math.Floor(3.14)
l: math.Log(100.2)
t: math.Tan(1.0)

cue eval math-ops.cue

n1: 5
n2: 1
n3: 6
n4: 1.5
q:  -2
r:  -1
d:  -3
m:  1
f:  3
l:  4.60716818865076442405424
t:  1.557407724654902

Additional math operations can be found in the Cue’s math package .

Comparison Operations

Cue has the expected relative comparison operators and semantics. Equality checks are handled by value unification.

compare-ops.cue

		// number constraints
positive:  >0 // numbers
doubledig: >=10 & <100 & int

// lexical comparison
lowercase: >="a" & <="z"

notone: <1 | >1
notone: 1 // error, empty disjuntion

cue eval compare-ops.cue

positive:  >0
doubledig: uint & >=10 & <100
lowercase: >="a" & <="z"
notone:    <1 | >1

Predefined Bounds

Cue has the following predefined bounds for sized numbers

int8      >=-128 & <=127
int16     >=-32_768 & <=32_767
int32     >=-2_147_483_648 & <=2_147_483_647
int64     >=-9_223_372_036_854_775_808 & <=9_223_372_036_854_775_807
int128    >=-170_141_183_460_469_231_731_687_303_715_884_105_728 &
              <=170_141_183_460_469_231_731_687_303_715_884_105_727

uint      >=0
uint8     >=0 & <=255
uint16    >=0 & <=65536
uint32    >=0 & <=4_294_967_296
uint64    >=0 & <=18_446_744_073_709_551_615
uint128   >=0 & <=340_282_366_920_938_463_463_374_607_431_768_211_455

rune      >=0 & <=0x10FFFF

Non-numerical, Math Operators

Some mathematical looking operators have secondary uses.

nonnum-ops.cue

// repeat strings and lists
s: 3 * "for he's a jolly good fellow\n" + "which nobody can deny"
l: 5 * ["eye"]

// concat lists
a: ["a", "b", "d"] + [1, 2, 4]

cue eval nonnum-ops.cue

s: """
    for he's a jolly good fellow
    for he's a jolly good fellow
    for he's a jolly good fellow
    which nobody can deny
    """
l: ["eye", "eye", "eye", "eye", "eye"]
a: ["a", "b", "d", 1, 2, 4]

String Expressions

Regular Expressions

Cue supports regular expression constraints with the =~ and !~ operators.

regexp.cue

a: "hello world" & =~"^hello [a-z]+$"
b: "hello" & !~"^[A-Z]+"

lowercase: =~"^[a-z]+$"

c: "hello" & lowercase
d: "Hello" & lowercase // error

cue eval regexp.cue

a:         "hello world"
b:         "hello"
lowercase: =~"^[a-z]+$"
c:         "hello"

They are based on Go’s regular expressions. Cue also has some additional regexp helpers .

Interpolation

Cue supports interpolation in strings and bytes with \(<expr>)

interpolate.cue

container: {
	repo:    "docker.io/cuelang"
	image:   "cue"
	version: "v0.3.0"
	full:    "\(repo)/\(image):\(version)"
}

name: "Tony"
msg:  "Hello \(name)"
// conver string to bytes
b: '\(msg)'
// convert bytes to string
s: "\(b)"

cue eval interpolate.cue

container: {
	repo:    "docker.io/cuelang"
	image:   "cue"
	version: "v0.3.0"
	full:    "docker.io/cuelang/cue:v0.3.0"
}
name: "Tony"
msg:  "Hello Tony"
b:    'Hello Tony'
s:    "Hello Tony"

For more complicated scenarios, use text/template base generation

You can also interpolate field names. (as we will see shortly)

Comprehensions

CUE has several forms of comprehension to add or extend values. More details and advanced cases can be found in deep-dives/comprehension.

List Comprehensions

Cue has list comprehensions to dynamically create lists. You can iterate over both lists and struct fields.

The form is [ for key, val in <iterable> [condition] { production } ]

* key is the index for lists and the label for fields

list-comp.cue

nums: [1, 2, 3, 4, 5, 6]
sqrd: [ for _, n in nums {n * n}]
even: [ for _, n in nums if mod(n, 2) == 0 {n}]

listOfStructs: [ for p, n in nums {
	pos: p
	val: n
}]

extractVals: [ for p, S in listOfStructs {S.val}]

cue eval list-comp.cue

nums: [1, 2, 3, 4, 5, 6]
sqrd: [1, 4, 9, 16, 25, 36]
even: [2, 4, 6]
listOfStructs: [{
	pos: 0
	val: 1
}, {
	pos: 1
	val: 2
}, {
	pos: 2
	val: 3
}, {
	pos: 3
	val: 4
}, {
	pos: 4
	val: 5
}, {
	pos: 5
	val: 6
}]
extractVals: [1, 2, 3, 4, 5, 6]

you cannot have more than list element introduced by a conditional (https://github.com/cue-lang/cue/discussions/713)

You can work around this with list.FlattenN

Field Comprehensions

Cue also has the ability to comprehend fields.

field-comp.cue

apps: ["nginx", "express", "postgres"]
#labels: [string]: string
stack: {
	for i, app in apps {
		"\(app)": {
			name:   app
			labels: #labels & {
				app:  "foo"
				tier: "\(i)"
			}
		}
	}
}

cue eval field-comp.cue

apps: ["nginx", "express", "postgres"]
#labels: {}
stack: {
	nginx: {
		name: "nginx"
		labels: {
			app:  "foo"
			tier: "0"
		}
	}
	express: {
		name: "express"
		labels: {
			app:  "foo"
			tier: "1"
		}
	}
	postgres: {
		name: "postgres"
		labels: {
			app:  "foo"
			tier: "2"
		}
	}
}

Conditional Fields

CUE’s if is different from other languages. It is a comprehension rather than a branching mechanism. That is why we refer to it as conditional fields, guarded fields, or another form of field comprehension.

Some important differences:

  • there is no else statement, you only include config when statements are true
  • there is no short-circuiting for multiple checks, all conditions will be evaluated

guards.cue

app: {
	name: string
	tech: string
	mem:  int

	if tech == "react" {
		tier: "frontend"
	}
	if tech != "react" {
		tier: "backend"
	}

	if mem < 1Gi {
		footprint: "small"
	}
	if mem >= 1Gi && mem < 4Gi {
		footprint: "medium"
	}
	if mem >= 4Gi {
		footprint: "large"
	}
}

// This will result in an error because CUE evaluates all conditions
// without short-circuiting, meaning it will still try to access app.field
// if app.field != _|_ && app.field == true {
//   foo: true
// }

// Use nested guards to check multiple conditions
if app.field != _|_ {
	if app.field == true {
		foo: true
	}
}

* Short-circuiting is likely to be added at some point, see https://github.com/cue-lang/cue/issues/2232

We'll never share your email with anyone else.
2024 Hofstadter, Inc