4 ms·
"Objects containing the same values should be equal by default." No. This breaks down as soon as you have references to other objects in your objects. If you c
by gridlockd 6y ago
"Objects containing the same values should be equal by default."
No. This breaks down as soon as you have references to other objects in your objects. If you compare by reference, you probably don't get what you want. If you compare by value, you need to go arbitrarily deep, which is not a sane default, because of possible reference cycles. You need a distinction between objects and value types. C# has that (record types).
"Once created, objects and collections must be immutable."
If this is how you want to program, fine. Don't tell me this is "the right way" to program. Immutable data structures can have a lot of overhead, which disqualifies them from many domains.
The real world is all about mutable state. At some point, you need to take the training wheels off.
- dudul 6y agoThe whole point is that equality should have nothing to do with comparing references. Your comment is just making the author's point. References, cycles, mutable state these just make it harder to reason about your code. And a nice petty little zing at the end for good measure. Good job.
- tsimionescu 6y agoThe point they raise is valid, though the tone is lacking. If you want to define a graph data structure, cycles are inherent, so there must be some way to deal with them - they are not something that can simply be ignored. This is a completely practical problem, and identity instead of value equality is a valid answer. Of course, this doesn't contradict the original article: reference equality can still exist in the language, it just helps if it's not the default. For example, in Common Lisp you have both `eq` (reference equality) and `equal` (typed value equality) [and even the somewhat stranger `equalp` (structural equality, e.g. (equalp '(1 2) '(1 2)) -> true)].
- lysium 6y ago> The real world is all about mutable state. At some point, you need to take the training wheels off. Funny enough, I think the opposite is true. For example, if you have a moving point in the real world, there is never a point where only the x coordinate is mutated, yet you have that in your mutating code.
- gridlockd 6y agoThere are no points in the real world, the are things, like chairs. In the real world, if you were to move a chair to the right, the natural way to do it would not be to build the same kind of chair at the desired coordinate and then, upon discovering that you do not need the extra chair, to discard it. Yet, this is how immutable datastructures often work in practice. That may or may not be a worthy tradeoff, but please do not act like it is the right way to do things by default.
- lysium 6y agoI did not say nor act that it is the right way. I think it is easier to reason about code if you cannot (accidentally) represent things that don’t exist in your model, which in my experience happens very easily with mutable state. I used a point as an example.
- mrkeen 6y agoAccountants do not use erasers. Mutating variables in-place is the training wheels. Got a bank account? Want me to transfer money by increasing this account and decreasing that account? But perhaps that's too small an example. What about a large, distributed system? Both Paxos and Raft are recipes for clusters of machines to agree on immutable sequences of values.
- jen20 6y agoOne small nitpick with this otherwise excellent post - Paxos allows a cluster of nodes to agree on a _single_ value, not a sequence (which requires Multi-Paxos or some other similar extension of 'basic' single-decree Paxos).
- discreteevent 6y agoThey do that because they want to keep a history of each transaction. I don't want to keep a history of all the positions of a character in my game.
- mrkeen 6y ago> They do that because they want to keep a history of each transaction. It's about more than just history. Logging would (maybe) suffice for that. It's about getting cause and effect right when there's more than one computer separated by a distance. > I don't want to keep a history of all the positions of a character in my game. Sure - not in a single-player game. But can you take the same approach in a multiplayer game? Grab some players, give them different clocks and separate them 20-150ms apart from another, and have each of them tell the server what happened at the time it happened? Things will diverge pretty quickly. You end up reinventing the same old append-only log on the server. That way, when client messages arrive at the server out-of-order, you still have the info necessary to rollback state and issue corrections to other clients. When that's all set up, you can then choose some horizon (200ms?) and garbage collect all events before that. Or you can keep the events around and show replays and/or calculate stats for achievements at the end of a match.
- 6y ago
- phillipcarter 6y ago> The real world is all about mutable state. At some point, you need to take the training wheels off. So the C#, VB, and F# compilers (all huge, "immutable data representations" codebases serving millions of developers worldwide) are training wheels?
- gridlockd 6y agoNot sure what you mean, the C# compiler source code I looked at seems to be using a lot of mutable data structures. Of course immutable data structures, like training wheels, make some things easier. You don't have to worry about certain classes of errors, because they just can't happen. It's the same with garbage collection, you can stop worrying about managing memory, for the most part. However, if you can't do your job without these helpers at all, that's going to be a problem. At some point, there will be something that your garbage collector can not clean up for you. There will be state that is going to be mutated, whether you like it or not. Your brain should be prepared for that.
- phillipcarter 6y ago> Not sure what you mean I work with the C#/VB codebase for my job (at Microsoft on compilers and language tooling) and with the compiler and tooling engineers who also use this codebase. It uses nearly everything under the sun, but is most definitely based on immutable data representations at many layers of its "stack". The very notion of a compilation and a syntax tree are immutable. > Of course immutable data structures, like training wheels, make some things easier. You don't have to worry about certain classes of errors, because they just can't happen. It's the same with garbage collection, you can stop worrying about managing memory, for the most part. I know. I work on a language that is immutable by default. > However, if you can't do your job without these helpers at all, that's going to be a problem. At some point, there will be something that your garbage collector can not clean up for you. There will be state that is going to be mutated, whether you like it or not. Your brain should be prepared for that. It's not quite how you characterized it, but yes there are circumstances where a "mutable core" or even just a mutable domain make sense. Usually it's related to performance. The GC "not cleaning things" doesn't really have much to do about that though. You can create all kinds of mutable data (e.g., very large arrays) that the GC won't clean as a part of a gen0 collection.