3 ms·
I am not sure I understand your differentiation of explicit and implicit state. I believe you refer to Objects that change their internal values over time; in t
by cessor 6y ago
I am not sure I understand your differentiation of explicit and implicit state. I believe you refer to Objects that change their internal values over time; in that calling the same function twice yields different results. Of course, such objects can be a pain to use.
Objects are all about making state explicit. Constructors connect different primitive values to a higher order concept, goal or task and checks invariants; The object's class gives the primitives a type which IS a form of state. A Year(2005) could guarante that the integer is > 1970; an int can do that on its own. 'hello@example.com' is not just a string; it should be an Email address and modelling this with an explicit class communicates state: that string is not just any string (all of Shakespeare's work in mandarin in base64) but a specific kind of string (an Email address). The mere existence of a valid object then communicates state, as do all types. I'd argue: Objects are all about making state explicit.
Still, it is really easy to abuse objects and make state implicit as you described above. I would argue that getters and setters are plain wrong to begin with, but that is a nother topic.
For example, if you do `Wallet.pay(amount)`, Ideally, you should get a new instance of a Wallet with the reduced amount, instead of reducing the internal credit variable. For many, this seems to be the wrong kind of modelling though, because when immitating the real world, you don't copy-clone your wallet physically when tipping a waiter.
Objects can and should be created immutable, but then, sometimes working with state is fine. For example an iterator (calling `bookmark = Boomark(book); bookmark.next()` a hundred times gives different page each time).
Imagine OpenGL; you send a lot of data to your graphics card and then tell it what to do with that data. Sending data is quite expensive. During rendering, you tell the pipeline what buffer to bind and what to draw at a single point in time (i.e. a frame). This is easlily represented by objects that keep track of the state. Your object-graph just remembers what buffers are bound. I, too have seen tangled and messed up designs; but I would still argue that thinking in state (my change does not go away) is intuitive for many people. Why not model systems that work like this explicitly? Shoehorning this into stateless pipelines can be quite difficult.
The problem isn't functions or objects (thats just fancy pointer syntax really) but that noone has figured out how to modell processes that work on symbols that change over time properly.
We won't fix this issue here; let's agree that we all like our state as explicit as possible as to avoid surprises and relieve or working memory.
- AnimalMuppet 6y agoI think your Wallet.pay(amount) example argues for a different conclusion than you arrive at. I have a Wallet with $500 in it. I call Wallet.pay(100). In your approach, it returns a new Wallet with $400 in it. But I also still have the old, unmutated Wallet with $500 in it, which could be referred to by mistake (or by malice). That's probably not the best argument for immutable objects...
- josephcsible 6y agoThat's actually an argument in favor of linear or affine types. In your example, you'd still get a new Wallet from that function, but the compiler would keep you from accidentally using the old one afterwards. That way, you can't make that mistake, but still get the benefits of immutability.
- cessor 6y agoI will admit that I don't know what "linear types" or "affine types" are. Your answer makes me feel like I am trying to convey an idea for which you have the perfect formalism / meta vocabulary. It might be that objects, or at least the way that I know how to use them in my favorite languges, are just a (potentially limited) implementation of said formalism. I feel that objects offer a flexibility benefit though (which is why they often elude formal approaches) for the cost of purity.
- josephcsible 6y agoRust is probably the most mainstream language that uses affine types. Once you call a function that takes ownership of a value (e.g., `drop`), the compiler won't let you use it anymore after the function call.
- cessor 6y agoIf you limit the scope of usage, the old wallet should be garbage collected as soon as you have the new one. If you don't want to rely on that, or the point in time when gc happens is important or you're dealing with sensitive data, then the environment should allow you to perform appropriate cleanup actions and for you to utilize a different means to control and protect the data.