Switch to the dark mode that's kinder on your eyes at night time.

Switch to the light mode that's kinder on your eyes at day time.

Switch to the dark mode that's kinder on your eyes at night time.

Switch to the light mode that's kinder on your eyes at day time.

in ,

Object-Oriented Programming and Essential State, Hacker News


Back in 2015, Brian Will wrote a provocative blog post:Object-Oriented       Programming: A Disaster Story. He followed it up with a video calledObject-Oriented Programming is Bad, which is much more       detailed. I recommend taking the time to watch the video, but here’s my one-paragraph summary:


The Platonic ideal of OOP is a sea of ​​decoupled objects that send stateless messages to one another. No one       really makes software like that, and Brian points out that it doesn’t even make sense: objects need to know which       other objects to send messages to, and that means they need to hold references to one another. Most of the video       is about the pain that happens trying to couple objects for control flow, while pretending that they’re decoupled       by design.


Overall his ideas resonate with my own experiences of OOP: objects can be okay, but I’ve just never been       satisfied with object –orientationfor modeling a program’s control flow, and trying to make code       “Properly” object-oriented always seems to create layers of unneccessary complexity.


There’s one thing I don’t think he explains fully. He says outright that “encapsulation does not work”, but       follows it with the footnote “at fine-grained levels of code”, and goes on to acknowledge that objects can       sometimes work, and that encapsulation can be okay at the level of, say, a library or file. But he doesn’t       explain exactly why it sometimes works and sometimes doesn’t, and how / where to draw the line. Some people might       say that makes his “OOP is bad” claim flawed, but I think his point stands, and that the line can be drawn       

If you haven’t heard this usage of the terms “essential” and “accidental” before, you should check out Fred       Brooks’ classicNo Silver       Bulletessay. (He’s written many great essays about building software systems, by the way.) I’ve aleady       writtenmy own post about essential and       accidential complexitybefore, but here’s a quick TL; DR: Software is complex. Partly that’s because we want       software to solve messy real-world problems, and we call that “essential complexity”. “Accidental complexity” is       all the other complexity that exists because we’re trying to use silicon and metal to solve problems that have       nothing to do with silicon and metal. For example, code for memory management, or transferring data between RAM       and disk, or parsing text formats, is all “accidental complexity” for most programs.


Suppose you’re building a chat application that supports multiple channels. Messages can arrive for any       channel at any time. Some channels are especially interesting and the user wants to be notified or pinged when a       new message comes in. Other channels are muted: the message is stored, but the user isn’t interrupted. You need       to keep track of the user’s preferred setting for each channel.


One way to do it is to use a map (a.k.a, hash table, dictionary or associative array) between the channels and       channel settings. Note that a map is the kind of abstract data type (ADT) that Brian Will said can work as an       object.       

If we get a debugger and look inside the map object in memory, what will we see? We’ll find channel IDs and       channel settings data of course (or pointers to them, at least). But we’ll also find other data. If the map is       implemented using a red-black tree, we’ll see tree node objects with red / black labels and pointers to other       nodes. The channel-related data is the essential state, and the tree nodes are the accidental state. Notice       something, though: The map effectively encapsulates its accidental state – you could replace the map with another       one implemented using AVL trees and your chat app would still work. On the other hand, the map doesn’t       encapsulate the essential state (simply usingget ()and (set))methods to access data       isn’t encapsulation). In fact, the map is as agnostic as possible about the essential state – you could use       basically the same map data structure to store other mappings unrelated to channels or notifications.


And that’s why the map ADT is so successful: it encapsulates accidental state and is decoupled from essential       state. If you think about it, the problems that Brian describes with encapsulation are problems with trying to       encapsulate essential state. The benefits that others describe are benefits from encapsulating accidental       state.       

It’s pretty hard to make entire software systems meet this ideal, but scaling up, I think it looks something       like this:


  • No global, mutable state

  • Accidental state encapsulated (in objects or modules or whatever)

  • Stateless accidental complexity enclosed in free functions, decoupled from data

  • Inputs and outputs made explicit using tricks like dependency injection

  • Components fully owned and controlled from easily identifiable locations

Some of this goes against instincts I had a long time ago. For example, if you have a function that makes a       database query, the interface looks simpler and nicer if the database connection handling is hidden inside the       function, and the only parameters are the query parameters. However, when you build a software system out of       functions like this, it actually becomes more complex to coordinate the database usage. Not only are the       components doing things their own ways, they’re trying to hide what they’re doing as “implementation details”.       The fact that a database query requires a database connection never was an implementation detail. If something       can’t be hidden, it’s saner to make it explicit.


I’m wary of feeding the OOP and functional programming false dichotomy, but I think it’s interesting that FP       goes to the opposite extreme of OOP: OOP tries to encapsulate things, including the essential complexity that       can’t be encapsulated, while pure FP tends to make things explicit, including some accidental complexity. Most of       the time, that’s the safer side to go wrong, but sometimes (such as whenbuilding self-referential data structures in a purely functional       language) you can get designs that are more for the sake of FP than for the sake of simplicity (which is why       Haskell includes some escape       hatches). I’ve written before aboutthe       middle ground of so-called “weak purity”.


Brian found that encapsulation works at a larger scale for a couple of reasons. One is that larger components       are simply more likely to contain accidental state, just because of size. Another is that what’s “accidental” is       relative to what problem you’re solving. From the chat app user’s point of view, “accidental complexity” is       anything unrelated to messages and channels and users, etc. As you break the problems into subproblems, however,       more things become essential. For example, the mapping between channel names and channel IDs is arguably       accidental complexity when solving the “build a chat app” problem, but it’s essential complexity when solving the       “Implement thegetChannelIdByName ()function” subproblem. So, encapsulation tends to be less useful       for subcomponents than supercomponents.


By the way, at the end of his video, Brian Will wonders if any language supports anonymous functions that       can’taccess they scope they’re in.Ddoes. Anonymous lambdas in D are       normally closures, but anonymous stateless functions can also be declared if that’s what you want:


importstd.stdio;voidmain(){    intx=41;    // Value from immediately executed lambda    autov1=(){        returnx1;    } ();    Writeln(v1);    // Same thing    autov2=delegate(){        returnx1;    } ();    Writeln(v2);    // Plain functions aren't closures    autov3=function(){        // Can't access x        // Can't access any mutable global state either if also marked pure        return42;    } ();    Writeln(V3);}


Brave Browser
Read More

What do you think?

Leave a Reply

Your email address will not be published.

GIPHY App Key not set. Please check settings

Current Time – Bulletin of the Atomic Scientists, Hacker News

Current Time – Bulletin of the Atomic Scientists, Hacker News

Realty bites: Indian property slump leaves beleaguered banks exposed – Economic Times, The Times of India

Realty bites: Indian property slump leaves beleaguered banks exposed – Economic Times, The Times of India

Back to Top

Log In

Forgot password?

Forgot password?

Enter your account data and we will send you a link to reset your password.

Your password reset link appears to be invalid or expired.

Log in

Privacy Policy

To use social login you have to agree with the storage and handling of your data by this website. %privacy_policy%

Add to Collection

No Collections

Here you'll find all collections you've created before.