2.0.0-rc.23
Pre-release2.0.0-rc.23
Delta from 2.0.0-rc.22. See the rc.1 notes for the full 2.0 release story.
One language addition, closing a hole in the type system.
empty — writing the value a type already promised
RIDDL could declare T? and T* but could not write their empty inhabitants.
There was no literal for either, so a model could express acquiring a value and never
releasing one — and a whole class of ordinary transition was unsayable:
- releasing a hold, clearing a cancellation reason
- un-assigning a driver, a table, a bed
- emptying a cart, clearing a line-item list on void
In a constructor a field can simply be omitted, but set has no such escape, so these
were being written as prose strings. Reported by riddl-models, where 686 set … to "…"
prose values are being eliminated and these could not be.
set field Prescription.OnHold.holdReason to empty
set field TableOrder.orderItems to none // `none` is a SYNONYM
let e = empty String(1,30)* // ascribed, carries its own type
One literal, and none is a synonym, not a second construct: both spellings produce
the identical AST and prettify converges them to empty. Same choice not/! made — a
spelling flag would let two ASTs meaning the same thing compare unequal.
Legal exactly where the minimum cardinality is zero:
| type | empty |
|---|---|
T?, T*, T{0,n} |
legal |
T+, T{1,n}, bare T |
Error |
That single rule is why one literal serves both the absent optional and the empty
collection — they are the same inhabitant under different upper bounds — and it makes the
check total over the cardinality wrappers rather than special-casing two.
The ascribed form is not sugar. A bare empty takes its type from the position, and
only let, constant and set supply one — notably not a constructor argument, which
is where models most want it (record Data(items = empty)). empty T* is the form that
works everywhere.
Two limitations worth knowing
- A bare
emptyis not checked against a field typed INLINE. The expected-type
machinery resolves only named types, sonote: String(1,20)+gives the check nothing
to compare against. Declare the type, or use the ascribed form, and it is exact. This
is pre-existing behaviour shared with typed holes, not new. let e: T* = emptydoes not parse, becauselet's ascription is a type reference
and an inlineT*is not one.let e: SomeNamedType = emptyworks, as does
let e = empty T*. Also pre-existing.
Arithmetic remains out of scope, deliberately: computation is what the AI prompt is
for. Naming the empty inhabitant of a declared type is a literal, in the same family as
true and 5.
Format changes
- BAST
FORMAT_REVISION21 — value tag 12. Regenerate.bastfiles with this riddlc. - JSON —
{"value":"empty"}, with an optionaltypefor the ascribed form. - EBNF —
empty_valueadded, with a guard preventing an unascribedemptyfrom
swallowing the following statement.