- that's why OOP failed - side effects, software too liquid for its complexity
- that's why functional and generic programming are on their rise - good FP implementations are natively immutable, generic programming makes FP practical.
- that's why Kotlin and Rust are in position to purge Java and C, philosophically speaking - the only things that remain are technical concerns, such as JetBrains' IDEA lock-in (that's basically the only place where you can do proper Kotlin work) as well Rust's "hostility" to other bare-metal languages, embedded performance, and compiler speed.
While the reasoning holds generally, that specific example is wrong.
The type the author presents is not the “User Profile” but a “User Profile Load Resource” (or something in those terms).
When you actually design interfaces you discover that there are way more states to keep in mind when implementing asynchronous loading.
1. There’s an initial state, where fetching has not happened yet
2. There may be initial cached (stale or not) data
3. Once loaded the data could be revalidated / refreshed
So the assumption that you either are loading XOR have data XOR have an error does not hold. You could have data, an error from the last revalidation, and be loading (revalidating).
What does it mean when loading is false, error is Some, and data is also Some? The type allows nonsense. You write defensive checks everywhere. Every render must guess which combination is real
How about you never write the wrong state in the first place ? Then you have nothing to take care of
Yet in practice, I've found that it's easy to over-model things that just don't matter. The number of potential states can balloon until you have very complex types to handle states that you know won't really occur.
And besides, even a well modelled set of types isn't going to save you from a number that's out of the expected range, for example.
I think Golang is a good counter example here -- it's highly productive, makes it easy to write very reliable code, yet makes it near impossible to do what the author is suggesting.
Properly considered error handling (which Go encourages) is much more important.
11 comments of 47
[ 3.1 ms ] story [ 25.9 ms ] thread- that's why OOP failed - side effects, software too liquid for its complexity
- that's why functional and generic programming are on their rise - good FP implementations are natively immutable, generic programming makes FP practical.
- that's why Kotlin and Rust are in position to purge Java and C, philosophically speaking - the only things that remain are technical concerns, such as JetBrains' IDEA lock-in (that's basically the only place where you can do proper Kotlin work) as well Rust's "hostility" to other bare-metal languages, embedded performance, and compiler speed.
When you actually design interfaces you discover that there are way more states to keep in mind when implementing asynchronous loading.
1. There’s an initial state, where fetching has not happened yet
2. There may be initial cached (stale or not) data
3. Once loaded the data could be revalidated / refreshed
So the assumption that you either are loading XOR have data XOR have an error does not hold. You could have data, an error from the last revalidation, and be loading (revalidating).
Now, is that gonna help design better software in any particular way?
> Stability isn’t declared; it emerges from the sum of small, consistent forces.
> These aren’t academic exercises — they’re physics that prevent the impossible.
> You don’t defend against the impossible. You design a world where the impossible has no syntax.
> They don’t restrain motion; they guide it.
I don't just ignore this article. I flag it.
Yet in practice, I've found that it's easy to over-model things that just don't matter. The number of potential states can balloon until you have very complex types to handle states that you know won't really occur.
And besides, even a well modelled set of types isn't going to save you from a number that's out of the expected range, for example.
I think Golang is a good counter example here -- it's highly productive, makes it easy to write very reliable code, yet makes it near impossible to do what the author is suggesting.
Properly considered error handling (which Go encourages) is much more important.