9 ms·
You gotta stick the state somewhere. OO isn't the panacea it was sold as, but it's worked out pretty well for a lot of software. Still, this quote is hilariou
by recursivedoubts 6y ago
You gotta stick the state somewhere. OO isn't the panacea it was sold as, but it's worked out pretty well for a lot of software.
Still, this quote is hilarious:
"Object-oriented programming is an exceptionally bad idea which could only have originated in California."
--Edsger Dijkstra
- staticassertion 6y agoIt's not about eliminating state it's about hiding it. OOP hides state, which means mutability is often shared and hidden.
- sodapopcan 6y agoI'm ripping a quote from another HN user the last OO/FP discussion I read on so apologies if you see this and are like, "Hey! I said that!" buuuut: OO says: "State is hard—let's hide it!" (er, sorry, "encapsulate it") FP says: "State is hard—let's isolate it!"
- bmitc 6y agoI think languages like F# and Racket get it right, because multiple paradigms are available to you. I like F#’s stance on functional-first programming. There are times in which you want to expose the underlying types and there are times you do not. When I recently started a ray tracer implementation, it was a good example of this. The vector, color, point, transform, world, camera, etc. types where all readily implemented by records and discriminated unions which properly isolated but exposed the types. However, for the matrix library, I chose to use F#’s Array.Parallel library and thus a 1D array as the underlying implementation, and this was a perfect use case for using a class. I wanted to hide the implementation of the matrices from the user of the type and encapsulate the internal behavior, only exposing a clean API. Even in that case, the matrix type was immutable because the operations on matrices would simply return new matrices. I think F#’s acceptance of multiple paradigms is really the way to go.
- colllectorof 6y agoEncapsulation has nothing to do with hiding stuff. It is the idea that an object is effectively defined by its externally observable behavior.
- sodapopcan 6y agoI was being cheeky—I regret it.
- mmis1000 6y agoProbably "State is hard—let's eliminate it!" is better if it is possible. Lots of states just shouldn't exist at first place because they are clearly derivations of some other state.
- deleted 6y ago[deleted]
- mumblemumble 6y agoThat's what college textbook OOP taught us. It only took me a couple decades to figure out that college textbook OOP taught us wrong. If all you're doing is hiding state, it's like sweeping dirt under the carpet - you're skimping on your work now, in a way that will only create more work later. Good object oriented design goes much, much further. To quote Alan Kay, "Doing encapsulation right is a commitment not just to abstraction of state, but to eliminate state oriented metaphors from programming." (emphasis mine)
- staticassertion 6y agoWell yeah, obviously Kay and Armstrong agree.
- eyelidlessness 6y agoNot only that, but it’s pretty clear the philosophical roots of OOP are basically just FP with a particular organizational model. The idea was never “everything is mutable and gets to mutate everything else unless you say otherwise”, it was about organizing functions (real functions) with the specific data they operate on. The big blob of imperative programming that got bolted onto that is a disservice to the idea. But unfortunately that cat’s been out of that bag for decades and isn’t going anywhere.
- zozbot234 6y ago> Not only that, but it’s pretty clear the philosophical roots of OOP are basically just FP with a particular organizational model. That's true of much of OOP, but implementation inheritance is the elephant in the room - it can't be modeled or understood using a pure FP model, because the combination of late binding and so-called 'open recursion' requires a dispatch step on all virtual method calls (that would in turn be modeled in FP via a "tying the knot" trick). The resulting semantics are extremely tricky, and most practitioners are aware of the problems with them (see "fragile base class"). Some recent programming languages have abandoned implementation inheritance altogether, e.g. Rust. IOW, they're really more like FP-semantics languages with OOP-like syntactic sugar on top.
- mathgladiator 6y ago"You gotta stick the state somewhere." I like this a lot as I run into so many arguments about stateless this or stateless that, and what gets lost is that not contending with state is problematic. Databases are forced to get massive and do all sorts of goofy shit so some people don't have to ever think about state; this goofy shit creates interesting reliability challenges which translates to bad user experiences. For my future projects, I've decided to build my own application-as-state-database-container thing: http://www.adama-lang.org/docs/why-the-origin-story http://www.adama-lang.org/docs/why-the-origin-story Granted, I'm focused on niche board games since they redefine complexity.
- coldtea 6y ago>Databases are forced to get massive and do all sorts of goofy shit so some people don't have to ever think about state; this goofy shit creates interesting reliability challenges which translates to bad user experiences. Huh? Databases don't do anything "goofy", they implement ACID guarantees. Which absolutely beats the untold horros of Chtulu proportions that would emerge if programmers had to implement state management at the persistence layer for multiple clients themselves (they'd implement a DB + ACID poorly and in an ad-hoc way, full of holes). What people seem to forget is that relational databases are not the first technology we had for periststent state. The first versions were custom solutions per app, application-as-state and various ad-hoc such databases with their own formats and techniques, which were such a hellist landscape, devs jumped at relational databases with utter joy...
- watwut 6y ago> Huh? Databases don't do anything "goofy", they implement ACID guarantees. I think that he meant that functionality that should not is pushed into database. I have definitely seen project full of crazy triggers and sql procedures and so on.
- mathgladiator 6y agoSo, databases don't do anything goofy, but developers sure do. Especially when scale (real or not) is in the picture. I'm a fan of databases myself, but I am also a fan of document stores as well.
- kiliancs 6y agoI read the quote first and I thought you meant California when you said "the state".
- the__alchemist 6y agoStructs and classes work fine for that. You don't need getters/setters/inheritance/factories etc.
- millstone 6y agogetters, setters, and factories allow the implementation to evolve without breaking client code.
- bccdee 6y agoThat only matters for interfaces which you expose to clients. The real problem with getters & setters & such is when they gum up the internal workings of a codebase, abstracting over nothing and complicating things unnecessarily.
- millstone 6y agoI agree with that. If you create accessors as a matter of course, then you are mostly adding dead weight. But accessors can add a useful layer of abstraction at the interface layer, as you say.
- Gibbon1 6y agoC# allows you to define getters and setters after the fact without breaking client code. foo.bar = x; // could be normal assignment or a setter.
- thatjoeoverthr 6y agonot quite! a property is a pair of methods. if you replace a member with a property, it does remain code compatible as you describe, but breaks the ABI. so if you do this in a published library, clients require a recompile. for this reason, they recommend: 1) different naming convention between members and props 2) dont expose members; use properties from the start for anything public to assist with two, they introduce the default get/set implementation, like so: public object Derp { get; set; } for when you want to expose an interface with the assignment idiom but dont actually have any interesting implementation
- flukus 6y agoIt's not the state that's the problem, it's the state being bundled with the code that operates on the state.
- pansa2 6y agoWhy shouldn’t they be bundled together? They’re completely interdependent - each is useless without the other.
- hderms 6y agoWell the common FP answer is that data might have many operations on it that are totally orthogonal and that don't depend on shared behavior. I say this as someone who thinks both paradigms have something to offer.
- meheleventyone 6y agoGenerics?
- lmm 6y agoNamespacing them together is good. Hiding the coupling between them isn't. If a function makes use of some data, you want to see where that data comes from, not have the function fetch it via a magic portal to some other part of your code.
- eyelidlessness 6y ago> You gotta stick the state somewhere. This is true, and it’s the primary reason I’m not finding some way to work in Haskell. But it’s also kind of a cop out. The issue isn’t just that state exists and will do well beyond our extinction. It’s not even just about how you manipulate state or how many restrictions you put on mutability. It’s also about the visibility of state and stateful processes, how that’s signaled, and the conventions that fall out. This isn’t something I fully understood until I worked with Clojure. Immutable-by-default was a fantastic constraint. But more valuable to me was that where state is accessed or changed, you can tell immediately. Just having that gives you several insights: - This code is more likely to be impacted by outside behavior - This code has additional concurrency requirements - This code may be unnecessarily complex - This code may be hard to understand a week or more later - This code is documenting its implicit dependencies Since I’ve moved on from Clojure I’ve mostly worked in TypeScript, and I’ve done my best to apply the same principles. In some ways it’s a loss: you can’t signal stateful access with @ or ! or *. But that’s all convention. In other ways it’s a huge win: if you’re trying to write functional code in TS, you eventually end up with the idiom that async/await and Promise types are generally signals of state. And the type system calls that out much more reliably. All of that said, you do gotta stick the state somewhere. But where and how you do is the difference between eternal pain and eternal much-less-pain. And coupling state with functions on objects is definitely more likely to produce more eternal pain.
- marcosdumay 6y ago> it’s the primary reason I’m not finding some way to work in Haskell Ok, now I'm curious about how StateT fails it.
- eyelidlessness 6y agoOnly that I didn’t know about it! I’ve only admired Haskell from afar.
- wglb 6y agoAnd it still amusing how intensely Alan Kay trashes him.
- coldtea 6y ago>You gotta stick the state somewhere The state is just data structures. You don't need to stick it anywhere aside from some namespace. You can then have functions operating on those data structures and be fine. For protection/privacy just make sure access to the data structure instances is not global.
- ww520 6y agoIn FP, the state got passed around in the function parameters and the return value. Oof.