DEV Community

Cover image for The scientific proof of that OOP is a mass psychosis
Thomas Hansen
Thomas Hansen

Posted on

The scientific proof of that OOP is a mass psychosis

Since my previous article generated 100+ comments, 9,500 page views, and some people commenting in anger demanding proof of my statements, I figured I'd prove it. Notice, I tried to explain how the proof of that OOP is a software development mass psychosis by stating "the proof is in your code" - However, nobody apparently believed me, so let me illustrate what I meant by that with two short code snippets doing basically the same.

C++

const auto ret = Tasks::join(
   m_Factories.HTTP->GET("https//gaiasoul.com"),
   m_Factories.HTTP->GET("https://servergardens.com")
).Start();
Enter fullscreen mode Exit fullscreen mode

Hyperlambda

join
   fork
      http.get:"https://gaiasoul.com"
   fork
      http.get:"https://servergardens.com"
Enter fullscreen mode Exit fullscreen mode

For those of us without bias the above should really be self explanatory and enough as proof. However, if you still find it difficult to see the proof, explain the basics of multi threading to a child (who's still not been exposed to OOP), then explain the basics of HTTP and retrieving documents from other servers, and ask the child "which is the easiest to read"?

If you're still in doubt, please realise that the above C++ code was supplied by a commenter as proof of that C++ was "just as good as functional programming languages". Then realise there's no instantiation of the m_Factories variable. Assuming the code is using the accepted coding standards, it's probably safe to assume it's a member variable of some sort, implying the class where it's declared is not shown, the member variable itself is also not shown, so it's probably safe to assume the (complete) code example would probably be at least 3/4 times as large as illustrated in the C++ example above. The C++ example of course also has tons of additional unnecessary constructs, such as classes, types, constructors probably, possibly destructors, maybe even (sigh!) copy constructors, etc, etc, etc - Most of this additional overhead of course being additional unnecessary overhead it shares with all OOP languages out there. However, even ignoring the missing C++ parts, the following is obviously true ...

The Hyperlambda example is obviously 100 times more readable!

Then realise the Hyperlambda code snippet above can literally be pasted into the "Eval" menu item and immediately executed, implying it's a 100% perfectly complete example. Something you can see in the cover image for this article. Then finally, also realise that the Hyperlambda snippet for all practical concerns is just as fast as the C++ version, since 99.999999% of the time is spent waiting for IO, and the Hyperlambda snippet is 100% perfectly async, and hence shares the same traits in regards to CPU and RAM usage as its C++ equivalent. So even though C++ might sometimes be faster than Hyperlambda, the speed performance gains C++ gives you would in 99% of the times be completely irrelevant unless you're developing drivers for hardware or something similar.

Facts are, I can replace 95% of your existing OOP code, with 20% as much Hyperlambda code. If you're using C++ probably as little as 5% as much Hyperlambda code - And it'll for all practical concerns be just as fast, consume the same amount of memory, and no more CPU - Assuming you're creating web apps of course, accessing some sort of database, integrating with other HTTP services. However, the proof of that OOP is a software developer mass psychosis is literally in your code, so let me repeat the code once more for clarity reasons ...

C++

const auto ret = Tasks::join(
   m_Factories.HTTP->GET("https//gaiasoul.com"),
   m_Factories.HTTP->GET("https://servergardens.com")
).Start();
Enter fullscreen mode Exit fullscreen mode

Hyperlambda

join
   fork
      http.get:"https://gaiasoul.com"
   fork
      http.get:"https://servergardens.com"
Enter fullscreen mode Exit fullscreen mode

Really, arguing against the code is literally futile ... :/

BTW, in case you're about to show me Python, Ruby, or PHP code at this point, please realise that Hyperlambda is probably (at least) one order of magnitude faster than all of these languages ...

The explanation of the proof

If you still don't get it, try to imagine a software development noob looking at these two snippets of code, asking questions. How many questions would the noob need to ask before understanding these two code snippets. Well, the Hyperlambda version would be as follows.

  1. What's with the colon :?
  2. What's with the spaces?
  3. What's a fork?
  4. What's a join?
  5. What's a URL?

The C++ equivalent would resemble the following.

  1. What's a const?
  2. What's with the auto thing?
  3. How does assignment work?
  4. What's with the Task?
  5. What's with the double colons ::?
  6. What's a join?
  7. Why the parenthesis?
  8. What's that m_Factories thing?
  9. Why does m_Factories start with m_?
  10. What's with the . after m_factories?
  11. Why can't we use . after HTTP, and what's with the -> part?
  12. What does Start do?
  13. What's with the semicolons?
  14. What's a URL?

And if we saw the complete example, including its class declaration, we'd have an additional.

  1. What's a class?
  2. What's with that private/public/protected thing?
  3. Why does it repeat the class name 3 times? (CTOR, copy CTOR and DTOR)
  4. Etc, etc, etc ...

Facts are, once you break down C++ into questions required to have an answer to before becoming productive in the language, C++ is little more than "glorified regex", with millions of characters, tied together such that changing just a single one of these characters, typically have repercussions to your entire program. The same is also true for most other OOP languages ...

Discussion (19)

Collapse
ktsangop profile image
ktsangop

I have had the following thought about the OOP vs FP battle :
There must be 2 ways the human brain understands data/information structuring.

Whether this is genetically affected or an acquired skill (people might be learning this through education), I am not sure.

But there's no other sane explanation of why otherwise bright students that are able to easily comprehend Mathematics, Statistical Analysis, Physics, Electrical engineering etc, are confused when trying to apply the OOP paradigm.

Not sure if the same applies to FP, since I fall into the above category. I get dizzy when reading things like "SimpleBeanFactoryAwareAspectInstanceFactory" (taken from Java Spring)

It would be a nice research though. Trying to find the way the human brain can organize complex information structures, and how OOP, FP, or any other paradigm can be used, and in which cases.

Collapse
polterguy profile image
Thomas Hansen Author • Edited on

There must be 2 ways the human brain understands data/information structuring.

That's an incredibly smart observation. Personally, I look at is as follows; "Most highly skilled software developers have historically been high functioning autistic. These tends to have fewer problems understanding complex parts, resulting in that they end up adding complexity. For the autistic brain, what is a cognitive problem resulting in mental overload for the neuro typical, is easily understood due to an ability to focus and concentrate being far superior to the neuro typical brain."

Of course, today the complexity is so huge in most software projects, that even the autistic amongst us tends to get a headache and depressions having to deal with this complexity. The cure is to simplify stuff, as always. The only way to simplify stuff, is to cure autism, and/or facilitate for neuro typicals to create software.

Psst, I say this with the outmost respect for high functioning autistic brains, having been a high functioning autistic myself, whom for weird reasons "cured myself" back in 2011 as a result of a temporal lobe seizure, resulting in a cognitive revision.

As to the proof of that I used to be autistics, check up SmartWin++ - A GUI library for C++. 15 years ago, I thought it was the best thing since sliced bread, with multiple inheritance, diamond inheritance, template classes, partial template specialisations, and God knows what not. Today when I look at its code, I become physically ill thinking that I'm actually responsible for this garbage ... :/

Bjarne (Stroustrup) loved it though - And links to it from his website ... ;)

Collapse
ktsangop profile image
ktsangop

Wow ... now that's something interesting I have never heard of!

When I think of OOP in my brain, I picture it as a huge building with multiple doors and levels, from which I have to "mentally" pass through in order to "get to" the information I want.
On the other hand, I picture FP or data-oriented structures like a giant whiteboard with multiple "areas" I can "focus" to in order to "get" to the information I want.

It's easier for me because I can afford to loose focus and go back to where I was (something that constantly happens in every workday) by just remembering vaguely where the "area" of interest was on the whiteboard.

In the OOP mental model on the other hand, I cannot afford to loose focus, because then I'd have to start back from the beginning, switching floors, and opening doors...

Not sure if this makes any sense but anyway I am glad I could share my thoughts on this.
Would be interesting if someone else in the autism spectrum could share their personal experience on this.

Thread Thread
polterguy profile image
Thomas Hansen Author • Edited on

Your building versus white area actually makes very much sense. The autistic brain tends to be better at focusing on details, and needs it isolated to focus - While the neuro typical tends to be better at seeing the whole picture. It would totally explain the differences in thinking ... ;)

I can afford to loose focus and go back to where I was (something that constantly happens in every workday) by just remembering vaguely where the "area" of interest was on the whiteboard.

This is definitely one of the largest advantages I see with FP, since it becomes less "expensive" being interrupted, and you can move faster around in "the terrain" ...

In the OOP mental model on the other hand, I cannot afford to loose focus, because then I'd have to start back from the beginning, switching floors, and opening doors...

There was a study on this subject some 20 years ago. If you're debugging complex (OO) code, interrupting you for simply one minute, looses 40 minutes of work. 20 minutes to "get out" and 20 more minutes to get "back in". Not sure I (completely) agree, but it's definitely much less "expensive" being interrupted with FP than with OO ... :/

Collapse
thexdev profile image
M. Akbar Nugroho

Well, I use any programming paradigm or technology when it match some certain conditions. The task is done, problem solved, customer happy, company revenue grow and I got my sallary 🤷‍♂️.

I think ppl nowadays are too much arguing technologies instead of share how to use it properly with detailed explanation about why and when it should be used.

Collapse
peerreynders profile image
peerreynders

C++ is a systems level language - Hyperlambda isn't. Given that Hyperlambda is a higher level language (as most FP languages are) one would expect it to be less verbose than C++.

Lisp as an Alternative to Java (Peter Norvig):

"I wrote my version in Lisp. It took me about 2 hours (compared to a range of 2 to 8.5 hours for the other Lisp programmers in the study, 3 to 25 for C/C++ and 4 to 63 for Java) and I ended up with 45 non-comment non-blank lines (compared with a range of 51 to 182 for Lisp, and 107 to 614 for the other languages). (That means that some Java programmer was spending 13 lines and 84 minutes to provide the functionality of each line of my Lisp program.)"

Norvig's piece tends to give the impression that fewer lines will be always be written faster. But all it really shows is that Norvig and his fellow lispers are extremely adept at wielding their language of choice.

I would hypothesize that in fact many (not all) of those Java Programmers, even after being trained in Lisp, would still take their 4 to 63 hours and write the Lisp code without arriving at a terse solution (taking additional time to compact it).

A better comparison would be between C++ and Rust. While Rust is imperative it isn't Object-Oriented and is largely expression based which allows all sorts of tactics that were inspired by functional programming languages. However having to satisfy the borrow checker can lead to more verbose code, nothing to say about the time required to "fight it"—likely leading to the comparison turning out inconclusive. Of course that kind of comparison wouldn't be useful in promoting Hyperlambda.

polterguy profile image
Thomas Hansen Author

In my 20+ years of software development I haven't faced a problem that is solved by this.

:D

Point taken ^_^

Thread Thread
moopet profile image
Ben Sinclair

I'm looking at the example as well and wondering basically what the Hyperlambda one does. It's not clear how the (a)synchronicity works to me.

Either the whole thing blocks inside join until all the forked paths complete or it returns some kind of result which is a "pending" state, like a promise.

The thing about the assignment, as well... in the C++ example you say that newbies will look and ask what the assignment's for - well I'm wondering why you included it at all. If you miss it out, then (presumably) the two pieces of code do much the same thing, except this C++ version does it in a particular order rather than in parallel.

Thread Thread
polterguy profile image
Thomas Hansen Author

It creates two thread, and waits for both of them to finish. It's non-blocking invocations (async), so no threads are blocked while it's waiting for IO. Remove the join, and it no longer waits. The result becomes additional nodes below the http.get invocations. You can run it through the "Evaluator" in the Magic dashboard to see its result ...

Collapse
wesen profile image
Manuel Odendahl

I'm not sure what discussing syntax has to do with OOP.

The advantage of OOP for me here is that:

  • the memory layout and lifetime of my HTTP calls and concurrency constructs is exposed
  • i can pass in different implementations of GET (with TLS, with or without mocks, etc...) or use a DI framework
  • i use a pattern that is well understood (factory)

OOP is a paradigm, and within that paradigm certain ideas can be expressed easily. In OOP that is the concept of data coupled to function, polymorphism and inheritance for code reuse, and a wide range of well known patterns (factories, strategy, facade, builder, CQRS, observer, visitor). They often have pretty straight forward mappings to functional programming patterns as well.

Thinking about memory layout and ownership in functional paradigms, as well as runtime behaviour, is much harder than in OOP, at least for me. I can't look at a function and quickly see how much memory it will allocate, nor where data is captured and later on released.

There's no reason you couldn't write

join(http::get("foobar"), 
       http::get("blabla"));
Enter fullscreen mode Exit fullscreen mode

and skip the factories, for example. That C++ decided to use :: as namespace separator, parentheses as function call operator and ; as statement delimiter is kind of irrelevant. I find it easier to read, you don't, who cares.

I understand that if you are not familiar with C++, the syntax and concepts might be confusing, but we're talking professional development by people who understand their tools. When I talk about factories with someone doing OOP, we build upon a shared understanding of what it means.

Collapse
polterguy profile image
Thomas Hansen Author • Edited on

I understand that if you are not familiar with C++, the syntax and concepts might be confusing, but we're talking professional development by people who understand their tools

I am familiar with C++. I think I'm attributed in the C++ std in fact - At the very least Bjarne Stroustrup used to link to my C++ GUI library (SmartWin) from his home page. I have barely touched upon it since 2008 though. I checked it up a little bit in 2016, at which point I was amazed by its lambda features, and other "functional features" - All of which are arguably ripoffs from FP. However, C++ gives me a headache, because keeping a reference to a destroyed object yields unpredicted results, dereferencing a deleted pointer results in (God knows what), and it's got way too much complexity to do even the simplest of things.

I have the same relationship to C++ (and OOP in general) as I do to having brain surgery. I'll do it if I have to, but I'll do everything I can to avoid needing it ...

Collapse
wesen profile image
Manuel Odendahl

Memory ownership is at this point a reasonably well solved problem. You can use unique_ptr or the plethora of other smart pointers. As for c++ having anonymous functions, that indeed cuts down on boilerplate. There's a discussion to be had on how much modern c++ and the STL really are "OOP". I personally don't use the STL and stick with a more traditional "struct with methods" approach, leveraging the template system to strongly enforce invariants at compile time.

Collapse
polterguy profile image
Thomas Hansen Author • Edited on

You're right of course ...

There's a use case in my code example in fact ... ;)

Collapse
peerreynders profile image
peerreynders • Edited on

Game Oriented Assembly Lisp

2005:
"In all honesty, the biggest reason we're [Naughty Dog] not using GOAL for next-gen development is because we're now part of Sony. I can only imagine Sony's shock when they purchased Naughty Dog a few years back, hoping to be able to leverage some of our technology across other Sony studios, and then realized that there was no way anyone else would be able to use any of our codebase.
:)

Sony wants us to be able to share code with other studios, and this works both ways - both other studios using our code and vice versa. Add this to the difficulty curve of learning a new language for new hires, lack of support from external development tools (we had our own compiler, linker, and debugger, and pretty much had to use Emacs as our IDE), etc, means that there are clearly a lot of other factors involved. Note, however, that these issues aren't really technical problems, they're social ones." Ref


Beating the Averages (Paul Graham, 2001/2003):

"In January 2003, Yahoo released a new version of the editor written in C++ and Perl."


Why OO was popular? by Joe Armstrong

  • Reason 1 - It was thought to be easy to learn.
  • Reason 2 - It was thought to make code reuse easier.
  • Reason 3 - It was hyped.
  • Reason 4 - It created a new software industry.

I see no evidence of 1 and 2. Reasons 3 and 4 seem to be the driving force behind the technology. If a language technology is so bad that it creates a new industry to solve problems of its own making then it must be a good idea for the guys who want to make money.

This is is the real driving force behind OOPs.


Not much has changed and no mass psychosis is required.

Collapse
polterguy profile image
Thomas Hansen Author • Edited on

Being in the middle of the road is not an accomplishment to celebrate, it's simply proof of that the statistical probability of that you're about to be hit by a car just increased exponentially ...

Collapse
wjohnsaunders profile image
wjohnsaunders

So if I posted a really long example in C doing the same parallel fetch of 2 URLs, by calling posix threads and curl APIs, would that disprove your theory? After all C is not OOP, never has been. I think you are confusing the term OOP with the level of abstraction that a language operates at. C and C++ operate much closer to the CPU hardware, where higher level languages operate much further away.

Also I am interested in how Hyperlambda would allow that code example to be unit tested. Some languages with introspection have the ability to redirect to mocks, is Hyperlambda like that? C++ does not, so you have no choice but to make those "seams" used for testing visible in the code. e.g. m_Factories.

Collapse
polterguy profile image
Thomas Hansen Author

I am interested in how Hyperlambda would allow that code example to be unit tested

It's a "click button thing", the system automatically generates integration tests by allowing you to replay HTTP invocations.