DEV Community

Cover image for Which Language Handles DOM-Like Models Best?
Andrey S Kalmatskiy
Andrey S Kalmatskiy

Posted on

Which Language Handles DOM-Like Models Best?

Modern applications - from document editors to game engines from UI frameworks to databases - rely heavily on complex, interconnected data models to represent their internal state. These models often form what we call here DOM-like data structures, which in their simplest form can be imagined as a familiar XML or JSON tree.


What Are DOM-Like Data Structures?

DOM-like data structures are polymorphic, interconnected object graphs characterized by three fundamental layers:

  1. 🌲 Tree of Ownership Objects are organized hierarchically, with each parent exclusively owning its children. This structure is acyclic and maps well to serialization formats like XML, JSON, or Protocol Buffers. It forms the backbone of many application data models, enforcing clear ownership boundaries and safe, exclusive containment.
  2. 🕸 Web of Weak References Beyond ownership, objects often need to reference each other without owning - think of a GUI control referencing the currently focused element, or a paragraph linked to an entry in a document's stylesheet. These are implemented as weak references to avoid circular ownership and memory leaks, forming a web of safe, non-owning links layered on the ownership tree.
  3. 🧊 Directed Acyclic Graph (DAG) of Shared Immutable Resources Immutable resources like styles, fonts, or textures are shared across multiple nodes without duplication, following the flyweight pattern. This DAG layer sits at the bottom of the ownership tree and enables efficient reuse of common immutable data while maintaining acyclic dependencies.

Real-World Examples of DOM-Like Structures

  • Game engines: Scene graphs with nested spatial hierarchies of entities.
  • UI frameworks: Controls grouped into panels, windows, or forms.
  • MVC/MVVM architectures: Loosely coupled models, views, and controllers.
  • Document editors: Pages containing structured text flows, paragraphs, and styles.
  • Object databases: Graphs of owned objects representing serialized data.
  • Relational databases: Tables with nested records and fields.

Why Modern Programming Languages Must Support DOM-Like Structures

These DOM-like object graphs represent the foundational data model for modern, stateful, interactive applications. Unlike flat or strictly hierarchical data, these structures are:

  • Large, mutable, and heterogeneous
  • Richly interconnected with complex dependencies
  • Combining ownership, sharing, and weak references

A programming language capable of modeling these structures safely, efficiently, and ergonomically is better suited for real-world application development. Such languages should provide:

  • Memory safety - no dangling pointers, use after free, double free
  • Leak prevention - guarantees against memory and other resource leaks
  • Clear ownership semantics - ideally verified at compile time
  • Immutability and controlled mutation - support for immutable objects, efficient resource sharing, and automatic unsharing on mutation
  • Safe deletion - modifying the DOM should never cause crashes, memory corruption, or undefined behavior, even if deleted objects are still referenced on the stack
  • Weak reference invalidation - when an object is deleted, all cross-weak-references to it should automatically become invalid

Evaluating languages by their ability to handle these DOM-like models offers deeper insight into their practical suitability beyond traditional benchmarks.


How We’re Going to Test Languages

Let's attempt a well-defined task to evaluate and compare how different programming languages handle DOM-like structures under a common set of structural constraints.

Task Definition

Participants must implement a simplified DOM for a hypothetical card editor/player application.

App look

This DOM consists of the following components:

  • Cards, each containing a list of Card Items.
  • Card Items may be one of:
    • Styled text blocks
    • Images
    • Connectors with arrows (auto-routing)
    • Buttons for navigation between cards
    • Groups of card items (recursive containers)

Object diagram

Constraints and Invariants

The implementation must enforce the following:

  1. Mutability. Cards and elements must be mutable, supporting live updates of all their attributes.
  2. Shared Resources. Styles and bitmaps can be shared across elements, cards, or documents. Modifying a shared resource must not affect unrelated elements - mutation must be explicit and localized (copy-on-write or unshare-on-mutate behavior).
  3. Ownership Structure
    • Each Card belongs to exactly one Document.
    • Each Element belongs to exactly one Card or Group.
    • Groups may be nested recursively.
    • A group cannot - directly or indirectly - contain itself.
  4. Connectors. Connectors may target arbitrary elements. If a target is deleted, connectors must safely enter a detached state without crashing.
  5. Button Navigation. Buttons link to other cards. If a target card is deleted, referencing buttons become safely detached.
  6. Memory Safety
    • No use after free, uninitialized pointers, double free allowed.
    • No memory leaks allowed.
    • Deleting an object must not crash the program - even if references are still on the call stack.
    • Runtime resilience is critical; the app must remain stable, especially for sensitive domains like medical systems.
  7. Copy Semantics. Copy of cards and card items must maintain predictable reference semantics and preserve topology (e.g., connectors and buttons must keep the same topology of links after duplication).

Methodology

Participants implement the DOM model in one or more languages, adhering to the constraints. They document:

  • Design decisions on ownership and reference tracking
  • Handling or avoidance of shared mutable state
  • Safety guarantees from the language or design
  • Trade-offs during implementation
  • Code size and cognitive overhead

A reference class diagram is suggested, though exact design and memory management can vary.

Class diagram

Evaluation Criteria

Criterion Description
Memory safety Avoids unsafe access patterns?
Leak prevention Avoids memory leaks?
Ownership clarity Are ownership relations clear and enforced by the language?
Copy semantics Are copy/clone operations predictable and correct?
Weaks handling Does the app survive partial deletions and dangling references?
Runtime resilience Can DOM operations cause app termination?
Code expressiveness Is the code concise and maintainable?
Ergonomic trade-offs How difficult is enforcing invariants in the language?

Everyone’s Invited

If you have a favorite programming language to showcase:

  • Implement this DOM-like model.
  • Share what worked, what felt clunky, and where safety relied on discipline rather than language features.

💬 Join the Experiment!

Whether you’re a language enthusiast, a systems programmer, or simply curious, I invite you to participate, share your experiences, and help uncover which languages truly excel at managing modern, complex application state.

What’s Next

In the upcoming posts, I’ll take a deep dive into implementing this DOM model in several widely used languages with very different memory and ownership systems. After that, I’ll explore other languages and compare their strengths and challenges.

Let's discover a winner - or will we confirm that no acceptable solution exists yet?

Top comments (0)