Hacker News new | ask | show | jobs
by berkut 1583 days ago
As someone with 20 years of C++ experience, in industries from everything from real-time systems through to low-level HPC graphics on CPU/GPU (currently in VFX), I really don't understand the hatred for OO programming, and I must be either missing something, or being lucky with the codebases I'm working on...

It's a tool for encapsulation: you can get into trouble with it, but I'd argue the same is possible with many things - it's how well you use it. You can easily use state composition in C++ if you want, and generally (multiple inheritance can cause issues in some cases) you can use interface classes as well.

And as someone who's been learning Rust for the past 6+ months, I've found that of the three new projects I started which I started in Rust instead of C++/Python over the past 4 months, Composition actually worked quite less well (it's quite verbose due to all the plumbing needed to connect things up) than if I could have used OO interitance in many situations where I wanted specialisation - i.e. hierarchy behaviour traits that had both common shared state and functionality AND specialised state and functionality. Thankfully Traits can at least have default implementations - if not, things would have been a bit worse.

To be clear: there's a lot to like in Rust though.

6 comments

Encapsulation is just another way of saying correctly used visibility modifiers. It doesn't mean the state has to be inseparable from the behavior, and its role is semantically fulfilled in Rust by modules. And IME issues with OO feeling like the better role tend to be people attempting to solve all the problems with one feature like OO lets you do, shying away from doing it with multiple features even though they're really multiple concerns. E.g. for common behavior manipulating common state among several local structs, a macro is what you'd use.
The 'hate' is reserved for implementation inheritance, which has its well-known drawbacks (research the "fragile base class problem") - basically, it introduces complex long-range coupling throughout inheritance hierarchies that makes it way too hard, or even impossible, to evolve code over time. Everything else is very much doable in Rust.
The criticism of OO is more Java and Gang of 4 related than anything.

Two things get the enterprise devs of the mid 2000s going:

Badmouthing Oracle. And complaining about refactoring someone's mess of an abstract factory.

Especially I would say since microkernels just became incredibly widespread After Docker. Encapsulation is just not as necessary as it used to be.

In C++ the whole encapsulated structs thingo works fine.

It's there for when you need it, and you don't need it when you don't.

Gang of 4-esque programming is okay when it's necessary. Sometimes you are making something with a 100 different buttons and you just gotta do it that way.

However, for every project that needs all those factories and such, there's probably 5-10 where straight procedural/functional programming is perfectly fine.

Or in the case of many data oriented applications, or when formal verification is needed, probably just straight better.

Just do your abstraction with subroutine signatures and scope.

One of the pieces of OO _inheritance_ I deeply miss in Rust is the ability to subclass a library class, override *one* function, and retain all the other functionality. Yesterday, I needed to tweak the behavior of one function on actix-identity's cookie and my option seemed to be to wrapper the original object and write the same interface for the entire object, passing through every function except the one I wanted to override. Am I a sinner for wanting inheritance yesterday? Probably, but I had to write so much boilerplate to achieve my tiny override.
You don't necessarily need inheritance. Kotlin for example has a feature wherein all that forwarding boilerplate you had to write is automated.

https://kotlinlang.org/docs/delegation.html

That sounds fantastic. It also sounds a bit like a vtable :-D
I guess one way would be via delegation, similar to how COM does it.

I bet with a couple of macros it would be possible to automate what languages on Windows can somehow do magically with COM interfaces.

You don't need any macros, it can be accomplished with the trait system[1], either manually or through auto-deref. Some of the boilerplate could be generalized with a derive proc-macro or a macro-by-example call but it is not absolutely necessary.

[1]: https://play.rust-lang.org/?version=stable&mode=debug&editio...

Thank you so much for this.
> As someone with 20 years of C++ experience... I really don't understand the hatred for OO programming

Well, where should I begin:

    std::cout << "Hello world";
Is just a nice way of doing things...

As the other commenter said, it's not so much OO, but more GoF and how the 2000's OO went.

Please tell me why any basic library adds 3 or 4 levels of inheritance just to do something basic like vector or array. "Oh but this is to make things more generic" and yet nobody uses all that generic stuff. STL is often replaced by more "serious" users.

C++ (and Java) are 2nd systems syndrome gone to 11

I've just taken a look at the Vector implementation at my current system and it's an exercise in frustration. Meanwhile I can understand most of this https://doc.rust-lang.org/src/alloc/vec/mod.rs.html#400

What does std::cout << has anything to do with OOP? It is simply operator overloading.

Where is the level of indirection in std::vector implementations? With templates, c++ really doesn’t use virtual dispatch all that much.

> has anything to do with OOP? It is simply operator overloading

It is an example of how they fumbled the implementation of APIs, because this one has very poor usability.

> With templates, c++ really doesn’t use virtual dispatch all that much.

Good, but try to understand why your multiple-inherited vector is not compiling by reading a 3 line error message.

I wasn't criticising OO. I was talking about how much of a square peg in a round hole it felt - for me - to do OO in C++.