What is OML?
OML — Object Modelling Language — isn't a specific
format. It's a category: any language or notation whose job is to
describe structured object data as text. JSON is one. YAML is one.
XML with a schema is one. Protocol Buffers' .proto
files are one. AML — ANVL's own modelling dialect — is one too.
What separates a good OML from an adequate one isn't feature count. It's whether the shapes it gives you already match how you think about objects in whatever language you're actually working in — or whether you have to translate.
The impedance mismatch problem
Every general-purpose language already has native ways to represent structured data: a record/dict/map/struct for keyed data, a list or array for ordered sequences, some flavor of typed literal for scalars. An OML's job is to describe that same shape in text — and the friction shows up exactly where the OML's model and the language's native model don't line up.
JSON gets the basics right (objects, arrays, a handful of scalar types) and that's most of why it won — almost nothing needs translating. But it stops there: no comments, no way to say "this value is the same as that one," no way to say "this shape extends that shape," no metadata channel separate from the data itself. Protocol Buffers goes the opposite direction — rich modelling (messages, enums, oneofs) but only reachable through a schema compiler and generated code, which is its own kind of impedance mismatch: you're not writing your language's native objects anymore, you're writing what the generator handed you.
How AML approaches it
AML's bet: keep the JSON-level shapes that already need no translation (objects, arrays, scalars), then add the handful of things config/data authors actually reach for — by naming them after concepts that already exist in essentially every mainstream language's own type system, not ANVL-specific inventions.
| AML construct | Maps onto | Already familiar from |
|---|---|---|
Object — { ... } |
A record / dict / map / struct | Every language has one |
Array — [ ... ] |
An ordered sequence | Every language has one |
Tuple — ( ... ) |
A fixed-arity, heterogeneous group | Python tuples, C# ValueTuple, Rust tuples, Go multi-return |
Inheritance — Child : Base := { ... } |
A base/derived class relationship | JS extends, Python subclassing, C# : Base, Java extends |
Attributes — @[key=value] |
Metadata attached to a field, separate from its value | Java annotations, Python decorators, C# attributes, Go struct tags |
$identifier VarRef |
A named reference to a value defined once | A variable or named constant, in any language |
None of that requires a schema compiler, a generated-code step, or learning ANVL's own mental model from scratch. If you already think in terms of records, base classes, and annotations — and you probably do, in whatever language brought you here — AML's shapes are ones you already have names for.
Where AMP fits
AML is deliberately the permissive half. ANVL's other dialect, AMP, is the restricted one — scalars and scalar collections only, no objects, no inheritance, no references, enforced at parse time rather than by convention. It exists for exactly the situations an OML's flexibility becomes a liability: message payloads, where you want a guarantee that structure can't silently grow arbitrary depth. See the AMP Guide for the full constraint list.