Data, objects, and how we're railroaded into poor design (2018)
12 comments
·August 21, 2025mcdeltat
jasode
>IMO the nice thing about Erlang and Elixir is their foundation of representing data is rock solid. Because data is fully immutable, you get a lot of nice things "for free" (no shared state, reliable serialisation, etc). [...] >In contrast with languages like C++ and Java where things are shakey from the ground up.
Yes, immutable does provide some guarantees for "free" to prevent some types of bugs but offering it also has "costs". It's a tradeoff.
Mutating in place is useful for highest performance. E.g. C/C++, assembler language "MOV" instruction, etc. That's why performance critical loops in high-speed stock trading, video games, machine learning backpropagation, etc all depend on mutating variables in place.
That is a good justification for why Erlang BEAM itself is written in C Language with loops that mutate variables everywhere. E.g.: https://github.com/erlang/otp/blob/master/erts/emulator/beam...
There's no need to re-write BEAM in an immutable language.
Mutable data helps performance but it also has "costs" with unwanted bugs from data races in multi-threaded programs, etc. Mutable design has tradeoffs like immutable has tradeoffs.
One can "optimize" immutable data structures to reduce the performance penalty with behind-the-scenes data-sharing, etc. (Oft-cited book: https://www.amazon.com/Purely-Functional-Data-Structures-Oka...)
But those optimizations will still not match the absolute highest ceiling of performance with C/C++/asm mutation if the fastest speed with the least amount of cpu is what you need.
nopurpose
So much written about relation between objects and data, but not a single mention of Lisp and derivatives?
mort96
An excellent opportunity for you to elaborate on the connection, since I'm not seeing it.
cbsmith
I didn't like how this essay misunderstood the design principles in Java's class files. With dynamic binding to the runtime, you can't know for certain the layout of a data structure in memory (e.g. what is the ideal memory alignment?). If the class file is untrusted, you can't even be sure you have a valid data structure in the first place. So allocating the array and then assigning elements one at a time is what you do.
lmm
I've had thoughts along this line for a while. I think Scala does better than this article gives credit for; case classes are a significant step in the right direction, particularly post-Scala 3 (or with Shapeless in Scala 2) where you have many tools available to treat them as records, and you can distinguish practically between case classes (values) and objects with identity even if in theory they're only syntax sugar. It also offers an Erlang-style actor system if you want one.
In my dream language I'd push this further; case classes should not offer any object identity APIs (essentially the whole of java.lang.Object) and not be allowed to contain non-value classes or mutable fields, and maybe objects should be a bit more decoupled from their state. But for now I wouldn't let perfect be the enemy of good.
arethuza
"objects should be a bit more decoupled from their state"
Do you mean allowing the "class" of an object to be changed - CLOS can do that. Mind you it's a long time since I wrote any code using CLOS and even then I'm pretty sure I never used change-class.
lmm
The thing I'm envisioning is something akin to typeclass instances / trait impls, but specialised to the case where you have a service with identity rather than being for general function implementation. Just making the bridge between the "bag of state" piece and the "interface implementation accessible via a name/reference" piece a bit more of a first-class citizen.
chuzz
Good post, for what is worth Java is slowly and painfully correcting course with features like records and project Valhalla. As with the other language improvements though we will have to live with the tech debt for decades to come…
high_na_euv
I'd say majority of programming languages struggle with elegant, robust and exhaustive check error handling
danieltanfh95
clojure exists.
evrennetwork
[dead]
IMO the nice thing about Erlang and Elixir is their foundation of representing data is rock solid. Because data is fully immutable, you get a lot of nice things "for free" (no shared state, reliable serialisation, etc). And then on top of that you can add your interfacey, mutable-ish design with processes, if you want. But you will never have oddities or edge cases with the underlying data.
In contrast with languages like C++ and Java where things are shakey from the ground up. If you can't get an integer type right (looking at you, boxing, or you, implicit type conversions), the rest of the language will always be compensating. It's another layer of annoyances to deal with. You'll be having a nice day coding and then be forced to remember that int is different to Integer and have to change your design for no good reason.
Perhaps you disagree with Erlang's approach, but at least it's solid and thought-out. I'd take that over the C++ or Java mess in most cases.