My useless philosophical ramblings about the ecology of programming languages (and OOP is not Java)

too many oop languages


I wanted to write this post to share, formalize, and expel my hopeless brain reveries about programming languages. Sometimes, as a hobby, I explore programming languages of different natures, and by doing this, I started to have an ethereal vision of what programming languages are.

Keep in mind that I'm not an academic. My approach is pretty raw. I like to back up my points with sources, but I can't promise 100% accuracy. Still, I hope to convey the overall picture I have in mind.

I firmly believe that getting feedback from others is crucial for refining our ideas.

I'm not 100% sure about this vision yet. I've put together my thoughts, speculations, criticisms, controversial ideas, and perhaps not enough informed musings to try and make sense of them. I've compiled them here in what I hope is a coherent manner.

So, you don't expect to leave here satisfied, because I don't either.

Fanciful comparison of programming languages with life, the universe, and everything: anthropology, sociology, economics, biology, ecology... music.

When I start thinking about "the evolution of programming languages," my mind sails, travels, surpasses the sky, and crosses space... then a planet appears, a planet of strange creatures...

Programming Languages Logos

This topic sparks my imagination. I ponder the vague similarities between PLs, ecology, food chain, and natural selection.

But PLs are fundamentally human constructs; I've always considered them influenced by the same social dynamics as other human creations. Therefore, the animal analogy may not be entirely fitting.

I don't want to write the Brief, Incomplete, and Mostly Wrong History of Programming Languages again.

music bands evolution

The vision I'm trying to share here became more concrete when I saw a delightful analogy to the music together with the programming languages history.

PLs, like natural languages, are the people who speak them. And they influence their evolution. They are communities, cultures, and collective knowledge transferred from user to user, depending on the use cases and problems the language aims to solve.

I also argue that the concepts of software construction evolved similarly, often in conjunction with the PL utilized. I believe that a form of Cargo Cult revolves around PLs and paradigms. People can have ideas and strong opinions based on their experiences in jobs, school, hobbies, literature consumed, people encountered, good or bad situations that happened, and emotions involved in doing something. Intriguing visions are the three tribes of programming and JavaScript tribalism.

In essence, I think the users' beliefs found the evolution of PLs. So, today, the programming languages we use reflect the beliefs of past users and creators, shaping our software concepts. At this juncture, solving a particular use case forces us to use a specific PL, which can sometimes lead us into what resembles an echo chamber.

echo chambers in programming

Why did you start playing a particular instrument?

Which bands do you follow?

What is your favorite song genre? And why?

If you're seeking a more profound insight into the evolution of programming languages, you might find the following resources useful:

Object-oriented programming is not so obvious!

oop influences

Today, OOP is one of the most fanatical taboos in my small programming experience.

I have mixed feelings about OOP. Don't get me wrong; I enjoy organizing my code in an OO style, but I often find myself dissatisfied with my own design: Sometimes, OOP feels unintuitive, paradoxically different from the real world, easy to make wrong, boilerplate, overly subjective, and hammered. Too often, my thoughts and discussions veer into philosophical territory. Sometimes, I believe simple data and functions work better. Also, there are times when I think an interface would be very appropriate, but others don't like using classes.

This is clearly a skill issue. I don't know enough about OOP. I can accept that, but my frustration with OOP isn't just about my lack of skills. I consistently struggle when discussing the well-known object-oriented programming paradigm with others. Too often, discussions about OOP miss the mark, diverting around interpretable principles, better naming, programming languages, language features, and past ideas.

Few discussions and sources I have found on my path don't continue to leave me unsatisfied and uncertain every time. I discover or re-discover something new every year in my quest for understanding. Furthermore, The more I examine this paradigm with people, the more I notice a common thread, but I also come across numerous conflicting ideas and strong opinions.

The Simula vs Smalltalk Diatribe

There's a narrative about the history of OOP, often revolving around Simula, Smalltalk, and the ideas of Alan Kay. Beneficial resources on this topic: Wikipedia, Alan Kay Did Not Invent Objects and Alan Kay definition of Object Oriented, after reading this material and other similar, I began to ponder whether was the high-level vision of OOP in the past, the today's perspective differs once more. And, like natural languages, we can't control it.

Some high-level ideas I find are:

  • Objects are similar to experts and collaborators(*) - I appreciate this definition because it emphasizes the concept of locality and encapsulation and is empirical rather than mathematical. Writing software is often like crafting rather than mathematics, but unfortunately, this vision complicates my hopeless pursuit of frame OOP.
  • OOP means only messaging - Sometimes it's similar to the previous, but I'm not sure; here, Small Talk, Erlang, Elixir, and the Actor Model are often mentioned.
  • Model real-life things with Classes and Inheritance - I don't entirely agree with this vision. I believe that OOP aims to model our business or real-world domain, but the real world is unrepresentable one-way, and inheritance is the worst tool for this task! Too many materials on the internet sponsor this vision (1, 2... ).
  • OOP is Clean Code - I've encountered situations where we changed code for OOP reasons. However, I thought the old way was more in line with my unsure perspective of OOP principles. Still, I liked the clarity of the new approach and supported using it.
  • Java - Another perspective I've observed is that some equate OOP with Java. I don't think that Java represents the definitive OOP approach. PLs are human creations, tools, and technology at our disposal. They are agnostic to human philosophies or mental exercises. They're simply collections of isolable PL features that carry the biases of their creators and community. I'm saying that doing Java well simply means doing Java well. OOP can be used in many places; what distinguishes the OO approach in languages like R, JavaScript, Perl 6, Racket, and Lua? Too often, I've encountered the misconception that true OOP is restricted solely to static types and static classes. But why? Is it to support the IDE's IntelliSense features?
  • OOP is Design Patterns.
  • Others? Mixes of the above?

Liskov and Inheritance are contagious virus

There are many forms of polymorphism; the most known are:

  • Ad-hoc polymorphism - often exemplified by Haskell's type classes and overloading, provides distinct function implementations for different types.
  • Parametric polymorphism - often exemplified by generics, allows functions and types to work with other types without knowing them upfront.
  • Subtype polymorphism - one type is substitutable with its subtypes. Subtype polymorphism is where OOP shines.
  • Trivia: Uiua has a super exciting form of polymorphism!

In my view, the difference between inheritance and interfaces is significant. While both involve subtyping, the distinction is profound for me. Sometimes, I think about an alternative world where OOP avoided inheritance altogether. My brain has a lot of problems with inheritance. Firstly, our human contextual hierarchical representation of reality doesn't match the object-oriented representation. Secondly, hierarchies can be overly situational. When they grow large, they become complex, difficult to dismantle, and understanding what each parent class does can be overwhelmed by cognitive load. Finally, even with basic interfaces, I have a constant and subtle fear of breaking the Liskov substitution principle. Yet, hierarchies compound this complexity by sharing data and behaviors, potentially creating confusion with indirection between overridden methods in child and parent classes, they add another level of entropy to this challenge.

"Anything that can go wrong will go wrong.", The Murphy's law is so true. How often have you encountered scenarios resembling the square/rettangle problem or the penguin problem?

I love simple interfaces.

However, you're unable to achieve the same tasks without inheritance.

Why not?

// js with inheritance 
class Father {
        this.aProperty = aProperty


class Child extends Father {

// js with delegation
class Father {
        this.aProperty = aProperty


class Child {
        this.father = father 



const child = new Child(new Father("aProperty"));

Yeah, delegation can be quite tedious and repetitive. But, sometimes, it's simply a matter of language capabilities. For instance, Go, Kotlin, Crystal, and Raku offer intriguing approaches to delegation.

# crystal with delegate
class Father
  getter a_property : String

  def initialize(a_property : String)
    @a_property = a_property

  def do_fizz
    puts "fizz"

class Child
  def initialize(@father : Father)

  delegate :do_fizz, to @father

  def do_buzz
    puts "different"

child ="value"))
// kotlin with 'by'
interface Fizzator {
    fun doFizz()

class Father(val aProperty: String) : Fizzator {
    override fun doFizz() {

class Child(father: Father) : Fizzator by father {
    fun doBuzz() {

fun main() {
    val child = Child(Father("property"))
# raku with 'handle'
class Father {
    has $.a-property;

    method do-fizz {
        say "fizz";

class Child {
    has Father $.father handles <do-fizz>;
    method do-buzz {;
        say "different";

my $father ="value"));
my $child =$father));

// golang with its interfaces
type Father struct {
    aProperty string

func (f *Father) doFizz() {

type Child struct {

func (c *Child) doBuzz() {

func main() {
    child := Child{Father{aProperty: "value"}}


Indeed, there's no silver bullet, but as I carry my beliefs, I harbor a strong bias against inheritance.

Also, the conventional viewpoint doesn't classify Golang as an OO language. However, if "OOP is not so obvious," the Golang categorization is not so obvious either. Does Go have subtyping?

Guidelines for Addressing Entropy and Power

coupling and cohesion

GRASP, SOLID, Law of Delimiter, Liskov substitution principle, Composition over Inheritance, Abstraction Principle, Coupling and Cohesion, Leaky abstraction, Port and Adapters Architecture, CQS, Anemic Domain Model, DDD... I'm starting to see OOP not as a precise manual but as a set of guidelines for navigating the complexity of software development. Sometimes, ambiguity and interpretability, as seen in legal matters, can actually be features that contribute to flexibility.


As developers, we often work to ensure our code can quickly adapt to changes in the real world. However, I feel that even when we prioritize maintainability and extendibility, coding acts as a means to document and formalize our contextual knowledge, enabling us to revisit and reactivate our understanding of the problem in the future. Focusing solely on extending the code can sometimes lead to a situation where everything is extendable. Still, we struggle to manage our cognitive load caused by widespread context and excessive generalization. I think this captures the essence of Cohesion.

A Time ago, I was fascinated by an article titled "The Unreasonable Effectiveness of Julia," which introduced me to the Expression Problem that reminds me of the Open-close-Principle. This article explored the challenge of extending a book of recipes and ingredients, raising the question of how much of the book would need to be modified when adding a new recipe or ingredient.

However, I lack sufficient experience with Julia and Multiple Dispatch to comprehend its advantages fully. At times, I feel that the capabilities of a language can surpass the limitations of other languages that lack those features.


Also, I read that there are situations when OOP guidelines may not suit specific domains that prioritize technical details over adaptability or understandability. Encapsulation and Abstraction might not work well in such cases, leading to a practice where code isn't viewed as representative of the real-world domain. Instead, code and data are treated merely for their capacity to manage bytes, cache, and cycles. This approach is known as data-oriented design.

The first principle: Data is not the problem domain:

For some, it would seem that data-oriented design is the antithesis of most other programming paradigms because data-oriented design is a technique that does not readily allow the problem domain to enter into the software so readily. It does not recognise the concept of an object in any way, as data is consistently without meaning, whereas the abstraction heavy paradigms try to pretend the computer and its data do not exist at every turn, abstracting away the idea that there are bytes, or CPU pipelines, or other hardware features. The data-oriented design approach doesn't build the real world problem into the code. This could be seen as a failing of the data-oriented approach by veteran object-oriented developers, as many examples of the success of object-oriented design come from being able to bring the human concepts to the machine, then in this middle ground, a solution can be written in this language that is understandable by both human and computer. The data-oriented approach gives up some of the human readability by leaving the problem domain in the design document, but stops the machine from having to handle human concepts at any level by just that same action.

Simple Data and Simple Functions

Additionally, sometimes, I feel that using simple data and simple functions, organizing the problem domain within immutable data structures, and envisioning our domain rules as data transformations can be more practical. I've often felt too forced by OOP's inclination to link behavior and data, leading me to create complex object chimeras influenced by my subjective view of the real world when a simple dictionary would have enough.

Principles of Data-Oriented Programming (to not confuse with data-oriented design)

I don't believe it's directly comparable to data-centric, or database-centric or data-driven architecture, or whatever you name it (why all this similar names?). I mean where interfaces and the entire software are derived and coupled to a large data structure, such as the database schema. That poses challenges when we must customize detailed implementations or change this structure, which can significantly affect the whole system. However, I recognize that overuse of this approach poses a dilemma for the Anemic Domain Model.


object good part

I'm arguing that OOP is not as obvious. If I haven't convinced you try with:

Functional programming is not so obvious, either!

fp languages influence

Programming languages are experiments

After reading A decade of developing a programming language, I started pondering: programming languages are incredibly complex beasts that evolve over time, carrying the weight of tough trade-offs and decisions made during their creation. Essentially, all the languages we use today are just experiments by their creators. Even those creators can't fully foresee how their language design will impact the software made with it. And thanks to the Lindy effect, we're still dealing with tech from the '70s and '90s.

Today, mature programming languages can present subtle issues at their core, such as null.

One day, while chatting with a friend who's really into functional programming, we started talking about OOP. The conversation shifted toward OOP literature, which mainly focuses on tackling the challenges and problems of OOP itself. Several design patterns remedy absent language features, while its principles act to circumvent issues originating from OOP itself.

scott wlaschin about fp desing patterns

I have mixed feelings about this statement and agree that OOP isn't so obvious at times. To me, OOP provides guidelines for navigating an intrinsically problematic territory. FP, instead, sets up a safe zone where problems like immutable rectangle/square, unhandled exceptions, illegal state, global state... just do not exist. However, many of these guidelines remain super valuable!

jose valim about polymorphism

Functional Programming! what?

What exactly is functional programming? I ask because numerous languages are labeled as "Functional," but their style and developer experience vary significantly. I know little about Lisp, APL, Haskell, OCaml, Prolog, Erlang...

It's interesting to learn about the perspective of a developer deeply familiar with Haskell and how significant the differences were to them when encountering OCaml, despite both languages sharing the same roots: 8 months of OCaml after 8 years of Haskell in production.

So, what is functional programming?

I rely on the insights of Richard Felman, who has offered compelling arguments on this matter.

The Essence of Functional Programming by Richard Feldman

"Maybe FP has always been vaguely shared understanding of relate ideas"

This reminds me of my previous section about OOP. However, in the realm of FP, in my experience, the emphasis often shifts towards language features rather than what I would term "guidelines".

  • ADT
  • Filter, Map, Reduce
  • Referential transparency
  • (exhaustive) Pattern Matching
  • "Function friendly" Language Ergonomics
  • High order functions
  • Recursion
  • Type Classes
  • Module Functors
  • Immutability
  • Managed Side Effect
  • Pure function
  • Category Theory
  • Laziness
  • Parametric Polymorphism and others
  • Other?...

Richard argues that there are no mandatory features for FP, but the essence of what he calls the functional style includes exclusively:

  • Avoiding mutation
  • Avoiding side effects

Learning a bit about Elm and Haskell broadened my perspective. I discovered solutions and possibilities I had never encountered before, and I was fascinated by the absence of problems that I frequently encountered when working with Java and JavaScript.

I was once again surprised when I encountered the same sensation while experimenting with Rust. But Rust is not an FP language. (it's also debated whether Rust adheres to OOP, but it's better to keep this topic apart...).

This Richard's talk helped me grasp and formalize this feeling better:

Functional Programming for Pragmatists

Substantially, can limitations and restrictions be liberating? FP style may restrict the power of the PL, like side effects and mutability, but features commonly present in FP languages bring some perks like better tools, easier testing, less thinking, and smoother refactorings. Constraining the language simplifies software, especially when low-level control isn't required. The trade-off is about adding little noise to simple tasks while facilitating complex ones.

I like what Felman says in "Why Isn't Functional Programming the Norm?" Java didn't become popular just because it was OO; it was valuable at the time(and a bit sponsored). FP isn't just about Haskell or Lisp... It's about how programming languages naturally evolve by adding new features and dropping the less valuable ones (like inheritance, maybe! :P).

Conclusion: In the end it doesn't even matter

So, programming languages are basically experiments influenced by what others before us believed. Both object-oriented programming and functional programming can be not so obvious.

In the end, the programming language we use doesn't really matter. We have little control over most of the tools we use daily because we can't alter the world's current trajectory, the software industry, or things like the lindy effect or Jevons paradox are pretty inevitable.

Jhon Carmack about tools

In the end, what matters most is agreeing on what works for us and making teamwork smooth. As people, we should focus on what we can control and find the best solution for the job without getting too stuck on our own opinions.

I enjoy learning programming languages; each new thing gives me a fresh perspective. But in the end, my goal is to deliver value to my users by creating working software. What pays off is always collaboration, having a shared way of communication with colleagues, simplicity, combating entropy, and avoiding unnecessary solutions. Writing code is only one small part of our job.

years of programming and complexity

The perfect programming language doesn't exist, or if it does, in each case, we should be capable of using it with simplicity.

Writing this post gives me a similar feeling to when I watched these talks:

I attempted to articulate my vague thoughts here. Please give me feedback on whether this post is coherent!

If you are interested, explore these particular programming languages:


interesting Articles and Resources:

Programming Languages Evolution:
- 3 tribes of programming:
- JavaScript's Dependency Problem:
- The Evolutionary Ecology of Technology: The Case of Programming Languages:
- Modelling the Evolution of Programming Languages:
- I made a family tree of all the world's languages:
- Band family trees:
- A Brief, Incomplete, and Mostly Wrong History of Programming Languages:
- Sketchpad: A Man-Machine Graphical Communication System:
- Towards a conceptual history of programming languages - Types: 
- The Next 700 Programming Language:
- Guido van Rossum about biological systems metaphor of languages:
- Programming languages genealogical tree:
- Genealogical tree of programming languages by wikipedia:
- A History of Programming Languages for 2 Voices(David Nolen and Michael Bernstein):
- Dictionary of Programming Languages:
Object Oriented Programming:
- A Solution to the Square-Rectangle Problem:
- Object-Oriented Thinking in the Data-Centric World:
- Anemic Domain Model:
- Abstraction Considered Harmful:
- Leaky abstraction:
- Cohesion and Coupling - the difference:
- Replace Delegation with Inheritance:
- Categorisation, Comparison and Cases - Einar Høst -
- Polymorphism haskell wiki -
- "The Power of Abstraction" with Prof. Barbara Liskov -
- Why extends is evil -
- If I implement an Interface, is it called an Inheritance? -
- does go have subtyping?:
- Object-oriented Programming and Modeling the Real World -
- Joe Armstrong interviews Alan Kay:
- Why you Can't Control Language:
- L'arte perduta di pensare ad oggetti, by Matteo Vaccari:
- Dr. Alan Kay on the Meaning of “Object-Oriented Programming”:
- Open issues in OOP:
- The unreasonable effectiveness of the Julia programming language:
- Extensibility for the Masses -
- Expression problem:
- The Expression Problem and its solutions:
- More thoughts on the Expression Problem in Haskell:
- Steve Jobs explains object-oriented programming:
- Introduction to Object Oriented Programming to
- What To Know Before Debating Type Systems -
- Alan Kay Did Not Invent Objects:
- Data Oriented Design, Data is not the problem domain:
- Principles of Data-Oriented Programming:
- OOP Design Dilemma - Data and Beheviour:
- People Don’t Understand OOP -
- Why is Object-Oriented Programming Bad?
- Object-Oriented Programming is Bad:
- Is Inheritance That Evil?: 

Functional Programming:
- Functional Design Patterns - Scott Wlaschin: 
- OOP vs Typeclasses - Ideology:
- 8 months of OCaml after 8 years of Haskell in production:
- The essence of functional programming by Richard Feldman:
- The Roc Programming Language with Richard Feldman (and what FP is) -
- Why Isn't Functional Programming the Norm? – Richard Feldman:
- Are Design Patterns Missing Language Features: 

- The Rust I Wanted Had No Future -
- A decade of developing a programming language: 
- The Mess We Are n: 
- Is Software Engineering Still an Oxymoron? • Alan Kay: 
- Features of a dream programming language:
- The World's Most Maintainable Programming Language:
- The Perfect Programming Language:
- Four Stages of Competence:
- The Fullstack conundrum and the commoditization of web development:

Object in various languages:
- Classes and object in Racket:
- Subtype in Racket:
- Objects in ocaml:,
- When should objects be used in OCaml?:
- Objects in Raku:
- Objects in Simula:
- Effiel Type System:
- About Eiffel origins:
- Objects in squeak: