codingstairs
NotesEDULifeContact
⌕Search⌘K
koen

Navigation

  • Intro
  • Blog
  • Life

Get in touch

Send without signing in. Add your email if you'd like a reply.

  • Leave a message anonymously →
  • ✉ warragon112@gmail.com
  • KakaoTalk Open Chat ↗

© 2026 codingstairs

  • Notes
  • EDU
  • Search
  • Life
  • Contact
  • Legal
  • RSS
  • GitHub
Notes›programming

OOP and Functional — Two Views Coexisting

Published 2026-04-28· Updated 2026-05-18·0 views

OOP and Functional — Two Views Coexisting

The question "OOP or functional?" used to be treated like a tribal feud. Today's modern languages support both, and real-world code mixes the two paradigms naturally. This article covers the origin of each paradigm, their core principles, how modern languages absorbed both, and which view fits which spot in practice.

1. About OOP and FP

OOP — the most cited origin is Smalltalk, made by Alan Kay at Xerox PARC in 1972. Before that, Simula 67 (Ole-Johan Dahl, Kristen Nygaard) introduced classes and inheritance in 1967, and Smalltalk crystallized "message passing" as a model. Alan Kay's own remark — "the core of object orientation is message passing, not classes" — is often cited. Mass adoption came with C++ in the 1980s (1985, Bjarne Stroustrup) and Java in 1995, the decisive push.

FP — the root is Lisp from 1958 (John McCarthy). The first practical language built on lambda calculus (1930s, Alonzo Church). Later ML (1973), Miranda (1985), and Haskell (1990) refined the pure functional shape, and Erlang (1986) settled into the concurrency / fault tolerance niche. Mass adoption arrived in the 2010s as the value of side-effect-free code shone again in the multicore era.

2. Four principles of OOP

Principle Meaning
Encapsulation Bind data and the behavior acting on it inside one object
Inheritance Children inherit and extend a parent's definition
Polymorphism Different implementations behind the same interface
Abstraction Hide complex internals behind a simple interface
// Java example
abstract class Animal {
  abstract String speak();
}

class Dog extends Animal {
  @Override String speak() { return "Woof"; }
}

class Cat extends Animal {
  @Override String speak() { return "Meow"; }
}

Animal a = new Dog();
a.speak(); // "Woof"  ← polymorphism

Inheritance feels powerful at first, but criticism that deep inheritance trees increase coupling and harm maintainability has accumulated, so since the 2000s "composition over inheritance" is often recommended (also stated in the GoF book).

3. Core ideas of functional

Idea Meaning
Pure function Same input always yields same output. No external state mutation
Immutability Data doesn't change after creation. Mutation = create a new value
First-class function Functions are values. Pass as args, return, store in variables
Higher-order function A function that takes or returns functions
Referential transparency Replacing an expression with its result preserves meaning
Recursion Express loops as recursion (including tail-call optimization)
// imperative
const xs = [1, 2, 3, 4];
let sum = 0;
for (let i = 0; i < xs.length; i++) sum += xs[i] * 2;

// functional
const sum2 = xs.map(x => x * 2).reduce((acc, x) => acc + x, 0);

map, filter, reduce are the most familiar spots where functional thinking has been absorbed into imperative languages.

4. Comparing the two views

Item OOP FP
State encapsulated in objects as immutable as possible
Behavior object methods free-standing functions
Coupling class hierarchy function composition
Side effects natural isolation recommended
Concurrency locks · mutexes needed natural via immutability
Modeling domain as objects domain as data + transformations

Neither is absolutely superior. The same problem fits different shapes naturally in different spots. UI, domain models, simulations lean OOP; data transformation, concurrency, validation lean FP — that's the common reading.

5. Coexistence in modern languages

Language Origin Both supported
Scala 2003 OOP + FP fusion on the JVM
Kotlin 2011 OOP-default, FP-friendly
Rust 2010 No OOP. Traits, ownership. Strong FP influence
Swift 2014 OOP + protocols, value types, higher-order functions
TypeScript 2012 Classes + first-class functions + immutability recommended
Java (8+) 2014 Lambdas and Stream API added
Python 1991 Classes + first-class functions + comprehensions
C# 2002 Lambdas, LINQ, record types

Many newer languages aim to hold the good parts of "both" rather than be "OOP only" or "FP only". The paradigm itself is no longer a tribal flag.

6. Other paths

Paradigms beyond OOP / FP:

  • Imperative — the oldest branch. C is the representative.
  • Declarative — express only "what". SQL, HTML, regex.
  • Logic programming — Prolog. Inference from facts and rules.
  • Dataflow / Reactive — RxJS, Akka Streams. Data change over time as a graph.
  • Actor model — Erlang, Akka. Small actors talk via messages.
  • CSP — Go's channels and goroutines.

7. The same task in two views

// Active users from a user list, names only, alphabetical

// OOP-style (hypothetical)
class UserService {
  constructor(users) { this.users = users; }
  getActiveSortedNames() {
    const active = [];
    for (const u of this.users) if (u.active) active.push(u);
    active.sort((a, b) => a.name.localeCompare(b.name));
    return active.map(u => u.name);
  }
}

// FP-style
const getActiveSortedNames = users =>
  users
    .filter(u => u.active)
    .map(u => u.name)
    .sort((a, b) => a.localeCompare(b));

Same result; the second is shorter and free of side effects.

// React component — a spot where the two paradigms meet naturally
function UserList({ users }) {
  const visible = users.filter(u => u.active).map(u => u.name);  // FP
  return <ul>{visible.map(n => <li key={n}>{n}</li>)}</ul>;       // component is OOP-ish
}

8. Common stumbles

Inheritance trap — deep inheritance trees explode the cost of changes. Composition or interfaces / traits are often better.

Cost of immutability — copying large data every time can hurt performance. Immer, Immutable.js, persistent data structures help.

Purity obsession — trying to write everything as pure functions tangles code where I/O and external comms live. "Push side effects to the boundary" is the practical line.

OOP obsession — modeling everything as a class. A 5-line empty class where a simple function would do.

Monad phobia — Haskell-style terminology is scary at first, but JS's Promise.then is also a monad shape. Start with syntactic familiarity.

Inconsistency from mixing — within one codebase, if the line between "where OOP, where FP" gets blurry, reading suffers. Team agreement is needed.

The flat assertion "this language is not OOP" — almost every modern language supports both. The difference is which style flows more naturally.

Closing thoughts

OOP and FP are no longer tribes but two seats in the same toolbox. Almost every modern language supports both, and real-world code mixes them naturally. UI and domain models → OOP; data transformation, validation, concurrency → FP. "Push side effects to the boundary" is the one line that combines the two views best.

Next

  • (programming end)

We refer to Alan Kay The Early History of Smalltalk (1993) · Design Patterns: Elements of Reusable Object-Oriented Software (1994) · Effective Java (Joshua Bloch) · Why Functional Programming Matters (John Hughes 1990) · Structure and Interpretation of Computer Programs (SICP) · Haskell.org Learn · Out of the Tar Pit (Moseley · Marks 2006) · Composing Software (Eric Elliott) · Scala official · Rust Book · Kotlin Docs.

More in programming

All in this category →
  • Design Patterns — Names for Recurring Solutions
  • Big O — Notation for Algorithm Performance
  • Data Structures — Containers for Data