<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/concurrency-interactivity-mutability-choose-two-lxvwbvctk" -->

---
title: Concurrency, interactivity, mutability, choose two
description: Explores the fundamental trade-off between concurrency, interactivity, and mutability in programming languages — arguing you can only have two of the three....
canonical: https://daily.dev/posts/concurrency-interactivity-mutability-choose-two-lxvwbvctk
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: Concurrency, interactivity, mutability, choose two | daily.dev
og:description: Explores the fundamental trade-off between concurrency, interactivity, and mutability in programming languages — arguing you can only have two of the three....
og:url: https://daily.dev/posts/concurrency-interactivity-mutability-choose-two-lxvwbvctk
og:image: https://api.daily.dev/og/posts/lXVwBVctk.png
og:image:alt: Concurrency, interactivity, mutability, choose two
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Concurrency, interactivity, mutability, choose two

**[Hacker News](https://daily.dev/sources/hn)** · 4 min read · 0 upvotes · 0 comments

## Summary

Explores the fundamental trade-off between concurrency, interactivity, and mutability in programming languages — arguing you can only have two of the three. Dropping interactivity (C, Rust, Go) gives safe concurrent programs but no live inspection. Dropping concurrency (Python, Ruby via GIL) allows interactive mutation but at a performance cost. Dropping mutability (Erlang) enables safe concurrency and interactivity through message-passing but suffers from data-copying overhead. Common Lisp attempts all three but risks race conditions when modifying live state from a REPL.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://www.n16f.net/blog/concurrency-interactivity-mutability-choose-two>

## Community take

How the wider developer community reacted, aggregated from 1 discussion and 52 comments across hackernews (as of 2026-07-30).

**TL;DR:** The community is largely skeptical of the article's framing, finding the trichotomy imprecise or Lisp-centric, though some find the Erlang/Python/Rust buckets meaningful. Several commenters argue the constraints are not as hard as claimed, pointing to locking primitives, immutable data structure sharing, and databases as counterexamples.

**Sentiment:** 20% positive · 50% mixed · 30% skeptical

**The case for**

- The Erlang vs. Python vs. Rust categorization is seen as a useful and meaningful way to think about language trade-offs.
- Erlang/BEAM's approach (e.g., reference-counted binaries, actor model) is praised as an elegant solution that other ecosystems are slowly reimplementing via external services.

**The pushback**

- The article's claim that dropping interactivity eliminates concurrency issues in C is seen as plainly wrong — other threads still cause data races.
- The argument that immutability requires slow copying is challenged: persistent data structures with structural sharing (e.g., Clojure) avoid most copying overhead.
- The trichotomy is viewed as a Lisp-specific limitation rather than a universal truth — Rust, for instance, enforces safe concurrent mutable access via the type system and Mutex.
- Commenters note that databases already provide all three properties, and that concurrency primitives (locks, RCU) let you have mutability and concurrency together.
- The term 'interactivity' is considered confusing; one commenter suggests 'statefulness' but that too is disputed as unclear.

**By community**

- hackernews (skeptical): Most commenters push back on the article's logic, arguing the constraints are either Lisp-specific, imprecisely defined, or solvable with standard concurrency primitives and persistent data structures.

**Hottest debate:** Whether immutability truly requires expensive data copying, or whether structural sharing in persistent data structures largely negates that cost.

**Open questions**

- Does the trichotomy hold for languages with strong type-system enforcement (like Rust) that can make all three safe simultaneously?
- How does RCU (Read-Copy-Update) fit into or challenge this framework?
- Is 'interactivity' the right term, and if not, what more precise concept does the author actually mean?

**Highlights**

> This doesn't follow at all!   Dropping interactivity [keep Concurrency, mutability]:   The most popular choice is to drop interactivity: since there is no one to randomly access runtime data, there are no concurrency issues. C, Rust, Go, the list of languages that go this way is long. No-one to randomly access runtime data?  Do "other threads" not count?  There are no concurrency issues in C?   Dropping mutability   What if you could not really change data? Instead of reading the value of a variable, you could have the runtime systematically (and safely) copy the value and return it to you. Why would you copy anything?  Copying is defense against mutation.  It's what you do for safety when you're working in a language with pervasive mutation, and it's opt-in and manual, meaning it works about as well as other opt-in and manual operations, like malloc and free. Peeking over the fence at an immutable language and thinking "that runtime does too much copying, which is bad!" is like peeking over the fence at a GC language and thinking "that runtime does too many mallocs and frees, which is bad!"
> — [mrkeen on hackernews · 1 comments](https://news.ycombinator.com/item?id=49107220)

> > But again, there is no free lunch: copying data is slow. Very slow. Of course you can optimize data representations, avoid copying binary blobs (they are ref-counted in Erlang) because it would be untenable. But it will still be horribly slow. You don't have to copy the data; it is immutable. Why copy something that isn't going to change? Are we being charged for empty RAM? Different objects can share the same structure. Famously, this is what Clojure does. Theoretically it can be faster than mutating objects because you only have to write the parts that are changing (which is the same as a mutable object), you lose something to overheads (might be nearly negligible) and have enormous gains in situations where you might need a copy of an object for some reason because that is free; there isn't any reason to actually do a copy unless the data itself is going to be mutated.
> — [roenxi on hackernews · 2 comments](https://news.ycombinator.com/item?id=49107366)

> I believe it is a Lisp related story, not some general truth. I mean, if I had a hashtable that needs to be mutated asynchronously, I'd probably create a single writer to it. Some entity that takes ownership of a hashtable and you can talk with hashtable only through it. But if you are writing Lisp, and that hashtable is a global, then good luck ensuring that no one except the designated entity talks with hashtable directly. In particular, you can't force the user at REPL prompt to not do it. The mutability lament in the same ballpark. Dynamic nature of LISP makes it hard to ensure that some code paths can't change values they deal with. Statically typed languages do it all the time: just pass a const reference into a function and you can be sure that it wouldn't change the value, or anything referenced from it. In LISP the easiest way is to make a deep copy of a value. Other ways would probably need some changes introduced into lisp-machine itself. So you are choosing between two alternatives: either copy everything, or to believe other code to behave like values are immutable. The former is slow, the latter just doesn't work generally. Take Rust for example: if I have a mutable HashMap that needs a concurrent access, I'd hide it. It would be accessible directly in one module only, and the module would export safe API that you can't use to achieve data race. Technically I can make this HashMap to be global, but then Rust would rebels and force me to wrap my HashTable into a Mutex. If I added REPL to the mix, then REPL would need to lock Mutex as any other thread. Lisp just an ancient language that doesn't have these guardrails, so you need to think things through and ofc you will be overwhelmed in any real case by all these things, and then you write that you can't have concurrency, interactivity and mutability at the same time. To have them, you have to limit yourself in how you write your program, and while you can use LISP to limit yourself, you still need to do the decision and invest some work into it. It doesn't happen magically all by itself. For magic you'd better try rust, though its "magic" requires months of fighting with borrow checker until it succeeds at conditioning you into right practices.
> — [ordu on hackernews](https://news.ycombinator.com/item?id=49108502)

> A reminder that databases (as an example) provide all three without issues (at the cost of complexity in the implementation of course).
> — [gpderetta on hackernews](https://news.ycombinator.com/item?id=49108371)

> I don't think the author took a position on synchronisation at all. He said you have to pick one to abandon of mutability/concurrency/interactivity and that abandoning mutability is horribly slow (because of the need to copy things). And that isn't technically accurate because you can abandon mutability and not copy things. If you have a 1MB int->int associative data structure and need to change one entry, then you can reuse most of the MB (it isn't going to change) and get away with writing a couple of integers. And that could be substantially faster than a mutable approach when you need to make a genuine copy of the 1MB structure with a small change and keep both, because you can't structure share and you will need to copy the whole MB. Obviously situation specific, and I'm sure there are edge cases where immutable lookup tables fall apart. I haven't met one myself. I don't disagree with the article exactly, I do think abandoning mutability is necessary. I just don't think his argument that it needs to be slow is good. If you abandon mutability, "copying" data logically is extremely fast because you can skip almost all the IO for large objects. And copying a large object with a small change should be much faster in an immutable language because of structure sharing. Depending on the workload, that might be faster.
> — [roenxi on hackernews](https://news.ycombinator.com/item?id=49108349)

**Source threads**

- [hackernews](https://news.ycombinator.com/item?id=49065874) · 41 points · 52 comments

## Similar posts on daily.dev

- [Ditch your \(mut\)ex, you deserve better](https://daily.dev/posts/ditch-your-mut-ex-you-deserve-better-sd9zhgwrg) · Hacker News · 1 upvotes · 0 comments
- [Stop Using Shared Mutable State — Embrace Immutability for Safer Code](https://daily.dev/posts/stop-using-shared-mutable-state-embrace-immutability-for-safer-code-r2wrr0tjn) · Javarevisited · 1 upvotes · 0 comments
- [Designing real systems with immutable data in Clojure](https://daily.dev/posts/designing-real-systems-with-immutable-data-in-clojure-wdvqc5itp) · Nubank · 0 upvotes · 0 comments

---

Tags: [#erlang](https://daily.dev/tags/erlang)

[View this post on daily.dev](https://daily.dev/posts/concurrency-interactivity-mutability-choose-two-lxvwbvctk)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"TechArticle","headline":"Concurrency, interactivity, mutability, choose two","url":"https://daily.dev/posts/concurrency-interactivity-mutability-choose-two-lxvwbvctk","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/concurrency-interactivity-mutability-choose-two-lxvwbvctk"},"datePublished":"2026-07-30T10:34:01.415Z","dateModified":"2026-07-30T12:19:59.701Z","description":"Explores the fundamental trade-off between concurrency, interactivity, and mutability in programming languages — arguing you can only have two of the three....","image":"https://media.daily.dev/image/upload/s--VDukGCjf--/f_auto/v1722860399/public/Placeholder%2002","thumbnailUrl":"https://media.daily.dev/image/upload/s--VDukGCjf--/f_auto/v1722860399/public/Placeholder%2002","isAccessibleForFree":true,"articleSection":"Hacker News","inLanguage":"en","publisher":{"@type":"Organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180}},"author":{"@type":"Organization","name":"Hacker News","logo":"https://media.daily.dev/image/upload/t_logo,f_auto/v1/logos/hn","url":"https://daily.dev/sources/hn"},"commentCount":0,"discussionUrl":"https://daily.dev/posts/concurrency-interactivity-mutability-choose-two-lxvwbvctk","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":0},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":0}],"keywords":"erlang","timeRequired":"PT4M"}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"Hacker News","item":"https://daily.dev/sources/hn"},{"@type":"ListItem","position":3,"name":"Concurrency, interactivity, mutability, choose two"}]}
```

