liveBook · Manning

Type checking constraint

As explained in Building User-Friendly DSLs

A constraint that verifies that related attributes have compatible or equal types.

A type checking constraint verifies that related DSL content has types that make sense together. In its simplest form, it requires equality: an attribute and the attribute it references must have the same type. A violation becomes an issue shown to the domain expert before inconsistent content reaches generated Runtime code. section 9.3.3 section 9.4

Types describe domain-specific value ranges and meanings. For example, amount and percentage may both be represented as JavaScript numbers, yet a dollar amount is not interchangeable with a percentage; date ranges represent a different kind of value altogether. Type checking preserves these distinctions in DSL content. section 13.0

Implement a type checking constraint by:

  • Computing the type of each relevant expression or attribute, including direct subexpressions where needed. section 13.4
  • Comparing the computed types against the equality or compatibility rule required by the construct. section 13.0
  • Reporting a precise issue that names the incompatible parts and their computed types, so the DSL content can be repaired. section 13.2
  • Producing a sensible best-effort type, or an untype when necessary, to avoid obscuring the root problem with cascading mismatches. section 13.4

Checking an attribute value

An Attribute can compare its own computed type with the computed type of its value. This generalizes an earlier reference-only check: instead of assuming that an Attribute Reference is directly nested in an Attribute, it works for any expression used as the value. If the types differ, the issue states both types. section 13.2 section 9.3.3

Binary operations need constraints tailored to their operators. A subtraction check can require both operands to have number types such as amount or percentage, reporting a separate issue for each operand that fails the requirement. Other expression constructs similarly check whether their combination of subexpression types is meaningful. section 13.2 section 13.4

Listing 13.6 Type checking the value of an Attribute
case "Attribute": {
    // ...code that checks existing constraints...
    if (isAstObject(settings["value"])) {
        const typeOfAttribute =
             typeOf(astObject, ancestors)  #1
        const typeOfValue =  #2
             typeOf(settings["value"], [ astObject, ...ancestors ])
        if (typeOfAttribute !== typeOfValue) {               #3
            issues.push(
`The types of this attribute and its value must match,  #4
    but they are: '${typeOfAttribute}', resp., '${typeOfValue}'`)
        }
    }
}

This implementation computes types for an Attribute and its value with the proper ancestor context, then emits an issue when they differ. section 13.2

How Building User-Friendly DSLs covers it

How deep it goes
Implements computed-type comparisons for attributes and binary operations, replacing a brittle reference-only AST-shape assumption.
Examples
Uses amount, percentage, date range, attribute references, binary subtraction, and Boolean business-rule conditions.
What it assumes
Assumes AST traversal and computed expression types while defining type equality and constraint-based issue reporting.
What you can do after
Build it from scratch by computing related types, comparing them, and reporting repair-oriented type errors.
How it connects
Connects type systems, type computation, type inference, ASTs, expressions, binary operations, and business rules.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Building User-Friendly DSLs. The section links point to the parts of the book it draws on.