The Fatal Mix: When Databases Store Semantics Instead of Syntax

Object-oriented databases (OODBs) really were the future for a brief moment, especially in the late 1980s and early 1990s. They promised a world where the gap between the programming language and the database would disappear. No more ORM. No more impedance mismatch. Just store your objects directly.

Then the hype vanished.

The reasons are surprisingly deep, and understanding them shows why Datom.world's fixed datom model avoids the same traps.

Here's what actually happened to OODBs, without nostalgia or marketing spin.

1. Objects Seemed Universal, But Were Not Universal Enough

Each programming language invented its own idea of an "object":

  • Smalltalk objects are not C++ objects
  • C++ objects are not Java objects
  • Java objects are not Python objects

An OODB stores language-specific object layouts and method assumptions.

That means the data is not portable across languages.

Data locked to a language is not data in the long-term archival sense. It is a memory snapshot of a specific runtime.

When languages evolve, or die, your data becomes unreadable.

The Achilles Heel

Storing objects stores semantics, not just structure. And those semantics decay.

An object isn't just fields. It's a package of assumptions about inheritance, method dispatch, type hierarchies, memory layouts, and runtime conventions. All of that becomes frozen into the persisted representation.

Five years later, when the language has evolved or your team has switched to a different language, that frozen semantic contract is broken. The data becomes archaeological, not operational.

2. Schemas Changed Too Often Because Objects Change Too Often

Developers refactor their object models constantly. Every little refactor becomes a schema migration in an OODB.

  • Your front-end team changes a field? Your deployment breaks.
  • Your back-end team renames a method? Your stored data can no longer be interpreted.

Objects change at developer speed.

Databases need to change at geological speed.

Those two rates are incompatible.

Relational databases survive because their schemas are deliberately simple and change infrequently. OODBs coupled the database schema directly to the application's object model, which meant every code refactor triggered a data migration. In practice, this was intolerable.

3. Methods Are Not Data (But OODBs Tried to Store Both)

OODBs didn't store just fields.

They tried to store methods, inheritance structures, polymorphic dispatch rules, vtables, and more.

This was fatal.

Because methods contain code, not meaning. They depend on the compiler, runtime, memory model, calling convention, and libraries.

Persisting code was far harder than persistently storing pure data.

OODBs dragged in the entire programming environment. They became VM snapshots disguised as databases.

This tight coupling meant that OODBs couldn't be separated from their host runtime. You couldn't query an OODB from a different language, a different platform, or even a significantly different version of the same system. The "database" wasn't a data store anymore. It was an extension of the application process.

4. Querying Objects Turned Out to Be Harder Than Querying Relations

The relational model survives because it is brutally simple:

  • A table
  • Rows
  • Columns
  • A few operations with strong algebraic laws

OODBs had none of that algebraic clarity. They had pointer graphs.

Pointer chasing is intuitive for programmers, but disastrous for:

  • Optimization
  • Indexing
  • Distributed execution
  • Partial reads
  • Declarative queries

Without an algebra, you can't plan queries.

Without an algebra, you can't scale.

SQL's success is not accidental. Its declarative nature allows query planners to optimize execution paths. Pointer-based object navigation is inherently imperative. You follow the pointers in the order the programmer wrote them. There's no way to reorganize execution for efficiency without breaking semantics.

5. Object Identity Is Brittle Across Versions, Processes, and Machines

The idea of an "object identity" that lives forever turned out to be ill-defined.

Is identity the memory address? The object ID? A hash? Some runtime value?

Different OODBs invented different answers.

  • Distributed systems broke them.
  • Upgrades broke them.
  • Snapshots broke them.

The lack of a simple, stable, universal identity model killed interoperability.

Relational databases use primary keys: simple, stable, portable. OODBs tried to use object references, which are fundamentally tied to a specific process's memory space. Making those references durable and portable required complex machinery that never quite worked reliably across all scenarios.

6. The Web Exploded (And OODBs Were Not Built for the Web)

The web forced:

  • Language-agnostic APIs
  • Stateless servers
  • Long-lived backend data
  • Multiple concurrent clients
  • Simple serialization formats

Object persistence made the opposite assumptions:

  • Stateful servers
  • One language
  • One runtime
  • Tightly coupled application/data layers

OODBs were not compatible with the web's architecture. The web won. OODBs lost.

By the mid-1990s, it became clear that data needed to outlive applications, cross language boundaries, and survive server restarts. OODBs couldn't adapt to this reality. Relational databases with REST APIs could. The choice was obvious.

7. Developers Discovered the Cost of Hiding Complexity

OODBs promised: "Just store objects, we'll take care of the rest."

But hiding complexity is dangerous when the complexity is essential.

ORMs later made the same promise and suffered many of the same problems.

A magical abstraction layer eventually leaks. When it leaks in the database layer, failure is catastrophic.

OODBs tried to make persistence invisible. Systems need visibility.

Developers need to understand when data is loaded, how queries are executed, what triggers I/O. Transparent persistence sounds appealing until a single navigation step triggers 10,000 lazy loads and brings down production.

Why Datom.world Avoids These Failures

This is where the contrast becomes sharp, and relevant for modern systems.

Object DatabasesDatom.world
Objects as dataDatoms as pure facts
Meaning embedded in stored valueStructure fixed, semantics external
Methods stored with dataNo methods stored, only facts
Language-dependentLanguage-independent
Runtime-dependentRuntime-independent
Complex object graphsSimple five-tuple streams
Pointer-based navigationDatalog queries
Brittle identityStable entity references

Datoms Do Not Change When the Application Changes

A datom is [entity attribute value transaction metadata]. That structure never changes.

Datoms do not encode the semantics of a language or an inheritance hierarchy. They are closer to atoms of information than snapshots of objects.

This is why the system remains stable over decades, not releases.

Interpretation Is Pluggable

Because semantics are external (see Structure vs Interpretation), interpreters can be swapped, composed, upgraded, or layered without touching the data.

Your application logic evolves. Your data does not. Interpreters read the same datoms and extract new meanings as requirements change.

No Object Graphs, No Pointer Chasing

Datom.world uses Datalog for queries. Datalog has a formal algebra. Queries can be optimized, distributed, and executed incrementally.

You don't navigate pointers. You declare patterns and let the query engine find them.

Identity Is Simple and Stable

Entities are represented by stable identifiers. Those identifiers are not memory addresses. They're logical references that work across processes, machines, and time.

The same entity can be referenced from any interpreter, any node, any moment in the stream's history.

Built for Distribution

Datom.world assumes distribution from the start. Streams are append-only. Interpreters are mobile. There's no central runtime to couple to.

This is the opposite of OODBs, which assumed a monolithic, stateful, single-language runtime.

The Deeper Lesson

Object databases failed because they stored too much.

They tried to store:

  • Data
  • Structure
  • Behavior
  • Semantics
  • Runtime assumptions
  • Language conventions

That entire package decayed. The more you store, the more brittle the system becomes.

Datom.world succeeds because it stores almost nothing.

Just five positions:

  • entity (who)
  • attribute (what aspect)
  • value (the value)
  • transaction (when)
  • metadata (context)

Everything else is interpretation.

By restricting the substrate to a minimal, stable form, Datom.world creates space for maximum semantic flexibility.

Objects pretended to be universal but carried hidden dependencies. Datoms actually are universal because they carry nothing but position and reference.

Historical Context: The OODB Vendors

For those curious about the actual systems, here were the major players:

  • ObjectStore (1988): Early C++ OODB, fast but tightly coupled to C++ runtime
  • Versant (1988): Multi-language support, but struggled with schema evolution
  • O2 (1991): French research system, elegant but impractical
  • GemStone (1987): Smalltalk-based, survived by pivoting to app server
  • Poet (1991): Embedded OODB, disappeared with its niche

Most are gone or pivoted to entirely different markets. The ones that survived did so by abandoning the pure OODB vision.

GemStone, for instance, still exists but evolved into a distributed caching and application platform, not a pure object database.

What About Datomic and Triple Stores?

Some might ask: aren't Datomic and RDF triple stores similar to Datom.world?

Yes and no.

Datomic uses a similar datom structure [entity attribute value transaction] but is primarily a database, not a distributed computation fabric. Datom.world extends the model to support mobile interpreters, continuations, and process migration.

RDF triple stores use [subject predicate object] triples, which are similar but lack the temporal and metadata dimensions that datoms provide. More importantly, RDF systems often encode ontologies into the data itself (OWL, RDFS), reintroducing the brittleness that Datom.world avoids by keeping semantics external.

Conclusion

Object databases failed because they conflated data with code, structure with behavior, persistence with execution.

The lessons are clear:

  1. Data must outlive applications (don't couple data to runtime)
  2. Semantics must be external (don't freeze meaning into storage)
  3. Structure must be simple (complexity should live in interpreters, not substrate)
  4. Identity must be portable (don't tie references to memory addresses)
  5. Queries need algebra (declarative beats imperative for scale)
  6. Distribution must be native (design for many runtimes, not one)
  7. Transparency is not always a virtue (visibility prevents catastrophic leaks)

Datom.world internalizes all these lessons. Its five-element tuple is not a limitation. It is the distilled essence of what data must be to survive, compose, and scale.

Object databases stored too much and died. Datom.world stores almost nothing and thrives.

Learn more: