Back to Blog

RIDDL 2.4.0 Released

RIDDL 2.4.0 is now available.

release riddl compiler

RIDDL 2.4.0 is now available. This release of the RIDDL compiler and language tooling includes the following changes:

What’s New

What’s New

RIDDL has always required every value to be typed. 2.4.0 enforces that rule for the two values whose spelling carries no type of their own: empty/none and prompt(…). A bare empty takes the type of its position. Where nothing supplies a type, you write empty T, and T is a type NAME, never a type expression. Declare type MaybeRecipe is Recipe? and write empty MaybeRecipe. See the Computational Model §0.3, ruling 6.

Features

  • empty is checked at every position that types it. A bare empty is now held to the minimum-cardinality rule at every position that supplies a type:

    • set, append/remove and let
    • constructor, call, initiate and terminate arguments
    • put, return, require … with
    • store/upsert and update … set
    • comparison operands

    Fields typed inline (note: String?) are checked too. Before this release only four of those positions checked anything, and the rest accepted empty against types that cannot be empty.

  • x == empty. empty can now be a comparison operand. The operand opposite it supplies its type.

  • EmptyValue.typeRef and PromptValue.typeRef. A value’s ascription is carried as the TypeRef it names. New non-deprecated readers: ascribedType and expressionAscription. A bare predefined type (Real, Boolean, TimeStamp) counts as a name; a parameterized one (String(1,30)) does not.

  • Three new Errors:

    • value-ascription-not-a-name: empty String? or prompt(…) as T*. The 2.0 spelling was admitted by mistake; it still parses, so the message names the fix.
    • value-empty-untyped: a bare empty where nothing supplies a type, such as an untyped let, log empty or empty == empty.
    • value-empty-ascription-contradicts: an ascription that is not, syntactically, the position’s declared type. A field typed inline takes a bare empty.

Bug Fixes

  • update T set f = empty where … failed to parse. empty’s optional ascription read the next word as a type name. put empty to …, append empty to … and store empty in … failed the same way. The guard after empty is now a word category rather than a list, and the EBNF carries the same rule.
  • empty with an alias type was refused. empty MaybeNote with type MaybeNote is String? reported “requires at least one value”, and so did a bare empty for any alias-typed constructor field. The cardinality check now reads through type names, including alias chains, and is safe on cyclic ones.
  • riddlc dump --json misreported alias-typed fields. cardinality and acceptsEmpty came back as exactly-one and false for a field whose alias names an optional or a collection.
  • Prettify dropped the keyword from empty record R, so the output re-parsed as a different AST.
  • Messages.justWarnings returned advisories. It filtered by severity band, and Advisory sits inside that band while reporting isWarning = false. RiddlLib.ValidateResult (as a trailing defaulted field) and the JS facade both gain an advisories bucket. Before this, an advisory reached consumers only inside all. Blocking behaviour (--fail-on) was never affected.
  • PromptValue had no JS export. Its @JSExportTopLevel annotation was attached to EmptyValue.

Deprecations

  • EmptyValue.typeEx and PromptValue.typeEx are deprecated in favour of typeRef and ascribedType. Both still parse and are still populated, so existing readers see no change.

Internal

  • BAST and JSON wire formats are unchanged; typeRef is derived on read, so files written by 2.3.x load to the same AST the parser builds.
  • EbnfReservedWordsTest keeps the grammar’s hand-kept word lists in step with the parser.
  • A corpus walk in the test suite prunes target/ instead of filtering it afterwards.
  • Corpus check: all 191 riddl-models entry points validate with 0 errors, as they did on 2.3.1.