Flyweight-Style Sharing with Immutable Data

Reduce duplication in Clojure by sharing stable immutable structures where measurement shows memory or allocation pressure.

The flyweight pattern reduces memory usage by sharing stable, reusable representation instead of duplicating it everywhere. In Clojure, this pattern often appears in a simpler and safer form than in mutable object systems because immutable values are already easy to share.

That means the pattern is both less dramatic and easier to misuse. Less dramatic, because ordinary immutable data already gives you a lot of safe reuse. Easier to misuse, because developers sometimes reach for “flyweight” before they have measured whether duplication is actually a problem.

What Shared Representation Means In Clojure

The central idea is to separate:

  • stable shared structure
  • small context-specific data

For example, many values might share the same template, schema description, color palette, or ruleset while differing only by a few identifiers or local fields.

 1(def base-theme
 2  {:font/body "IBM Plex Sans"
 3   :font/code "JetBrains Mono"
 4   :colors {:accent "#0f766e"
 5            :warning "#c2410c"
 6            :surface "#ffffff"}})
 7
 8(defn page-theme [page-id overrides]
 9  {:page/id page-id
10   :theme/shared base-theme
11   :theme/overrides overrides})

Here, the expensive or stable part stays shared. The per-instance data remains small and explicit.

Why Clojure Changes The Pattern

In object-oriented treatments of flyweight, a lot of complexity comes from coordinating shared mutable objects safely. In Clojure, immutable data removes much of that risk. A shared value can often just be a value:

  • a shared map
  • a shared vector
  • a shared rules table
  • interned keywords or canonical enums

That means the key design question is not “Can this be shared safely?” but “Is the sharing actually buying us something important?”

Good Use Cases

Flyweight-style sharing helps when:

  • a large stable structure repeats many times
  • allocation or memory pressure has been measured
  • the shared part is truly immutable and reusable
  • per-instance context stays small and separate

Examples include:

  • rendering or layout templates
  • shared schema descriptors
  • token or AST metadata reused across many nodes
  • lookup tables reused by many values

Bad Use Cases

Do not reach for the pattern when:

  • the shared structure is tiny
  • the complexity of indirection exceeds the saved memory
  • ordinary structural sharing from persistent data structures already solves the problem
  • the design makes the data harder to understand

That last point matters most. A flyweight optimization that makes a simple domain model unreadable is usually a bad trade unless profiling proves the pressure is real.

Relation To Clojure’s Existing Structural Sharing

Clojure already gives you persistent data structures with structural sharing. That means some “flyweight” wins come for free when you derive one value from another.

So before introducing explicit flyweights, ask whether the language has already solved enough of the duplication problem. Sometimes the right answer is not a custom sharing scheme. Sometimes it is just using ordinary immutable values well.

Measuring Before Optimizing

This pattern belongs in the same performance conversation as the cache-locality and lazy-sequence pages elsewhere in the guide: measure first.

Use explicit flyweight design only when you can point to one of these:

  • memory pressure
  • allocation churn
  • repeated large stable substructures
  • profiling evidence that the duplication matters

Without that evidence, the pattern is often premature.

Design Review Questions

Ask these before adopting a flyweight-style design:

  • What exact stable structure is being shared?
  • How much duplication does that really eliminate?
  • Could ordinary persistent structural sharing already be enough?
  • Does the resulting data model stay readable?

If the answers are clear and measured, the pattern can be very effective. If not, prefer simpler data.

Loading quiz…
Revised on Thursday, April 23, 2026