Okay, so I've spent some time trying to understand this, and I think it's
actually really cool, but I found the "About" and "Concepts" documents tumid and murky.
Here is my understanding of the basic concepts:
- It allows a schema-like set of constraints to be declared for JSON (and
therefore for YAML & TOML) in a syntax that is an extension of JSON.
- Cue deals with types (sets of values) where JSON deals with single values.
Ordinary JSON syntax for a primitive value denotes a set containing that
one value. For example, `a: 1` means that the set of possible values for
`a` is {1}. Cue calls this a concrete definition.
- Cue provides operators for union (`|`) and intersection (`&`) of sets, and
inequalities for ranges of numbers, and so on. `1 | 2` denotes `{1, 2}`.
- Built-in names provide the types `int`, `float`, `string`, etc.
- Cue "struct" types look like JSON objects, associating names with sets.
Each name/value pair is a constraint, and all constraints must be met.
For example, `{a: int}` denotes "the set of objects that have a property
`a` with the value in `int`".
- Properties can be referenced by name; this allows a property defined in
one place to be used a type (set) definition in multiple places.
- When a name is bound more than once, the sets associated with each binding
are intersected. This means that enforcing a schema reduces to simply
combining the schema definition with the "concrete" bindings and throwing
an error when an empty set is encountered.
BTW, if I do have it all wrong and what I've described above is not an
accurate description of Cue, then I think I'll have to go build what I've
described.
Some reasons I'm afraid I'm off-base:
- What's with the lengthy discussion of lattices, and related terminology?
Sure, we can construct a lattice from the set of possible types and a
"subset of" operator, but that's another level of abstraction away from
the necessary concepts, so I don't see what value it adds.
- The `|` operator is described as constructing a sum type, when it seems
to me it must actually be a (non-discriminated) union. Elsewhere the
`|` operator is described as "computing the join", which to me would mean
finding an element in a lattice, but for this to make sense to me I have
to think of it as adding an element to the lattice (again all the lattice
or poset terminology serves only to obfuscate things).
> What's with the lengthy discussion of lattices, and related terminology?
It's how the author thinks about the values. All the operations move a value up (|) or down (&) the lattice and those operations are associative, commutative, etc. Moving down past the concrete values gets you bottom, the error value, so 1 & 2 is _|_. It fits into things like default values where (using # for * because HN formatting doesn't do escape sequences) a: int | #1 and a: int | #1 unify to 1 because #1 & #1 = #1 but a: int | #2 added would result in a: int because #1 & #2 = _|_ so there is no default anymore.
I don't think the extended discussion on lattices is particularly useful. A much better intro is the tutorial [1] plus the concepts page [2]
The motivation is clearly to build a tool for configuring kubernetes but I see the combination of data, validation, and order independence as being valuable outside that use. I've definitely had projects where it'd fit. The main reason I'd think twice is because it does add a LOT of concepts for something that can be pretty simple on most projects.
Some of the reasons I like the tool can't be found in the language spec. CUE (the tool) provides import facilities for existing configurations like yaml, json, openapi, protobuf or even go code into cue. this helps with adoption and time spent porting existing configs. Another feature of the CUE tool is the ability to create small tools that are able to operate on cue definition files. https://github.com/cuelang/cue/blob/master/doc/tutorial/kube...
Here is my understanding of the basic concepts:
- It allows a schema-like set of constraints to be declared for JSON (and therefore for YAML & TOML) in a syntax that is an extension of JSON.
- Cue deals with types (sets of values) where JSON deals with single values. Ordinary JSON syntax for a primitive value denotes a set containing that one value. For example, `a: 1` means that the set of possible values for `a` is {1}. Cue calls this a concrete definition.
- Cue provides operators for union (`|`) and intersection (`&`) of sets, and inequalities for ranges of numbers, and so on. `1 | 2` denotes `{1, 2}`.
- Built-in names provide the types `int`, `float`, `string`, etc.
- Cue "struct" types look like JSON objects, associating names with sets. Each name/value pair is a constraint, and all constraints must be met. For example, `{a: int}` denotes "the set of objects that have a property `a` with the value in `int`".
- Properties can be referenced by name; this allows a property defined in one place to be used a type (set) definition in multiple places.
- When a name is bound more than once, the sets associated with each binding are intersected. This means that enforcing a schema reduces to simply combining the schema definition with the "concrete" bindings and throwing an error when an empty set is encountered.
BTW, if I do have it all wrong and what I've described above is not an accurate description of Cue, then I think I'll have to go build what I've described.
Some reasons I'm afraid I'm off-base:
- What's with the lengthy discussion of lattices, and related terminology? Sure, we can construct a lattice from the set of possible types and a "subset of" operator, but that's another level of abstraction away from the necessary concepts, so I don't see what value it adds.
- The `|` operator is described as constructing a sum type, when it seems to me it must actually be a (non-discriminated) union. Elsewhere the `|` operator is described as "computing the join", which to me would mean finding an element in a lattice, but for this to make sense to me I have to think of it as adding an element to the lattice (again all the lattice or poset terminology serves only to obfuscate things).