Skip to content

Explore reflection #1114

@alandefreitas

Description

@alandefreitas

Note: content from https://cppalliance.org/alan/2025/10/28/Alan.html#reflection

The corpus keeps drifting out of sync because every important path in MrDocs duplicates representation by hand. Almost every subsystem reflects data from one format to another, and almost every internal operation traverses those structures. Each time we adjust a field we have to edit dozens of call sites, and even small mistakes create inconsistent state—different copies of the “truth” that evolve independently. Reflection eliminates this churn. If we can describe the corpus once and let the code iterate over those descriptions, the boilerplate disappears, the traversals remain correct, and we stop fighting the same battle.

A lightweight option would be to enforce the corpus from JSON the way we treat configuration, but the volume of metadata in AST makes that impractical. Instead, we lean on compile-time reflection utilities such as Boost.Describe and Boost.mp11. With those libraries we can convert the corpus to any representation, and each generator—including future binary or JSON targets—sees the same schema automatically. MrDocs can even emit the schema that powers each generator, keeping the schema, DOM, and documentation in sync. This approach also fixes the long-standing lag in the XML generator, where updates have historically been manual and error-prone.

sequenceDiagram
  participant AST as Clang AST
  participant Corpus as Typed Corpus
  participant Traits as Reflect Traits
  participant DOM as Corpus DOM
  participant Generators as Generators
  participant Clients as Integrations
  AST->>Corpus: Extract symbols
  Corpus->>Traits: Publish descriptors
  Traits->>DOM: Build type-erased nodes
  DOM->>Generators: Supply normalized schema
  Generators->>Clients: Deliver outputs
  Clients->>Generators: Provide feedback
  Generators->>Traits: Request updates
Loading

Process: We can start by describing the Symbols, Javadoc, and related classes, shipping each refactor as a dedicated PR so reviews stay contained. Each description removes custom specializations, reverts to = default where possible, and replaces old logic with static asserts that enforce invariants. We generalize the main merge logic first, then update callers such as the AST visitor that walks RecordTranche, ensuring the comments data structure matches the new descriptions. A MRDOCS_DESCRIBE_DERIVED helper can enumerate derived classes so every visit routine becomes generic. Once the C++ side is described, we rebuild the lazy DOM objects on top of Describe so their types mirror the DOM layout directly.

Use cases: Redundant non-member functions like tag_invoke, operator⇔, toString, and merge collapse into shared implementations that use traits unless real customization is required. New generators—binary, JSON, or otherwise—drop in with minimal code because the schema and traversal logic already exist. The XML generator stops maintaining a private representation and simply reads the described elements. We can finally standardize naming conventions (kebab-case or camelCase) because the schema enforces them. Generating the Relax NG Compact file becomes just another output produced from the same description. A metadata walker can then discover auxiliary objects and emit DOM documentation automatically. As a side effect of integrating Boost.mp11, we can extend the tag_invoke context protocol with tuple-based helpers for mrdocs::FromValue, further narrowing the gap between concrete and DOM objects.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions