[HN Gopher] Pitfalls of object oriented programming (2009) [pdf]
       ___________________________________________________________________
        
       Pitfalls of object oriented programming (2009) [pdf]
        
       Author : davikr
       Score  : 73 points
       Date   : 2023-12-27 12:19 UTC (1 days ago)
        
 (HTM) web link (harmful.cat-v.org)
 (TXT) w3m dump (harmful.cat-v.org)
        
       | hurril wrote:
       | I think this description of what OO is, is flawed and makes
       | people talk past each other:
       | 
       | > * What is OO programming? - a programming paradigm that uses
       | "objects" - data structures consisting of datafields and methods
       | together with their interactions - to design applications and
       | computer programs. (Wikipedia)
       | 
       | It isn't that they are together, it's that the core entity of the
       | language used to express solutions centers around identity over
       | state or values. As in: two objects are different even when the
       | fields are all equal, and also: two objects can be the same even
       | with different field values.
       | 
       | If you are going to object to this, I ask that you first
       | contemplate whether or not you have programmed in any other way
       | first, because as a fish, reasoning about what water is can be
       | difficult.
        
         | kragen wrote:
         | i am going to object to this; i've programmed in, among other
         | things, prolog, ocaml, basic-80, c, the unadorned l-calculus,
         | bicicleta, and qfitzah, the last two of which are languages i
         | designed and implemented myself and which have no mutability.
         | moreover i don't think anyone would claim that basic-80 or c is
         | object-oriented
         | 
         | so i feel secure in claiming that i am more a walrus than a
         | fish and therefore qualified to opine about water
         | 
         | i do agree that identity and hidden mutability are important
         | aspects of the oo view of the world, and that the author of
         | these slides is off-base about what oo is. but i think that the
         | _essence_ of oo is that computation is done by sending messages
         | to objects, but sending the same message to different objects
         | invokes different code. this feature is present without
         | mutability in bicicleta, and in abadi and cardelli 's untyped
         | s-calculus, which it's based on; the s-calculus was invented to
         | formalize the essence of object-oriented typing
         | 
         | the original intuition behind oo was to decompose a computer
         | system into smaller computer systems, like a computer network;
         | each object in the system was in effect a tiny computer, with
         | its own private code and state. this was inspired by alan kay's
         | undergraduate degree in biology, which mostly studies organisms
         | made out of cells, which are basically tiny organisms. and in
         | that formulation, obviously hidden mutability is the default,
         | because you can't prevent a computer from changing its internal
         | state as a result of a packet you send it; and mutability
         | generally means identity is important
         | 
         | but even more central to this formulation is the idea that
         | different objects can behave differently in the same
         | circumstances
         | 
         | obviously none of this has anything to do with memory layout!
         | except very indirectly
        
           | bruce343434 wrote:
           | This is it. OOP is about building sub programs with their own
           | state and behaviours, yet implementing a common interface so
           | they can still effectively communicate to each other.
           | 
           | If you boil it down to the essence, this means branching
           | logic is encoded via a function pointer. Instead of manually
           | switching to the correct behavior using other branching
           | mechanisms like if or switch.
           | 
           | This is what polymorphism is about. It's pattern matching.
           | 
           | An interface is like an Enum to which you can add entries
           | after it has been defined, and the behaviour for that
           | specific variant naturally then has to be encoded inside the
           | variant itself.
        
             | Gehinnn wrote:
             | Would it be far fetched to say object oriented programming
             | is inspired by nature/physics?
             | 
             | And thus, "more natural" than, let's say, procedural
             | programming.
             | 
             | Animals can be modeled nicely with objects/classes.
             | Physical objects do have internal private state and public
             | interfaces. Also in nature, usually, you have multiple
             | similar objects that work the same but have different
             | internal state.
        
               | bruce343434 wrote:
               | That might have been what Alan Kay was going for with his
               | "cells of an organism" thing, yes.
               | 
               | But even if you're not inspired by biology, it might just
               | come up "naturally". Separating your data into structs,
               | then operations on those structs, and not wanting to deal
               | with all kinds of bookkeeping all the time, letting
               | things manage their own - separation of concerns, aka
               | single responsibility principle.
               | 
               | I think automatic memory management might be a big
               | example of this. Who wants to bother with this
               | malloc/free stuff all the time? Who wants to keep track
               | of ownership everywhere? Instead, have a dedicated
               | subsystem handle it. That allows a higher signal to noise
               | ratio in all the rest of the code that would otherwise be
               | polluted with malloc/free. It also removes the entire
               | class of bugs that can happen when you inevitably forget
               | either of those.
               | 
               | But having memory management in and of itself isn't
               | "OOP". It's just an example of one of the principles that
               | people tout when they talk of "OOP". Those principles can
               | and do apply broadly.
               | 
               | Was Alan Kay thinking of all this? I really don't know.
               | All I know is that the dude digs biology.
        
               | meheleventyone wrote:
               | I think more that messaging was the fundamental part.
               | Modularization and composition is pretty common in most
               | paradigms. I actually looked this up the other day for a
               | different comment but this is Alan Kay's own words on the
               | subject:
               | 
               | https://lists.squeakfoundation.org/pipermail/squeak-
               | dev/1998...
               | 
               | It's a concept I really like and use quite a bit in game
               | development at the inter/intra-entity communication level
               | even if below that I'd pick a more performant substrate.
        
             | mostlylurks wrote:
             | > OOP is about building sub programs with their own state
             | and behaviours, yet implementing a common interface so they
             | can still effectively communicate to each other.
             | 
             | This doesn't seem like a sufficient definition, as closures
             | are also sub programs with their own state and behaviors
             | that implement a common interface (the function signature),
             | and you'd have to stretch the definition of OOP to the
             | point of meaninglessness if that would be sufficient to
             | qualify as OOP.
        
           | trashburger wrote:
           | You nailed it. Object programming was never about the low-
           | level details like inheritance; it was always about managing
           | state and sharing behavior (just like function programming!).
           | Object programming looks at things from the perspective of
           | the object; each object has some state and some behavior it
           | can respond to when sent messages. Objects with compatible
           | behavior can be substituted for each other (this is the
           | essence of behaviorism[0]). This is symmetrical to function
           | programming's pattern matching where values with compatible
           | structure can be substituted as arguments to a function (this
           | is also why I firmly hold the belief that Lisp and Smalltalk
           | are symmetrical languages). Languages like Haskell even use
           | things like "Integer a =>" which are basically object
           | programming interfaces!
           | 
           | [0]: https://handbook.selflanguage.org/2017.1/progguid.html#b
           | ehav...
        
           | hurril wrote:
           | We don't disagree at all by the looks of it. I was objecting
           | (lol!) to the description of OO as code and data together.
           | _Together_ doesn't carry the necessary weight here because a
           | struct and a module of functions in the same file is also
           | code and data together.
           | 
           | It's that the receiver of those messages have an identity
           | that defines it.
           | 
           | Inheritance and polymorphim is of course central to OO, but
           | it's not defining characteristics imho because inheritance is
           | "module arithmetic" and polymorphism has plenty of flavours.
           | 
           | (I am in no way trying to have a go at OO either.)
        
         | cmrdporcupine wrote:
         | You've hit the nail on the head, and I think the replies below
         | aren't getting your original point. Which I think is actually
         | your point :-)
         | 
         | The defining feature of OO approaches is in shifting the
         | emphasis in sw development into the concept of identity-bags.
         | All the other stuff about message passing, encapsulation,
         | inheritance etc is just window dressing and implementation
         | details of this core concept of identity-classification in
         | software systems.
         | 
         | I like how the "Out Of the Tarpit" (2006) paper breaks this
         | down into the notion of "intentional" vs "extensional"
         | identity, and I think this is a great model.
         | 
         | For them, OO is all about "intentional identity" in that we
         | _create_ identities (objects, components) in our systems and
         | move attributes and behavior onto them. OO shifts the analysis
         | of software to identifying objects, components, services, and
         | then makes software development all about the taxonomical
         | management of them. In this model of software development, it
         | 's all about identifying components and then shuffling the data
         | and functionality "into" them and managing the flow between
         | them. (FWIW the paper identifies this way of thinking as one of
         | the prime culprits in unnecessary complexity in software
         | systems, and I agree with them.)
         | 
         | The contrast is "extensional" identity, where identity in the
         | software systems are emergent from their attributes. In this
         | box we can put the relational data model, and its cousins in
         | logic programming (prolog, datalog etc). In those systems, we
         | are not concerned with "creating" identities and classifying
         | systems/components/objects, but instead declaring the raw
         | attributes -- tuples, facts, relations -- only. _Queries_ then
         | produce, at runtime, a multitude of results from permutations
         | of those attributes. And, as you point out, equality
         | /inequality is defined by the value of a tuples attributes, not
         | by the object it lies in. This is crucial.
         | 
         | There's a couple generations of software developers that are so
         | immersed in the OO/intentional-identity way of thinking that
         | they don't see that it's not intrinsic to software development,
         | but actually a mental framework that was fostered through the
         | 80s and 90s. It was an attempt to manage complexity and
         | structure in software systems and also to create a marketplace
         | of re-usable components. But I think it's actually _failed_ at
         | that.
         | 
         | Most classes, objects, components, microservices end up failing
         | in two respects: they end up reflecting the company's org chart
         | more than anything else, and .. worse .. the bulk of the code
         | and complexity ends up being how one moves data between all
         | these (programmer created) systems rather than what the actual
         | data is. The relationships (lines) between the boxes becomes
         | the focus instead of the stuff was shoved into the box, and the
         | whole behavior of the system becomes difficult to reason about.
         | 
         | And when developers encounter systems that _don 't_ work along
         | this model -- relational databases, functional programming,
         | logic programming -- they often scratch their heads, resist, or
         | wrap them up/confine them in OO/component type structures...
         | damaging their usefulness.
        
           | kaba0 wrote:
           | A great, and often under-appreciated point is - as put by Guy
           | Steele - "We find that the notion of side effect and the
           | notion of equality (object identity) are mutually
           | constraining; to define one is to define the other."
           | 
           | With that in mind, I do believe that objects, as in
           | encapsulating some kind of side-effect, is a very good model.
           | But it is not a replacement for _everything_ - a more data-
           | oriented approach makes much more sense for some other parts
           | of a program. Multiple views are absolutely possible within
           | the same language /program, and should in general be the
           | preferred way.
        
             | cmrdporcupine wrote:
             | What I would like to see is a system where object-
             | orientation is emergent from a more set-oriented/relational
             | model. I haven't put my finger on what exactly this _is_
             | yet, but maybe it 's something like "methods" really being
             | a kind of predicate-dispatch over matching tuples.
             | 
             | So a "class" (and object identity) is really telling the
             | system: when you see attributes X, Y, Z bundled together as
             | a result of a query, here is a set of behaviors that you
             | can apply on those tuples.
        
               | kaba0 wrote:
               | I don't know, relational model seems to be fundamentally
               | mathematical/side-effect free.
               | 
               | Like, I think we should think of a `Connection` as an
               | object, not `User`, which is just plain data.
        
               | cmrdporcupine wrote:
               | I get your point, but ... updates on tuples are
               | definitely a "thing" in a relational system... and the
               | set of connections and their attributes and state can be
               | modeled in relations quite easily... Not sure I see a
               | conflict.
        
               | kaba0 wrote:
               | Fair enough, though I think a functional approach (you
               | create a new set from the old, with one field changed),
               | and somehow "committing" it back is fine, and no need for
               | side effecting then (besides at the boundary).
               | 
               | Maybe structural typing is somewhat similar to what you
               | think of? Probably typescript, maybe go are the most
               | well-known for this out of the statically typed ones, but
               | clojure is also all about every "object" being a key-
               | value map.
        
               | cmrdporcupine wrote:
               | Yeah, a functional approach is fine. In reality you can
               | think of an "update" to a tuple in a relation as a
               | "replace this relation-valued variable with a new one
               | where this tuple has been modified." And so mutations to
               | base relations ("tables" in SQL parlance) just means
               | changing the value of that relation in in the global
               | shared, named base relation list. And if you use a
               | persistent data structure behind the scene, and do CoW
               | etc, you can even probably make this relatively
               | efficient...
               | 
               | And I don't think it's so much structural typing, as it
               | is defining method/function dispatch off predicate
               | matches. More.. structural values? Clumsily:
               | 
               | Disconnect(connection_id) = with project ConnectionState
               | CS where CS.Id = connection_id { if CS.state !=
               | 'connected Raise('not_connected) else CS.state =
               | 'disconnected }
        
               | senderista wrote:
               | Mutating a tuple in a relation doesn't really make sense
               | _per se_ , because a relation is just a subset of the
               | cartesian product of its attribute domains, and only
               | value-based semantics apply to sets. What does make sense
               | is identifying a primary key for a relation, deleting a
               | tuple, and inserting another tuple with the same primary
               | key but different values of its other attributes. In
               | practice, of course, this is equivalent to in-place
               | mutation of identity-objects corresponding to unique
               | values of the primary key.
        
           | hurril wrote:
           | Indeed, we seem to understand each other. A very well put
           | post of you!
           | 
           | I've come to appreciate these difference in later efforts to
           | learn functional programming as a way of giving myself more
           | tools. But for the longest time, it was very difficult for me
           | to "get the boxes right" for what things go where. What is a
           | module, an object, a function, a method, etc, coming from the
           | object oriented universe.
           | 
           | I still have the urge to "create objects" when I
           | conceptualise solutions and _imho_ this isn't always a good
           | path.
           | 
           | These days OO exists within my horizon of tools for solving
           | tasks. Before, it was the water, if you will. Some problems
           | have a want for objects, others don't really.
        
             | cmrdporcupine wrote:
             | Cool. Where do you work?
        
               | hurril wrote:
               | I am a freelance programmer. I don't wish to out such
               | information here.
        
       | abberation wrote:
       | cat-v at it again lmao
        
         | Baldbvrhunter wrote:
         | The site builder, Uriel [0], was like those of us in his
         | circle, strongly opinionated.
         | 
         | Sadly he suicided in 2011 with Sodium Pentothal he bought mail
         | order from China. My final Skype message to him was "goodnight,
         | don't drink the pentothal!" and Skype used to show it to me
         | under his username every time I logged in.
         | 
         | He, and his acerbic nature, are sorely missed.
         | 
         | [0] https://www.reddit.com/user/uriel/
        
         | kaba0 wrote:
         | if you mean that ridiculous "gcc/pdf/web browser is ridiculous,
         | use tcc/txt file/curl" bullshit page, then I can't take you
         | seriously. Feel free to use a pocket calculator instead of your
         | current device, I guess, that's not bloated.
        
       | robaye wrote:
       | The original author revisited this talk[1][2] in 2017. You can
       | also read more of the same ideas from the data-oriented-design
       | list[3].
       | 
       | 1. https://www.youtube.com/watch?v=VAT9E-M-PoE
       | 
       | 2.
       | https://docs.google.com/presentation/d/1ST3mZgxmxqlpCFkdDhtg...
       | 
       | 3. https://github.com/dbartolini/data-oriented-design
        
       | nemoniac wrote:
       | "I invented the term 'object-oriented', and I can tell you C++
       | wasn't what I had in mind." ~ Alan Kay, OOPSLA '97
        
         | vendiddy wrote:
         | I believe Erlang/Elixir are closer to what he had in mind.
         | (Processes with encapsulated state passing messages to each
         | other.)
        
           | freetonik wrote:
           | And also Smalltalk, I believe. It appeared ~15 years earlier
           | than Erlang. The idea of holding encapsulated state and
           | receiving messages is its core concept, AFAIK.
        
             | kragen wrote:
             | guess who headed the smalltalk team and what team he was
             | working on when he invented the term 'object-oriented'
        
           | frou_dh wrote:
           | It does make a lot more sense if messaging is asynchronous,
           | because the metaphor breaks down immediately if sending any
           | message requires the sender to freeze until a reply comes
           | back.
        
         | lucidguppy wrote:
         | I don't think anyone would "want" CPP. It feels like it's
         | multiple layers of "this is how we've always done it"
         | interleaved with some really good ideas (STL).
        
         | kaba0 wrote:
         | Just because someone coined the term, doesn't mean that they
         | get to define it. The industry absolutely _doesn 't_ use OOP in
         | any way similar to what Alan Kay does, and the former is the de
         | facto correct usage.
        
           | cmrdporcupine wrote:
           | It's also worth pointing out that as smart and important of a
           | guy as he is, Alan Kay has not been employed as a software
           | developer for a very long time.
           | 
           | What OO has become in the industry is a product of practical
           | concerns encountered by people working in the field. Can't
           | say I like it much, but working in this industry for 25ish
           | years, I can understand the pragmatic "whys" of every step of
           | language and tool design fairly well.
        
       | freetonik wrote:
       | I find "modern" OOP concepts apply pretty well to graphical user
       | interfaces. I believe that a good UI has a consistent and
       | relatively strict hierarchy, with few "unique snowflake"
       | elements. Even such a divisive idea as multiple inheritance often
       | makes sense in UI, i.e. there could be an element inheriting low-
       | level behavior (HTTP/API call, etc) from a button and a high-
       | level behavior (style/presentation, etc) from a visual class.
       | 
       | (In a way, even CSS is kind of OOP, albeit with very confusing
       | overriding rules.)
       | 
       | When writing generic backend code in a language like Java, I
       | often found fighting against OOP because the business logic is
       | not necessarily mappable to "dog inherits from animal". And I
       | can't change the business logic, so OOP has to give in. But when
       | developing user interfaces, I am usually in more control, I am
       | actually designing it, not observing directly from the business
       | logic. And OOP forces me to have a more consistent
       | implementation, which is beneficial for the user, because
       | consistent UI makes it easy for people to get used to it, find
       | the underlying logic in it, and start relying on it. If all links
       | on all web pages would inherit from normal HTML href link (like
       | it was designed in the beginning), we wouldn't suffer from those
       | weird JS web apps where you can't open a link in a new page for
       | example.
        
         | trashburger wrote:
         | Inheritance is usually not the solution; composition and
         | delegation is. Unfortunately, the current landscape of popular
         | languages have equated "object programming == inheritance" in
         | people's minds. The fact that these languages make inheritance
         | easy but provide no syntactical or semantic support for
         | composition and delegating to inner objects compounds this
         | problem.
         | 
         | > there could be an element inheriting low-level behavior
         | (HTTP/API call, etc) from a button and a high-level behavior
         | (style/presentation, etc) from a visual class.
         | 
         | This becomes very messy very quickly, and you would need to
         | clearly separate the concerns to make them non-expressible on
         | either side. CSS and JS make this possible by being two
         | different languages, one Turing-incomplete (in usual
         | scenarios).
        
           | frou_dh wrote:
           | I think of inheritance as just being a workaday
           | implementation detail to _facilitate code reuse_ in some
           | scenarios. Polymorphism ( "many forms") is more related to
           | the concept of interfaces, but as you touch on has been
           | equated with inheritance in a lot of peoples' minds.
        
             | _a_a_a_ wrote:
             | Inheritance should be used for interfaces, not code reuse
             | (unless that comes free with it).
        
               | nradov wrote:
               | Then how do you avoid duplicate code without using
               | inheritance? Other solutions like placing shared
               | functions in "helper" classes are far worse from a
               | complexity and maintainability standpoint.
        
               | javcasas wrote:
               | "helper" classes are a symptom of an object-obsessed
               | programming language, a language where functions can't
               | live in a module, they must always exist in a class.
               | Especially if it doesn't make sense for a class to hold
               | them.
               | 
               | You avoid duplicated code by making generic functions,
               | putting them in modules, and making your objects accept
               | them as parameters.
        
             | magicalhippo wrote:
             | In Delphi, this is my preferred way. I use interfaces[1]for
             | the public-facing stuff, but I might use inheritance to
             | implement the interfaces for code reuse and ease. I of
             | course also use delegation a lot, but for some things I
             | feel inheritance is a better fit.
             | 
             | Regardless, the inheritance remains an implementation
             | detail.
             | 
             | [1]: https://docwiki.embarcadero.com/RADStudio/Alexandria/e
             | n/Inte...
        
           | _a_a_a_ wrote:
           | > make inheritance easy but provide no syntactical or
           | semantic support for composition and delegating to inner
           | objects compounds this problem
           | 
           | I admit I would really like a 'delegate function call to
           | <object>' construct, but excuse me for being dense, what
           | composition are you referring to? Other than inheritance and
           | delegation, what else is there[1] , and what would a suitable
           | construct supporting it in the language look like? TIA
           | 
           | [1] (there is functional-style composition, but that's
           | perfectly well supported in many decent languages like Scala)
        
             | Tmpod wrote:
             | > I admit I would really like a 'delegate function call to
             | <object>' construct
             | 
             | Yeah, I'd love to see Kotlin's delegation[0] developed
             | further and appear in other languages as well.
             | 
             | [0]: I admit I would really like a 'delegate function call
             | to <object>' construct
        
               | mike_hearn wrote:
               | Kotlin's delegation feature is useful sometimes, but OOP
               | inheritance still crops up more often.
               | 
               | One reason is that inheritance is strictly more powerful.
               | When you delegate (compose), you can't modify the inner
               | working of the object you delegated to, you can only wrap
               | it. Often that's not sufficient. You want to actually
               | customize the implementation in some way. OOP's
               | inheritance is ideal for this, because the superclass can
               | clearly define chunks of functionality that subclasses
               | are allowed to either (a) replace entirely or (b) wrap or
               | (c) provide (abstract methods).
               | 
               | This is a very flexible approach. With mere delegation
               | you can only wrap, and only for method calls that
               | originate _outside_ the object, and only for public
               | methods.
               | 
               | It's also clean. The distinction between what you must
               | implement, what you can implement and what is for the
               | user is defined in the type system and enforced by the
               | compiler. Additionally you separate the interface for
               | customizations from the interface for users (protected vs
               | public), which keeps documentation and auto complete
               | properly focused.
               | 
               | When combined with dependency injection and code
               | generation it also allows third party frameworks and
               | libraries to enhance the code you write in various ways,
               | that remain mostly tucked out of the way but can be
               | revealed in an IDE in an instant (and a good IDE will
               | show visual hints that there are such customizations in
               | effect).
               | 
               | The final advantage is that in some languages the
               | implementation is highly optimized. On HN you'd be
               | forgiven for thinking nobody writes virtual method calls
               | since 20 years ago but in reality virtual method dispatch
               | is so common in real programs that it's heavily optimized
               | by both CPUs (sophisticated indirect branch caching) and
               | language runtimes (PICs in fast VMs like Hotspot or V8).
               | Composition is less well optimized.
               | 
               | Inheritance gets an overly bad rap on Hacker News,
               | despite how prevalent it is. I think this is because it's
               | so flexible you can easily make a mess with it, and some
               | people have. Also the decision of Java to make all
               | classes and methods open by default means overriding is
               | often used as a hacky way to hot-patch libraries in the
               | field, rather than as part of any principled overall
               | design. Kotlin reverses that decision to some extent and
               | so classes and methods are all final by default, unless a
               | compiler plugin overrides that.
               | 
               | I also suspect the move to web development has had this
               | effect, because in most classical OOP toolkits you are
               | allowed or even encouraged to extend the UI by
               | subclassing pre-existing node types. So you can make a
               | custom button by subclassing Button or whatever. HTML is
               | implemented using classical OOP designs, but mostly for
               | implementation reasons that isn't exposed to the web
               | developer who instead is expected to customize the
               | controls purely through CSS and setting properties. If
               | you want to make a custom button widget, well that's too
               | bad, better learn React or something similar. So people
               | just aren't exposed to the situations where OOP is useful
               | because browsers weren't designed for UI, and the memory
               | of why it was originally developed atrophies.
               | 
               | And some of it is just memeing.
               | 
               | OK, now tell me why I'm wrong.
        
               | _a_a_a_ wrote:
               | I don't have much time so pardon the brevity, but I
               | believe it's been proven that inheritance and delegation
               | have equal expressiveness.
               | 
               | > Often [delegation] not sufficient. You want to actually
               | customize the implementation in some way. OOP's
               | inheritance is ideal for this
               | 
               | The usual way of customising behaviour without
               | inheritance is to pass in an object to actually implement
               | the behaviour.                   var LogToConsole = new
               | logger(new WriteToConsole());
               | 
               | vs                   var LogToFile = new logger(new
               | WriteToFile());
               | 
               | Which customises the logger class. Trivial example but I
               | use this a lot.
               | 
               | > I think this is because [inheritance is] so flexible
               | you can easily make a mess with it, and some people have
               | 
               | agreed
        
               | mike_hearn wrote:
               | It's all Turing complete, so of course you can implement
               | the same thing as protected methods by using callbacks.
               | When I say power here I don't mean in the sense that you
               | literally can't do it any other way, I mean it's more
               | convenient and natural.
               | 
               | C++/Java/Kotlin style OOP is basically about putting
               | common design patterns into language syntax. You could do
               | it all with C, but it's easier if the compiler does it
               | for you. For example Kotlin has "data classes" and Java
               | now has "records" which are in both cases classes, but
               | they sacrifice inheritance in order to auto-generate more
               | boilerplate for you. That's still OOP though.
        
               | lmm wrote:
               | > One reason is that inheritance is strictly more
               | powerful. When you delegate (compose), you can't modify
               | the inner working of the object you delegated to, you can
               | only wrap it.
               | 
               | It's more powerful, sure, but in the same way that goto
               | is more powerful than if/for/while. In theory some
               | languages give you the tools for a superclass to expose a
               | stable interface to its subclasses (ish - even Java
               | doesn't give you a way to specify "subclasses may read
               | but not write this field", for example), but in practice
               | they're rarely used (Wicket is literally the only library
               | I've seen to offer an effective inheritance interface);
               | the overwhelming majority of the time inheritance ends in
               | fragile base classes and the resulting bugs.
               | 
               | Which is perhaps inevitable; the trouble with giving you
               | the tools to change the superclass's behaviour in
               | unintended ways is that it results in people changing the
               | superclass's behaviour in unintended ways. If you have a
               | locked-down inheritance model where classes and methods
               | are final by default then maybe you avoid the fragility
               | problem - but by the same token if subclasses can only
               | use extension points that were deliberately exposed then
               | you're probably not gaining much flexibility over what
               | you could do with composition.
               | 
               | > The final advantage is that in some languages the
               | implementation is highly optimized. On HN you'd be
               | forgiven for thinking nobody writes virtual method calls
               | since 20 years ago but in reality virtual method dispatch
               | is so common in real programs that it's heavily optimized
               | by both CPUs (sophisticated indirect branch caching) and
               | language runtimes (PICs in fast VMs like Hotspot or V8).
               | Composition is less well optimized.
               | 
               | Shrug, as the language design consensus shifts, the
               | implementation optimizations will follow. Composition
               | should ultimately be easier to get better performance out
               | of, because it's more constrained (in particular, knowing
               | that a given class or method is final means that you can
               | optimise that class or method much more aggressively).
               | 
               | > So people just aren't exposed to the situations where
               | OOP is useful because browsers weren't designed for UI,
               | and the memory of why it was originally developed
               | atrophies.
               | 
               | AIUI the association between OOP and GUI is more of a
               | historical coincidence than a deliberate design. Though I
               | agree that they do seem to fit together well.
        
           | ernst_klim wrote:
           | > Unfortunately, the current landscape of popular languages
           | have equated "object programming == inheritance" in people's
           | minds.
           | 
           | Because OOP is somewhat equals to inheritance (or more
           | strictly late binding + open recursion + self-polymorphism,
           | inheritance is just one way to achieve that).
           | 
           | "delegating" is completely orthogonal to OOP, you can have
           | delegates in any modular language, like ML. Saying "you need
           | to use more delegates and less inheritance" basically equals
           | to "you need to write less OOP code".
        
             | crabmusket wrote:
             | > you can have delegates in any modular language, like ML
             | 
             | I'm struggling to understand this, could you give an
             | example?
        
               | ernst_klim wrote:
               | module type Repo = sig          type t
               | type user               val get_user : t -> name:string
               | -> user option               val get_all_users : t ->
               | user list        end             module LoggedRepo (R :
               | Repo) : sig          (* Resulting module is of type Repo
               | plus create function *)          include Repo
               | val create : delegate:R.t -> logger:Logger.t -> t
               | end = struct                    type t = { delegate :
               | R.t; logger : Logger.t }               type user = R.user
               | let create ~delegate ~logger = { delegate; logger }
               | let get_user repo name =             Logger.debug
               | repo.logger "Get user by name";             R.get_user
               | repo.delegate name                    let get_all_users
               | repo =             Logger.debug repo.logger "Get all
               | users";             R.get_all_users repo.delegate
               | end
               | 
               | In languages like C it would be harder since they don't
               | have notion of interface and implementation, so you would
               | have to implement that as an object-like structure of
               | function pointers and opaque structs for state.
               | 
               | The point is, for delegate you don't need lately bound
               | methods and virtual dispatching, i.e. oop, only the
               | notion of interface and implementation supported (or
               | emulated), and then you can create implementations that
               | wrap another implementations.
        
               | _old_dude_ wrote:
               | You still need virtual dispatch (or type pattern
               | matching) if there is a variable which can contain either
               | a BDRepo or a LoggedRepo(BDRepo).
        
               | ernst_klim wrote:
               | No, you don't. LocalRepo.t != Repo.t, and all the
               | functions are purely static. LocalRepo.get_user won't
               | work with other Repo.t, and other Repo.get_user won't
               | work with LocalRepo.t. What you would need is to
               | parametrize your further computation with a Repo module,
               | as in                   module HttpHandler (R : Repo) :
               | sig            val handle_user : R.t -> HttpWriter.t ->
               | username:string -> unit         end = struct
               | let handle_user repo writer ~username =
               | match R.get_user repo username with               | None
               | -> Writer.write_status writer 404               | Some
               | user -> Writer.write_body writer (User.to_string user)
               | end
               | 
               | and then to construct a handler module with a proper
               | repo.
        
           | mrkeen wrote:
           | > Unfortunately, the current landscape of popular languages
           | have equated "object programming == inheritance" in people's
           | minds.
           | 
           | That's because inheritance isn't really elsewhere, making it
           | uniquely an OO concept (though I'm sure there are
           | exceptions).
           | 
           | When people say OO is all about X, Y, and inheritance, well,
           | X and Y are in most of the other languages too.
        
             | BurningFrog wrote:
             | The big "X" is that the code is implemented by objects
             | calling each other.
             | 
             | That's what OO is to me. Inheritance is nice for some
             | things, but entirely optional.
        
           | jrumbut wrote:
           | We forget that favoring composition over inheritance is one
           | of the core ideas of OOP. It's supposed to be, at least.
           | 
           | Textbooks have an example like "Dog inherits from Animal" as
           | a way to demonstrate the concept of inheritance, but people
           | took that as an invitation to become Linnaeus and create a
           | hierarchical taxonomy of their domain.
           | 
           | It might be a useful exercise, actually, but it's rarely the
           | best way to design software and you can do OOP (and do it
           | better) with sparing use of inheritance (by replacing it with
           | extensive use of composition).
        
         | bob1029 wrote:
         | The #1 canary for me is circular dependencies. In more complex
         | domains, a strict hierarchy of types begins to fall apart
         | rapidly.
         | 
         | In my experience, a relational model is the best solution for
         | domain modeling precisely because it can directly represent
         | circular dependencies without any sort of weird interface
         | hacks, one off Init() methods, etc.
         | 
         | A practical example of this would be something like the domain
         | of banking. In a bank, you generally have 2 major types of
         | entities: accounts and customers. Accounts can have many
         | customers and customers can have many accounts. Which type
         | should "win"? In SQL you don't have to make this decision at
         | modeling time - it is deferred to the caller and its specific
         | view of the world.
         | 
         | You can certainly emulate this in OOP, but then you are stuck
         | doing joins between collections manually.
        
           | Xcelerate wrote:
           | This is why I prefer multiple dispatch over classes:
           | functions dispatch on the types of all arguments, not just
           | the type of the implicit first argument. After first
           | encountering this paradigm in Julia, it's painful to use
           | other languages that don't have this feature.
        
             | JanisErdmanis wrote:
             | I don't think multiple dispatch solves this issue. Julia
             | does have a strong type hierarchy and the proposed example
             | with customers and accounts would be likewise hard to
             | model. IMO only Rust like traits solves this issue
             | elegantly.
        
               | bob1029 wrote:
               | > solves this issue elegantly
               | 
               | What about cycles?
               | 
               | For example, "List all distinct customers from all
               | accounts that are owned by customers who are members of
               | some other subset of accounts".
        
               | JanisErdmanis wrote:
               | I agree Rust does not make it easier either. This is an
               | interesting design problem.
               | 
               | I tried it with ChatGPT and it did produce a robust
               | solution. This does not seem to be a limitation for
               | strong type hierarchy after all:
               | 
               | ```
               | 
               | # Define a struct for Customer struct Customer
               | id::Int              name::String              # Other
               | customer-related fields
               | 
               | end
               | 
               | # Define a struct for Account
               | 
               | struct Account                   id::Int
               | balance::Float64              type::String  # e.g.,
               | "Savings", "Checking"              # Other account-
               | related fields
               | 
               | end
               | 
               | # Define a struct to manage the many-to-many relationship
               | 
               | struct CustomerAccount
               | customer::Customer              account::Account
               | 
               | end
               | 
               | # Define a struct for the Bank which holds all
               | information
               | 
               | struct Bank                   customers::Dict{Int,
               | Customer}              accounts::Dict{Int, Account}
               | customerAccounts::Vector{CustomerAccount}
               | 
               | end
               | 
               | ```
        
               | bob1029 wrote:
               | > it did produce a robust solution.
               | 
               | Indeed. It produced a relational solution that emulates
               | what you'd do with SQL tables.
               | 
               | This is approximately the schema shape we use in our
               | product today.
        
           | nradov wrote:
           | I don't see the problem. You can have a class for accounts, a
           | class for customers, and a class for the links between
           | accounts and customers. Those classes are peers; there's no
           | need for one to be the winner. Most OOP languages also have
           | ORM frameworks that can help here. I've built stuff like that
           | in Java and in practice it's just not issue.
        
         | uticus wrote:
         | I understand what you mean but at the same time in the web-dev
         | world I find it interesting that React is migrating from OOP to
         | functional.
         | 
         | ("We recommend defining components as functions instead of
         | classes." at top of page at
         | https://react.dev/reference/react/Component)
        
           | codeptualize wrote:
           | React has always used functional programming patterns. They
           | used classes to define components, but even those applied
           | functional principles.
        
           | meheleventyone wrote:
           | From the looks of things the main benefit is less
           | boilerplate? What are the other benefits from beyond this?
        
             | codeptualize wrote:
             | Mainly hooks. Hooks make it easy to reuse component logic,
             | something that was difficult with class components. You'd
             | need HOC's which are hard to deal with, especially with
             | prop collisions and refs.
             | 
             | (This change has little to do with OOP vs functional. React
             | calls them function components, not functional. React has
             | always used functional patterns, even in the class
             | components.)
        
               | meheleventyone wrote:
               | Thanks I went and looked up the different approaches
               | (have never written a line of React in my life) and I
               | definitely like the hooks more on first blush.
        
           | mike_hearn wrote:
           | React isn't actually functional. It's OOP in disguise.
           | There's no such thing as functional UI, in the classical
           | sense of FP. It's one of the weaknesses of FP.
           | 
           | Although React tutorials start by saying your UI becomes a
           | pure function of your app's state, React components do have
           | encapsulated state. Any time you call useState inside a react
           | function you're doing something that doesn't exist in real FP
           | programs. Additionally React boils down to a way to create
           | DOM elements, which are highly stateful C++ objects exposed
           | to JavaScript, implemented using inheritance:
           | 
           | https://source.chromium.org/chromium/chromium/src/+/main:thi.
           | ..
           | 
           | An HTMLButtonElement _is a_ HTMLFormControlElement _is a_
           | HTMLElement (and a ListedElement and a FormAssociated).
           | 
           | The rules for how you write code in React (or Jetpack
           | Compose) violate even the most basic rules of the host
           | language. useState defines or returns what is effectively an
           | object field (it's data associated with that widget), but it
           | looks syntactically like a local variable. It's not a local
           | variable though because its value will survive the exit of
           | the scope. Nor is useState a normal function call because
           | there's a hidden invocation counter used to work out what
           | state slot you want, which is why you aren't allowed to call
           | it inside conditional branches and why loops need special
           | handling.
           | 
           | So in React's "functional style" we can see that you're
           | actually defining objects with encapsulated state, that
           | register event handlers, that export properties and so on.
           | It's just obfuscated to look like it's not OOP.
        
             | mwcampbell wrote:
             | I'm curious, do you have a current favorite way of
             | implementing UI, particularly for desktop applications,
             | that isn't obfuscated and doesn't violate the rules of the
             | host language? Or do you find that Jetpack Compose is a
             | good choice overall despite those shortcomings?
        
               | mike_hearn wrote:
               | I'm still making up my mind about Compose, there are
               | aspects I really like and aspects I really don't. It's
               | not the fault of Compose itself, the aspects I don't like
               | are basically the conceptual model as copied from React.
               | 
               | Honestly for recent simple GUIs I've made for my own in
               | house tools I'm still using JavaFX. Mostly because I
               | always seem to end up needing a good table view, and
               | because I happen to know it. If I were working with it a
               | lot I'd end up maintaining a TornadoFX style set of
               | wrappers but for simple stuff the plain API works OK.
               | 
               | Because I'm weird I'd probably use it for low-traffic web
               | apps these days too, with JPro (jpro.one). Probably not
               | for mobile web, and not for stuff where users are on high
               | latency connections in general, but if the user has a
               | nice big screen and a low latency connection I'd
               | personally find it a lot easier and more productive than
               | dealing with HTML and CSS. The results are
               | indistinguishable for the user if you are careful.
        
               | mwcampbell wrote:
               | Thanks for that info. I promise the original intent of my
               | question wasn't to find an excuse to nag about
               | accessibility, but I should point out that JPro is
               | certainly not indistinguishable from typical HTML for a
               | screen reader user, judging by the JPro website. In
               | particular, the links are marked up strangely, with a
               | separate link for each word in a multi-word phrase, and
               | there are no headings or landmarks to aid navigation.
               | Just thought you should know.
        
             | convolvatron wrote:
             | you can certainly write functional UI using a differential
             | 'pure core state on the outside model' (someone here had a
             | discussion that gave this thing a name)
        
             | lmm wrote:
             | > Any time you call useState inside a react function you're
             | doing something that doesn't exist in real FP programs.
             | 
             | Meh, it's just a monad, hidden in a fake syntax so people
             | don't panic.
             | 
             | > Additionally React boils down to a way to create DOM
             | elements, which are highly stateful C++ objects exposed to
             | JavaScript, implemented using inheritance
             | 
             | And C++ and JavaScript are just ways to run machine code,
             | which is fully unstructured. But all of that is an
             | implementation detail. React creates DOM elements because
             | that's what you have to do to render UI in the browser, not
             | because its creators think the DOM is a good idea.
             | 
             | > So in React's "functional style" we can see that you're
             | actually defining objects with encapsulated state, that
             | register event handlers, that export properties and so on.
             | It's just obfuscated to look like it's not OOP.
             | 
             | It's not OOP - it doesn't have inheritance, most state is
             | (idiomatically) immutable and exposed, and as you noted,
             | React state does not follow the same rules as OOP state.
             | While it's not fully pure functional (I'd actually say the
             | React state model is a novel and interesting thing, that I
             | expect may end up being a language feature in the next
             | generation of successors), it's closer to functional than
             | traditional OOP, and most of the benefits are those of a
             | functional rather than OO style.
        
           | kaba0 wrote:
           | React is not a UI library itself -- the actual UI stuff is
           | delegated to the DOM. It is more like a library on top a UI
           | library, that manages the state->representation flow (where
           | reactive FP is indeed a good choice).
        
             | ithkuil wrote:
             | And in case it wasn't clear let's say it explicitly: the
             | DOM is pretty much an object oriented model (the O stands
             | for object)
        
               | mostlylurks wrote:
               | Yes, but the fact that react uses the DOM is because that
               | is what the very restricted platform gives you out of the
               | box, and opting for other options would have several
               | disadvantages that are purely the result of those other
               | options not being directly provided by the platform
               | itself. A reactive UI library (like react) could very
               | easily be implemented on top of other UI paradigms as
               | well, including decidedly non-OOP ones. There's nothing
               | special about object oriented UI systems that motivates
               | reactive UI libraries to use them except for the fact
               | that that's what the underlying platform provides because
               | that was what was in fashion when the platform was taking
               | shape.
        
         | ernst_klim wrote:
         | > I find "modern" OOP concepts apply pretty well to graphical
         | user interfaces.
         | 
         | Though most contemporary frameworks (react, elm, android
         | compose) tend to prefer (functional) reactive programming.
        
           | Scarblac wrote:
           | That's also because they exist in a browser. The browser
           | displays one page (from the viewpoint of a web app) and has
           | one global event loop, the event loop calls into the
           | application code. Application code doesn't run at other
           | times. Reactive programming is a good fit for that.
        
             | PaulDavisThe1st wrote:
             | > one global event loop, the event loop calls into the
             | application code. Application code doesn't run at other
             | times.
             | 
             | In the 80s we called that "event-driven programming", and
             | until threads became widely available, it is how all native
             | GUI programming worked, more or less.
        
               | marcosdumay wrote:
               | Event-driven is the "reactive" part only. And the old
               | implementations of it where so less capable of fine-
               | handling the events and complex dependencies that it's
               | reasonable to change the name.
        
         | codeptualize wrote:
         | I disagree on the UI side. UI has been moving towards more
         | functional declarative approaches as it's much easier to
         | manage.
         | 
         | CSS is also interesting, we mostly try to avoid the inheritance
         | with scoping, utility classes and or css in js solutions as it
         | becomes really hard to manage otherwise.
        
         | marcosdumay wrote:
         | > In a way, even CSS is kind of OOP
         | 
         | Inheritance makes for a very powerless form of logical
         | programing. CSS is way more than OOP.
         | 
         | (Powerless is always preferred if it's sufficient, but CSS
         | clearly shows a single hierarchy isn't sufficient.)
        
         | nine_k wrote:
         | Inheritance is likely the worst idea of OOP's implementations.
         | 
         | The right way to achieve the same and better results is
         | interfaces / typeclasses / traits. They work pretty well in
         | languages from Rust and Haskell to Typescript, Kotlin, Java,
         | and even Go. (Go is a bit special because you don't even have
         | to declare that your class implements an interface, as long as
         | it actually has a set of methods with right signatures.)
         | 
         | Ideally, all public methods should only describe parameters and
         | return values in terms of interfaces, and never as concrete
         | classes.
         | 
         | If you need to take a big class and inherit from it to override
         | one or two methods, it's a failure to compose the things
         | correctly. These one or two methods usually are better off as
         | their own entity which you can pass to the "base" as
         | parameters. This both prevents proliferation of "god objects",
         | increases testability, and improves build times (shallower
         | dependency graph, yay).
        
           | 38 wrote:
           | > Ideally, all public methods should only describe parameters
           | and return values in terms of interfaces, and never as
           | concrete classes.
           | 
           | Citation needed. I've seen interface heavy Go code, and
           | without fail it's always unreadable garbage. Interfaces are
           | best used in moderation, at API boundaries only.
        
       | ChrisMarshallNY wrote:
       | For me, personally, I've learned to use the right tool for the
       | job.
       | 
       | In some cases, it's OOP, in some cases, it might be something
       | like FP, or Protocol-Oriented Design.
       | 
       | I write in Swift, which supports all of the above. It's been a
       | while, since I've worked with C++, but I have heard that the
       | modern version of the language similarly supports multiple
       | paradigms.
       | 
       | For the frontend, if I am writing for UIKit, I use OOP, and
       | fairly standard MVP, as that is exactly what the framework was
       | designed to afford. I haven't done much SwiftUI, but I suspect
       | that I'll be using a lot less OOP, when I do.
       | 
       | On the server end, I tend to use good ol' PHP. It's not an
       | especially good OOP language, but I find that OOP isn't as
       | relevant for my backend work. That work tends to look a lot like
       | very old-fashioned Structured Programming, which PHP is good for.
       | As others have pointed out, I've found it easy to go down
       | rabbitholes, with backend OOP.
       | 
       | There's a lot to be said for an approach as an experienced,
       | multidisciplinary professional.
       | 
       | It seems as if programming and software engineering pundits
       | generally start from the premise that all [other] software
       | developers stink, and rules and tools should be used in an effort
       | to force them to write "good code," as opposed to, for example,
       | hiring smart people, and training and mentoring them to be
       | adaptable, resourceful, disciplined engineers.
       | 
       | That's nothing new. I have been seeing this for my entire [long]
       | career. The "new hotness" changes, but the attitudes are
       | consistent.
       | 
       | Here's an old joke, from the 1980s:
       | https://news.ycombinator.com/item?id=29345907
        
         | kbrannigan wrote:
         | Do you use any framework for PHP?
        
           | ChrisMarshallNY wrote:
           | No, but if I did, it would probably be Laravel. A number of
           | folks I highly respect, swear by it. In that case, I'd
           | probably be using more OOP.
           | 
           | With PHP, I tend to use OOP constructs as namespaces.
           | 
           | My backend work is fairly humble. Most folks here, would
           | laugh at it, but it works really, really well.
        
       | zigzag312 wrote:
       | OOP, FP and other paradigms are all useful. Just don't do
       | extremes like _everything is an object_ or _everything is
       | immutable_ or _everything is without side effects_.
       | 
       | I enjoy multi-paradigm languages the most.
        
         | danielvaughn wrote:
         | Yep. Any given software project of non-trivial complexity is
         | going to be composed of many types of problems, each of which
         | requiring its own solution and approach. I don't think I've
         | ever worked on a codebase that didn't need both OOP and FP in
         | different places.
        
         | pydry wrote:
         | Yeah but have you considered joining the church of everything
         | is a list?
        
       | augustk wrote:
       | > Data abstraction       > Encapsulation       > Polymorphism
       | > Inheritance
       | 
       | Note that it's the last two concepts which are specific to object
       | oriented programming. The first two are already supported by non
       | OOP languages like C and enable implementation of abstract data
       | types. I think it's unfortunate that all concepts are often
       | introduced in the same OOP course which may make the students
       | believe that a class and an abstract data type is the same thing.
        
         | Log_out_ wrote:
         | > Encapsulation as an idea failed spectacular again and again.
         | What would have been valuable would have been a way to enforce
         | layers of abstractions, with no composition or inheritance of
         | objects on the same layer.
        
         | ryandv wrote:
         | Polymorphism is not at all specific to OOP, and there are in
         | fact different kinds of polymorphism; "generics" are pervasive
         | in pure FP languages such as Haskell or imperative/functional
         | languages like Rust, and are an instance of parametric
         | polymorphism. Ad-hoc polymorphism, or "operator overloading,"
         | can also be seen in both languages as the "Eq" typeclass/trait
         | and the equality operator `==`. It's subtype polymorphism and
         | deeply nested inheritance structures that are maybe particular
         | to OOP.
         | 
         | It's also worth making a distinction between an abstract data
         | type - a "thing" and some set of operations defined over it -
         | and a data structure - a particular in-memory construction and
         | set of procedures defined over it, often used to realize an
         | abstract data type. An example being a dictionary ADT -
         | supporting get, set, delete, etc. being realizable through
         | different data structures; for example, a linked "association
         | list" of (key, value) pairs vs. a hash table - with each having
         | different performance characteristics, despite possessing the
         | same properties as the ADT they implement.
        
           | adrian_b wrote:
           | Polymorphism that is resolved at run-time, i.e. "virtual"
           | functions is what is specific to OOP.
           | 
           | The term "polymorphism" was first used in the documents of
           | the language CPL (in mid sixties), the source of BCPL, where
           | in British English it corresponded to what in the American
           | documents of the same age, starting with McCarthy, were
           | called overloaded operators and overloaded functions.
           | 
           | The use of "polymorphism" mostly for the run-time
           | polymorphism of OOP languages has appeared only a couple of
           | decades later, with Smalltalk.
           | 
           | "Generic", which might be a better term than both, has been
           | popularized during the programming language contest that has
           | lead to Ada (1979). Nowadays it is mostly used for
           | polymorphism/overloading that is resolved at compile time,
           | because this is how the term has been used in Ada.
        
             | ryandv wrote:
             | Even still, there exist non-OOP implementations of runtime
             | dynamic dispatch, such as Clojure's multimethods.
        
             | ykonstant wrote:
             | I thought Julia's multiple dispatch was run-time
             | polymorphism?
        
             | mostlylurks wrote:
             | Even polymorphism that is resolved at run-time is not
             | specific to OOP. In fact, it's used quite extensively
             | outside of OOP, including in both functional and procedural
             | programming. Even ignoring the types of dynamic
             | polymorphism present in other paradigms that might be
             | called "OOP-inspired", there are commonplace patterns such
             | as the use of closures that let you achieve run-time
             | polymorphism and data encapsulation.
        
           | augustk wrote:
           | What you call an abstract data structure is what I have
           | learned is called a concrete data type. To my understanding
           | an abstract data structure is a module with global (single
           | instance) private data which is manipulated using the
           | module's interface. In OOP terminology it's a singleton
           | class.
        
         | joe_the_user wrote:
         | How exactly does C support encapsulation?
         | 
         | I mean, you can do OO type stuff with anonymous handles but the
         | compiler will let a function take one handle type where another
         | belongs and things will fail opaquely but immediately if you're
         | luck and fail slowly if you're unlucky. Which is to say there
         | is no "support".
        
           | augustk wrote:
           | > How exactly does C support encapsulation?
           | 
           | You simply declare a type as a pointer to a struct in the
           | header file along with the functions that operate on
           | variables of this type, and define the struct and the
           | functions in the implementation file.
           | 
           | M.h                 typedef struct M_TDesc *M_T;
           | void M_Foo(M_T x);       ...
           | 
           | M.c                 #include "M.h"            struct M_TDesc
           | {          ...       };            void M_Foo(M_T x)       {
           | ...       }       ...
        
       | ryandv wrote:
       | The slide deck is about performance pitfalls of OOP languages,
       | which can surreptitiously introduce cache misses, random access
       | to memory, and excessive levels of indirection into your code:
       | 
       | > Prefetching
       | 
       | > Data accesses are now predictable
       | 
       | I'm reminded of a Stroustrup talk in which he says that vectors
       | will always outperform linked list structures, by taking
       | advantage of spatial locality and predictable access patterns to
       | enable better cache prefetching. He even has a slide on C++ vs
       | "True OO" style object graphs, and it looks remarkably similar to
       | what's described in the OP:
       | https://www.youtube.com/watch?v=YQs6IC-vgmo&t=3m53s
        
       | commandlinefan wrote:
       | That went in a different direction than I expected it to - but
       | it's also not specific to object oriented programming. Richard
       | Stevens summarized this 40 years ago: "modularity is the enemy of
       | performance". We've mostly accepted that this is an acceptable
       | tradeoff, although the author (and I) aren't fully on board.
        
       | rkagerer wrote:
       | When the whole OOP movement gained traction I struggled to accept
       | the degree of value it provided above simple structs and
       | functions (at least for an organized programmer).
       | 
       | After decades developing on a lot of diverse platforms in a
       | variety of languages and models, I've decided there ain't much
       | you can't achieve without structs and functions (or their
       | equivalent).
       | 
       | Sure, any tool is most efficient in the hands of a master who
       | knows how to wield it. But in practice all those shiny extras too
       | often become productivity distractions.
        
         | AnimalMuppet wrote:
         | To me, the big difference between a struct and an object is
         | when data has constraints.
         | 
         | Let's say I have a rotation matrix. That means that the squares
         | of all the entries in any one row or column add up to 1. If I
         | have such a structure, and I find that it has rows that no
         | longer add up to 1, well, what function messed it up? I have no
         | idea. And if I have a million lines of code, that gives me a
         | lot of places I have to look.
         | 
         | But with an object, if I made that data private, only a member
         | function can have messed up. I may still have a thousand lines
         | I have to look at, but that's a lot less than a million. For
         | larger code (tens of thousands of lines and larger), I consider
         | access control to be essential, just to limit the size of the
         | code that could possibly be at fault.
         | 
         | Back in the day, I spent a _lot_ of time playing  "who messed
         | up the structure?" in structure-and-function code...
        
           | ReleaseCandidat wrote:
           | > But with an object, if I made that data private
           | 
           | Being able to make a field of a record private does have
           | nothing to do with OOP, even in C you can hide a struct's
           | fields.
        
       ___________________________________________________________________
       (page generated 2023-12-28 23:02 UTC)