Live data from Hacker News

Case against OOP is understated, not overstated (2020)

boxbase.org

451–460 of 557 posts

Re: Case against OOP is understated, not overstated (2020)

#451
The author has a point. Yet, most mainstream languages provide OO features; especially many recent ones. Even languages like Rust and Go have some limited OO features. And many languages also add features common to functional programming languages. So, I guess the consensus among language designers is that it's not all bad.

I would say early OO is very different from what is practiced today. I use Kotlin mostly. It's obviously an OO language but it puts some interesting twists on it relative to earlier languages (like Java):

- classes are closed by default and you must define them as open to be even able to create a subclass. When you do, you must explicitly label things in classes that you override. This prevents, un-intential abuse of inheritance that is common in many Java frameworks. E.g. Spring has riduculously deep inheritance hierarchies. When I was still using Java I had a simple rule: any form of class extension is probably something I need to get rid off. Delegation is just preferable in my opinion. I almost always end up regretting class extension to the point where I rarely consider using it.

- Speaking of delegation, the Kotlin language designers obviously agree with this and added interface and property delegation to the language. This is just syntactic sugar but it's awesome. I can take any class and pass myMap: Map into the constructor and then add implements Map by myMap. And just like that you have extended a class but without actually extending it. I can even override some of the methods (because it implements the interface). They basically provided syntactic sugar for a common design pattern: delegation, which you should almost always favor over inheritance IMHO. Property delegation is equally powerful and you can use it to e.g. lazily initialize a property foo: String by lazy { someFunctionThatReturnsAString() }

- it encourages the use of val variables that cannot be reassigned. If you want that, you need to use var. If you define a var and don't reassign it, the compiler will warn you to use a val instead. Immutability by default is encouraged and it helps with e.g. asynchronous code and a few other things.

- it has sealed classes (and interfaces) as of a few versions ago. The advantage of those is that the hierarchy is closed after compilation. So you can't add more sub classes and this benefits the compiler doing some optimizations. Likewise, value classes are now a thing. In the rare cases I do use inheritance, I use sealed classes.

- it actually discourages class extension in favor of using extension functions and properties. This is much cleaner and does not suffer from a lot of the problems associated with inheritance. For example, you can't actually override anything this way. Extension functions are surprisingly useful and I use them a lot. They even work on type aliases or on nullable types. So you can call a function on a null value for e.g. a nullable generic type T and it's not going to trigger a null pointer exception when you do that. More languages should add this. This just removes a lot of use cases where you might have used inheritance or interfaces in the past. This also removes a lot of the need for multiple inheritance; which is problematic in the few languages that still support that.

- having default values on parameters in functions means that you rarely have more than 1 constructor for classes. You can add more constructors, but it's just not something you'd need often and certainly not to support different combinations of properties. Constructors have no body either. All that happens is assigning properties. This enforces the sane rule that constructors must do no work. If you need to do work on class creation, you add an init function.

I'm sure some language designers have plenty of nits to pick with Kotlin. But for me it's a very pragmatic language that mostly manages to nudge people to do the right things while providing them with a lot of convenience. Scala people tend to look down on it for example and that language does have some interesting features. But then I find most Scala code to be utterly unreadable because. Purity has a price, I guess. And of course many Scala coders consider its OO legacy to be somewhat of a mistake apparently.

Re: Case against OOP is understated, not overstated (2020)

#452
post #240

Earlier quoted context omitted.

>solutions to imaginary problems This is a fundamental misunderstanding of what patterns are. The GOF book is used to this though. A design pattern is someting that will naturally crop up if you adhere to certain design principles. If you follow a principle of separating instantiation logic from other logic then you will start to see factories. If you combine multiple complex parts of your code into simpler ones then…

That exact sentiment exists deep in my comment history here: I think I used the word "blueprint" if you care enough to fact check that. That is why I said I don't hold issue with the content of the book. My issue is that the book is useful. It helps solve the artificial complexity introduced by OOP.

I see. It was the ambiguity over your usage of 'imaginary problems'. But yes - your previous comments seem to suggest we're actually on the same page regarding patterns.

Re: Case against OOP is understated, not overstated (2020)

#453
post #427

Earlier quoted context omitted.

I have come to the same conclusion. State is the problem. State should be: - minimal (amount and lifetime) - well conceptualized (~= easy to understand the organization) - well named - minimally exposed - coherent by construction (make inconsistency impossible by design of the format or by offering updating functions that ensure the invariants) OOP can actually help with some of these things! I develop mainly in C++,…

All well and good, but where do you put the damn state?

Somehow I often end up with classes containing lists or hash tables containing structs, more often than other people apparently. A technique that is IMO underused is getting creative with the key in a hash table or an ordered map - it does not have to be a primitive type, and even an integer can be divided into ranges or an integer plus a few bit-flags.

I also like to use enums, but these are widely used anyway.

It's hard to say something general because the answer is "it depends".

Re: Case against OOP is understated, not overstated (2020)

#454
post #70

Earlier quoted context omitted.

There's a really wonderful talk that I've recommended to almost everyone I've ever worked with called Simple Made Easy[1] by Rich Hickey. I also struggled to explain why I hated state so much. You can talk about races with shared mutable state but even single threaded code I found I couldn't stand it, that it made things harder to reason about and change. It's because state is complex , in the sense Rich discusses in…

The problem I have with talks like this is that they sound fantastic on the surface. They almost sound self-evident! "Duh! I want to make simple things, not easy things! That was great!" But where are the examples? Not a single example of something easy versus simple, or how something "easy" would resist change or be harder to debug. All of these concepts sound fantastic until you begin to write code. How do I apply…

The Clojure language is the example. Basic data structures vs classes/objects, immutable vs mutable, lisp vs other languages, etc.

Re: Case against OOP is understated, not overstated (2020)

#455

Earlier quoted context omitted.

I have come to the same conclusion. State is the problem. State should be: - minimal (amount and lifetime) - well conceptualized (~= easy to understand the organization) - well named - minimally exposed - coherent by construction (make inconsistency impossible by design of the format or by offering updating functions that ensure the invariants) OOP can actually help with some of these things! I develop mainly in C++,…

I like your "bullet points" and agree with them all. Wat are your thoughts on (super simplified example): * 1 state-var with 3 values ? * 2 state-vars with 2 values each ? Sometimes I steer my design too much to first example and then other times to the last example. Both extremes can make things ugly

This is a typical conflict, and I think my main problem is that I spend too much time worrying about it. The important thing is that you make sure that they cannot become inconsistent (you can do this by always going through a function that ensures that when updating them). A thing I have done somewhat recently is:

  enum AuthConnectionState 
  {
      WaitingForConfig = 0,
      Disabled,
      Connecting,
      Connected,
      TimedOut
  };
where the value of the corresponding variable is derived (in just one place that is called when any input changes!) from many inputs, and it's the authoritative source of information. If you want to know whether the current state allows to proceed with login (which can be local if so configured or the connection definitely failed), call:

  static bool connectionStateAllowsLogin(AuthConnectionState state)
  {
      return state == Disabled || state == Connected || state == TimedOut;
  }
(Note for people who don't know C++: this is a file-static function, which is basically as private as it gets in C++, and it's also a pure function, not by any language feature though. It could access globals.)

It has a couple of sister functions like isWaitingForWhatever() or isLocalLogin().

The naive alternative is a very nasty and error-prone forest of booleans, each of which you must remember to update when something about the connection changes, and to make sure it's all consistent. It's almost impossible to get right without exhaustive testing.

Re: Case against OOP is understated, not overstated (2020)

#456
post #367

I don't quite understand what this is trying to say. It's a summary review of some reviews? Or something. It's not even clear if the author of this post agrees or disagrees with the claim in the YC News title. It's peppered with sentences like: "That you don't understand something doesn't mean it's flawed or bad." Precisely. Many of the arguments against OO are from academics that don't write real-world, large-scale…

Are you claiming Rust is incapable of writing microservices, being run on K8s, using service buses or event streams, etc.? Why focus on building OOP functionality into the language, when it should be the infrastructure and API frameworks that should be built for OOP?

A1) No.

A2) Because it's about 1,000x to 10,000x more efficient.

An awful lot of the "ills" of modern development practices boil down to the lack of ingrained rules of thumb related to performance. The difference between a local function call -- virtual or not -- and a network call can easily be a factor of a million.

This just isn't in the mental model of most developers. The terms "nanoseconds" or "clocks" are not in their vocabulary.

I grew up and learnt programming in an era where OO was considered extravagantly wasteful because virtual function calls had an extra indirection! Those precious instructions -- and more importantly -- the lost opportunity for inlining or CPU pipelining were considered brutal performance hits.

These days, people throw Python into Docker containers and run them remotely on the network to invoke what amounts to a page of code. They call this "modern".

Then they go on Y Combinator News and complain about how OO is "bad" somehow. Quite a few of these people have probably never written a class hierarchy from scratch themselves.

I literally just spent a day talking to some full-time developers with years of experience, explaining how to implement a simple "storage abstraction" OO hierarchy. You know, you have a base interface or abstract class with a bunch of implementations like "S3BucketStorage", "ZipFileStorage", "LocalFilesStorage", or whatever... and then you have the meta-implementations that combine them, such as "UnionStorage", "CacheStorage", and "RetryStorage", each of which take the abstract interface as input parameters during construction. So you can have local files act as a cache for S3 buckets (with retry) that override a local zip file of static content. Or whatever! Combine implementations to suit your whims.

They looked at me like I had grown a second head that started speaking Greek while the other spoke Latin.

Then they wrote some spaghetti code of functions with hard-coded parameters, checked that garbage in to the repo, and then dutifully sent out an email to management saying "job done".

Is OO bad, or are most developers bad? I suspect the latter...

Re: Case against OOP is understated, not overstated (2020)

#457
post #376

Earlier quoted context omitted.

This made me think: if we wrote object oriented code methods where all the members that we access are passed explicitly as parameters, as well as all the members that we modify (as out references), then we at least would immediately identify the real complexity of some methods! I'll try to do this, I'm curious to see how that would look like.

> I'll try to do this, I'm curious to see how that would look like. That looks like a terrible mess. The problem is not state, but messy access to it.

Everybody agrees that OOP was killed by getters and setters. But I don't think that there is much consensus about how long it would have survived without.

(I'm not saying that OOP doesn't have its place, but it has clearly turned from a way of structuring code to universally strive for into something to avoid if possible)

Re: Case against OOP is understated, not overstated (2020)

#458
post #70

Earlier quoted context omitted.

There's a really wonderful talk that I've recommended to almost everyone I've ever worked with called Simple Made Easy[1] by Rich Hickey. I also struggled to explain why I hated state so much. You can talk about races with shared mutable state but even single threaded code I found I couldn't stand it, that it made things harder to reason about and change. It's because state is complex , in the sense Rich discusses in…

I enjoyed the talk and agree with it in many ways, but perhaps a contrarian stance will stimulate some interesting discussion. Here's the steelman I can think of against that talk. Hickey's fundamental contention is that whether something is easy is an extrinsic property whereas whether something is simple is an intrinsic property. Whether something is easy is dictated often by whether it is familiar, whereas simplic…

I want to add to this that physics aims at this 'simplicity', i.e. being able to derive mathematical models ab initio, with the least amount of assumptions.

While the 'simplest' (in the physics sense) description of something is elegant, it can also be extremely hard to understand and work with. Maxwell's equations are used in engineering for a reason - and not their simpler theoretical physics underpinnings.

Re: Case against OOP is understated, not overstated (2020)

#459
post #96

Earlier quoted context omitted.

That time part is what you are wrestling with when you are battling with state. So it's natural to think about it that way. But there's also this somewhat dumbed down version of the argument: every piece of state a method reads is like an additional function argument and every state it writes an additional return value. What a mess.

This is insightful. In some sense, the only distinction a "pure" function has over "non-pure" is that it declares all its inputs/outputs (as function parameters and result). We say that a non-pure function has "side effects", but all that actually means is that we don't readily see all its inputs/outputs. Even a function that depends on time could be converted to a pure function which accepts a time parameter - this…

There's no such thing as UI = f(state) in React. You may know that already, but it's UI = f(allStatesStartingFromInitialState). That way all state transitions are captured and all state changes are handled accordingly inside components taking into account component's internal state.

Re: Case against OOP is understated, not overstated (2020)

#460
every time I see this kind of posts I remember the good old "Qc Na" koan[0]

> The venerable master Qc Na was walking with his student, Anton. Hoping to prompt the master into a discussion, Anton said "Master, I have heard that objects are a very good thing - is this true?" Qc Na looked pityingly at his student and replied, "Foolish pupil - objects are merely a poor man's closures."

> Chastised, Anton took his leave from his master and returned to his cell, intent on studying closures. He carefully read the entire "Lambda: The Ultimate..." series of papers and its cousins, and implemented a small Scheme interpreter with a closure-based object system. He learned much, and looked forward to informing his master of his progress.

> On his next walk with Qc Na, Anton attempted to impress his master by saying "Master, I have diligently studied the matter, and now understand that objects are truly a poor man's closures." Qc Na responded by hitting Anton with his stick, saying "When will you learn? Closures are a poor man's object." At that moment, Anton became enlightened.

[0] http://people.csail.mit.edu/gregs/ll1-discuss-archive-html/m...

Post reply on HN