skip to content

Why does a chat room's shared mutable participant roster force coordination between delivery threads when an immutable roster does not?

level: juniorimportance: must knowfreq 70%

answer

  1. who is allowed to write
  2. change in place versus publish a value
  3. a discipline every access site must obey
  4. contention grows with the read rate
  5. copying trades waiting for allocation

basics

~20 s

A mutable roster is changed in place, so every reader and every writer must follow one shared discipline or observe a half-applied change. An immutable roster is never written after publication, so a reader that holds one needs no permission from anybody.

solid answer

~50 s

The difference is what a reader is allowed to assume. With a **mutable roster**, a join writes into the same structure a delivery loop is walking, so what a reader sees depends on when it looked — and one of those moments is mid-change. Correctness stops being local to a function and becomes a protocol every access site must join, and the run-time price is waiting: deliveries queue behind whoever is applying a join, so the cost scales with how often the roster is *read*. With an **immutable roster**, a join builds the next roster and publishes it whole; readers hold whichever version they captured and can never see it change underneath them. The cost moves to copying and allocation on each change, plus staleness — a fan-out already in flight finishes against the version it started with.

code

pseudocode · 6 lines
pseudocode
// in place: readers and writers share one discipline
roster.add(user)

// as a value: build the successor, publish it whole
next = roster + [user]
current_roster = next      // a reader keeps whichever version it read

go deeper

for a junior

Be able to say what changes for a reader: in-place change means the roster can move under you, a published value cannot. Name one cost on each side — waiting on one, copying on the other.

for a middle

Explain why the guarded cost scales with the read rate while the copying cost scales with roster size times change rate, and why that makes the choice a measurement rather than a preference.

for a senior

Show the judgement in a real room: estimate the two rates, pick the style, and say out loud what staleness window you are accepting when a fan-out runs against a captured roster.

for a principal

Frame it as a standard others will follow: which regions of a service default to published values, which keep guarded state, and what evidence should force a region to switch.

A chat service fans each message out to the participants currently joined to a room. The roster is the piece of state both delivery and joins touch at once, and the two styles disagree about one thing only: whether that state is changed in place or replaced by a new value. ## In-place change makes every reader a participant When the roster is a **mutable collection changed in place**, a join is a write into a structure other threads are simultaneously walking. The value a reader observes depends on *when* it looked, and one of the instants it can look is part-way through a change. Correctness therefore stops being a property of any single function and becomes a property of a **protocol** that every site touching that roster must obey — writers and readers alike. Three consequences follow, and they are the real cost of the style: - **The obligation is invisible locally.** A delivery loop that reads the roster without joining the protocol compiles, runs and is usually right. It is wrong only under a schedule you cannot reproduce on request. - **The obligation is global to the value.** Adding one new call site anywhere can break code that did not change, because the protocol is an agreement among all of them. - **The obligation costs time at run time.** While one thread applies a join, the others that want the roster wait. That price is paid per *access*, so it grows with the fan-out rate, not with the join rate. A room with two joins an hour and ten thousand deliveries a second still pays it ten thousand times a second. ## Publishing a value removes the reader's obligation When the roster is a **value that is never written after it is published**, a join does not modify anything anyone is reading. It builds the next roster and installs it as the current one. A reader that has obtained a roster holds something that cannot change beneath it, so it needs no agreement with anyone and no waiting. What this style does *not* do is abolish the writers' problem. Two joins that each read the same old roster, each build their own successor and each publish it will lose one of the two participants — so there must still be one agreed way to install the next value. The saving is real but it is precisely scoped: **readers become free, writers do not.** The costs that appear instead are: - **Copying.** Building the successor of an `n`-entry roster copies those `n` entries unless the structure shares its unchanged parts. - **Allocation.** Every change produces a new object that eventually becomes garbage, so a high change rate shows up as memory traffic rather than as waiting. - **Staleness.** A fan-out that captured the roster before a join finishes against that captured version. Someone who joined mid-fan-out misses that one message. This is usually acceptable for a chat room and unacceptable for, say, a permission check — that judgement is part of choosing the style. ## Reading the trade-off | | Guarded mutable roster | Roster published as a value | |---|---|---| | Who must cooperate | every reader and every writer | the writers only | | Cost per message delivered | waiting behind the current change | none | | Cost per join | one in-place insert | building the successor | | What a reader observes | the roster as of its turn | the version it captured | | Degrades worst when | reads are heavy and constant | the roster is large and churns | ## The two numbers that decide it 1. **The contention rate** — how often the state is accessed multiplied by how long each access holds it. High read rates punish the guarded style hardest, because every reader pays. 2. **The size of the shared state and how often it changes** — the product of roster size and change rate is what the value style pays. A small roster that changes rarely makes copying invisible; a large roster that churns on every message makes it the bottleneck. Notice that neither number is a property of a language. The same two numbers decide the question in any of them, which is why this is a comparison of **styles** rather than of tools. ## What the comparison is not It is not a ranking. "Immutable is safer" is only true of the reader's obligation; it says nothing about the writer's, and it says nothing about cost. It is also not a lesson in any particular guarding machinery — how a guard is implemented, and what a memory model promises about visibility, is a separate subject. Here the question is narrower and more useful in a design review: given this state, this read rate and this change rate, which style of arrangement fits, and what will it cost when the room gets busy?

  • If the roster is read on every message but changes only a few times an hour, which style fits better?
    The value style. Readers never wait and never coordinate, and the copy is paid only on the rare change, so the total cost tracks the change rate rather than the delivery rate. The guarded style pays on every read, which is the frequent event.
  • What happens to a fan-out that is already in flight when the roster is replaced?
    It finishes against the version it captured, so a participant who joined mid-fan-out misses that one message and one who left may still receive it. The window is bounded by the fan-out's duration. Whether that is acceptable is a product decision, not a technical one.

A whiteboard anyone may edit means everyone must agree who holds the marker before reading it. A handout reprinted after each change means readers never negotiate — you pay for the printing instead.

saying these in an interview costs you the question

  • Claims immutability makes the program faster in every case
  • Thinks copying a roster is free because installing the new reference is cheap
  • Says only writers need the discipline and readers may read freely
  • Believes publishing values removes the need for one agreed writer
  • Treats a slightly stale but consistent roster as a defect in every design