Object-oriented programming (OOP) is a programming paradigm that organizes software around objects -- data structures that bundle together data (called attributes or properties) and the functions that operate on that data (called methods). Rather than writing a program as a flat sequence of instructions, OOP models a system as a collection of interacting objects, each responsible for managing its own state and behavior. The paradigm emerged in the 1960s with the Simula language, matured in the 1980s with Smalltalk, and became the dominant approach in enterprise software through the 1990s and 2000s with C++, Java, and C#.
When you learn to program, one of the first mental models you encounter is the idea of a program as a sequence of instructions: do this, then do that, then check a condition, then do something else. This is called imperative programming -- you tell the computer how to achieve an outcome, step by step. Object-oriented programming offers a fundamentally different mental model. Instead of thinking about a program as a linear sequence, you think about it as a collection of things -- objects -- that have properties and can perform actions. These objects interact with each other. The program's behavior emerges from those interactions.
This shift in perspective sounds abstract, but it has been enormously influential. OOP is the dominant paradigm in enterprise software, mobile development, game development, and graphical user interfaces. Understanding it clearly -- including its genuine strengths, its real limitations, and the common misconceptions that surround it -- is essential for anyone working in or adjacent to software development.
"Object-oriented programming is an exceptionally bad idea which could only have originated in California." -- Edsger Dijkstra (attributed), a provocative framing that captures the genuine debate about OOP's merits that has persisted for decades among computer scientists
What OOP Is: The Core Idea
The central metaphor of object-oriented programming is that software can be structured around objects -- self-contained units that combine data (what the object is) with behavior (what the object does).
Consider a real-world example. A bank account has:
- Data: account number, owner name, current balance, transaction history
- Behavior: deposit money, withdraw money, display balance, transfer funds, calculate interest
In OOP, these are bundled together into a single object. The bank account object carries its own state (the balance) and knows how to operate on that state (the methods for depositing and withdrawing). Code that wants to deposit money into an account calls the account's deposit method -- it does not directly modify the balance variable. This bundling has specific advantages that become clearer as we examine each pillar.
Classes and Objects
The key vocabulary:
Class: A blueprint or template that defines what a type of object will contain and how it will behave. A class defines the structure; it does not itself hold data. Think of it as an architectural plan -- it specifies the design, but it is not itself a building.
Object (or instance): A specific realization of a class. If BankAccount is a class, then a specific account (account number 12345, owned by Alice, with a balance of $1,000) is an object -- an instance of the BankAccount class. You can create many instances from the same class, each with its own independent state.
A class defines what a bank account is. An object is a specific bank account that exists in the running program.
# Class definition (blueprint)
class BankAccount:
def __init__(self, owner, initial_balance):
self.owner = owner
self.balance = initial_balance
def deposit(self, amount):
self.balance += amount
def withdraw(self, amount):
if amount <= self.balance:
self.balance -= amount
else:
print("Insufficient funds")
# Object creation (specific instance)
alice_account = BankAccount("Alice", 1000)
alice_account.deposit(500) # balance is now 1500
The BankAccount class is the definition. alice_account is a specific object with its own state, created from that definition. You could create a bob_account = BankAccount("Bob", 500) from the same class -- it would have its own independent balance.
A Brief History of OOP
The object-oriented paradigm has a richer history than most programmers realize:
- 1967: Ole-Johan Dahl and Kristen Nygaard create Simula at the Norwegian Computing Center -- the first language with classes and objects. Simula was designed for simulation problems, and the idea of modeling real-world entities as software objects emerged naturally from that context.
- 1972: Alan Kay and colleagues at Xerox PARC create Smalltalk, which pushed OOP further by making everything an object, including numbers and booleans. Kay coined the term "object-oriented" and emphasized message-passing between objects as the fundamental mechanism.
- 1979: Bjarne Stroustrup begins developing C++ as "C with Classes," bringing OOP to systems programming. C++ became enormously popular in the 1980s and 1990s.
- 1995: James Gosling and Sun Microsystems release Java, designed explicitly around OOP principles with automatic memory management. Java's "write once, run anywhere" promise and its strict OOP model made it the dominant enterprise language for two decades.
- 1995: Yukihiro Matsumoto releases Ruby, where everything is an object -- even more consistently than Java.
- 2000s-present: Modern languages like Python, Kotlin, Swift, and TypeScript support OOP alongside other paradigms, reflecting a pragmatic "use what fits" philosophy.
The Four Pillars of OOP
The four fundamental principles of object-oriented programming -- encapsulation, inheritance, polymorphism, and abstraction -- are taught as pillars because they work together and each addresses a different aspect of how objects should be designed and used.
| Pillar | What It Does | Key Benefit | Common Pitfall |
|---|---|---|---|
| Encapsulation | Bundles data + methods; controls access | Prevents uncontrolled state changes | Over-engineering getters/setters |
| Inheritance | Child classes derive from parent classes | Code reuse and specialization | Deep hierarchies become rigid |
| Polymorphism | Same interface, different implementations | Extensibility without modifying existing code | Overuse makes code hard to trace |
| Abstraction | Hides complexity behind simple interfaces | Reduces cognitive load | Leaky abstractions obscure bugs |
1. Encapsulation
Encapsulation is the bundling of data and the methods that operate on that data into a single unit (the object), combined with access control -- restricting direct access to some of the object's components.
The idea: an object's internal state should be managed by the object itself, not modified directly from outside. Other parts of the program should interact with the object through a defined interface (its public methods), not by reaching into its internals.
Why this matters practically: If the internal representation of an object can be modified from anywhere in the program, bugs are extremely hard to trace -- anything could have changed the state. David Parnas, in his influential 1972 paper "On the Criteria To Be Used in Decomposing Systems into Modules," laid the theoretical groundwork for what would become encapsulation by arguing that modules should hide their internal design decisions behind stable interfaces. This principle has only become more important as codebases have grown larger.
In the bank account example: the balance variable is the internal state. External code should not be able to write alice_account.balance = -50000 directly. It should have to go through the withdraw method, which enforces the business rule that you cannot withdraw more than your balance. Encapsulation enforces that rule structurally, not just by convention.
Most OOP languages support access modifiers:
- Public: Accessible from anywhere
- Private: Accessible only within the class itself
- Protected: Accessible within the class and its subclasses
Java and C++ enforce these strictly at the compiler level. Python uses naming conventions (a leading underscore _variable suggests private, a double underscore __variable triggers name mangling) but does not prevent access -- reflecting Python's philosophy of "we are all consenting adults." The difference in enforcement philosophy reflects a genuine design debate: should languages prevent misuse or merely signal intent?
2. Inheritance
Inheritance allows one class (the subclass or child) to derive properties and behaviors from another class (the superclass or parent). The subclass inherits the parent's attributes and methods and can add its own or override the parent's.
class Animal:
def __init__(self, name):
self.name = name
def breathe(self):
return f"{self.name} breathes"
class Dog(Animal): # Dog inherits from Animal
def bark(self):
return f"{self.name} says: Woof!"
rex = Dog("Rex")
rex.breathe() # Inherited from Animal: "Rex breathes"
rex.bark() # Dog's own method: "Rex says: Woof!"
Inheritance enables code reuse: if multiple types share common behavior, define it once in the parent and inherit. It also enables specialization: a SavingsAccount and a CheckingAccount share BankAccount behavior but differ in specific rules like overdraft protection and interest calculation.
The problems with inheritance: Deep inheritance hierarchies become rigid and difficult to maintain. Changes to a parent class can have unexpected consequences throughout all its children -- a phenomenon called the fragile base class problem. This has led many experienced developers to follow the principle "favor composition over inheritance": rather than creating an is-a hierarchy (a Dog is an Animal), build objects from components that can be mixed (a Dog has a RespiratorySystem, has a VocalSystem).
The distinction matters practically. Inheritance couples classes tightly. Composition allows more flexibility. The Go programming language famously omits inheritance entirely, relying on composition and interfaces. Joshua Bloch, in Effective Java (2001), devotes an entire chapter to the dangers of inheritance and the advantages of composition -- advice that has become one of the most widely repeated guidelines in the Java ecosystem.
The Diamond Problem: When a class inherits from two parent classes that share a common ancestor, ambiguity arises about which version of an inherited method to use. C++ allows multiple inheritance and requires the programmer to resolve this explicitly. Java avoids the problem by allowing only single inheritance of classes (but multiple inheritance of interfaces). Python resolves it using a Method Resolution Order (MRO) algorithm called C3 linearization, designed by Samuele Pedroni and adopted in Python 2.3 (2003).
3. Polymorphism
Polymorphism (from Greek: "many forms") is the ability of different objects to respond to the same method call in different ways appropriate to their type.
class Shape:
def area(self):
pass # Will be defined differently in subclasses
class Circle(Shape):
def __init__(self, radius):
self.radius = radius
def area(self):
return 3.14159 * self.radius ** 2
class Rectangle(Shape):
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
return self.width * self.height
# Polymorphism in action
shapes = [Circle(5), Rectangle(4, 6), Circle(3)]
for shape in shapes:
print(shape.area()) # Each object responds to area() differently
The code that calls shape.area() does not need to know whether it is dealing with a circle or a rectangle. It just calls area() and each object handles it appropriately.
Why this matters: Code that uses polymorphism is more flexible and extensible. Adding a Triangle class later does not require changing any of the code that iterates through shapes -- as long as Triangle implements an area() method, it will work. This property -- the ability to extend a system without modifying existing code -- is formalized as the Open/Closed Principle, one of the SOLID principles described below.
There are two main forms of polymorphism:
- Subtype polymorphism (as above): Different classes responding to the same interface through inheritance
- Parametric polymorphism (generics): Code that works with any type meeting certain conditions -- for example, a
sort()function that works on a list of any type that supports comparison
Alan Kay, who coined the term "object-oriented programming," later said that the essence of OOP was not classes and inheritance but message passing -- the idea that objects communicate by sending messages to each other, and each object decides how to respond. Polymorphism is the mechanism that makes this meaningful: different objects can receive the same message and respond differently.
4. Abstraction
Abstraction is hiding complex implementation details behind a simpler interface. You interact with an abstraction without needing to understand how it works internally.
When you call alice_account.deposit(500), you do not need to know that internally the method validates the amount, updates the balance variable, logs the transaction to an audit trail, applies anti-fraud rules, and potentially notifies a monitoring system. You just know: "deposit 500 dollars." The complexity is hidden behind a simple verb.
Abstraction occurs at multiple levels in OOP:
- Method level: A method hides its implementation behind a name and parameters
- Class level: A class hides internal state management behind public methods
- Interface/abstract class level: A contract defines what an object will do without specifying how
Joel Spolsky, in his influential 2002 essay "The Law of Leaky Abstractions," warned that all non-trivial abstractions are to some degree leaky -- the hidden complexity eventually surfaces, usually at the worst possible time. Understanding this is important for using abstraction wisely: abstract enough to manage complexity, but not so much that debugging becomes impossible because you cannot see what is actually happening.
Abstraction and encapsulation are closely related but distinct. Encapsulation is the mechanism (bundling and access control). Abstraction is the outcome (the ability to use complex systems through simple interfaces).
OOP vs. Functional Programming
Functional programming (FP) is the other major paradigm that experienced developers encounter. Understanding the contrast sharpens the picture of what OOP actually is -- and when to use each.
The Core Difference
OOP organizes code around objects that hold state and expose behaviors. Objects change over time -- a bank account's balance changes as deposits and withdrawals occur. This mutable state is fundamental to the OOP model.
Functional programming organizes code around pure functions that transform data without modifying shared state. The same input always produces the same output (referential transparency). Data is treated as immutable: you do not change a value, you create a new value.
# OOP style (mutable state)
account = BankAccount("Alice", 1000)
account.deposit(500) # account.balance is now 1500
# Functional style (immutable)
def deposit(account, amount):
return {**account, "balance": account["balance"] + amount}
new_account = deposit({"owner": "Alice", "balance": 1000}, 500)
# original dict unchanged; new_account has balance 1500
When Each Works Better
| Dimension | OOP | Functional Programming |
|---|---|---|
| Modeling real-world entities | Natural fit -- objects mirror entities | More abstract, requires different thinking |
| Mutable state | Managed explicitly through encapsulation | Avoided entirely; new values created |
| Concurrency and parallelism | Challenging (shared mutable state causes race conditions) | Safer (immutable data eliminates race conditions) |
| Testing | Methods can depend on object state, harder to isolate | Pure functions easy to test: same input, same output |
| Code reuse | Inheritance and composition | Higher-order functions, function composition |
| Debugging | State changes can be hard to trace | Data flow is explicit and traceable |
| Learning curve | More intuitive for beginners (real-world metaphor) | Steeper initially, especially for those trained in imperative thinking |
| Main languages | Java, C++, Python, C#, Ruby, Kotlin | Haskell, Erlang, Clojure, F#, Elm |
Neither paradigm is universally better. Most modern languages (Python, JavaScript, Scala, Kotlin, Swift, Rust) support both styles, and experienced developers use them together -- choosing the approach that fits each part of the problem. A web application might use OOP for its domain model (users, products, orders) while using functional patterns for data transformation pipelines and request handling.
Robert C. Martin ("Uncle Bob"), author of Clean Code (2008), has argued that mature developers should be proficient in both paradigms and able to recognize when each is appropriate, rather than treating paradigm choice as an identity.
Common Misconceptions About OOP
"OOP is about classes and objects, that's it"
Many developers learn OOP as syntax -- how to write a class, how to instantiate an object -- without grasping the design principles. The four pillars are not just vocabulary; they are guidelines for making design decisions. A codebase can use OOP syntax while violating every OOP principle, producing code that is harder to maintain than the procedural code it replaced. According to a 2019 study by Tornhill and colleagues analyzing over 30,000 codebases, the most common source of technical debt in OOP systems was not lack of classes but violation of encapsulation -- classes with too many public fields and insufficient abstraction boundaries.
"More inheritance means better design"
Deep inheritance hierarchies are a warning sign, not a mark of sophistication. The Gang of Four (Gamma, Helm, Johnson, and Vlissides) in their 1994 book Design Patterns repeatedly favor composition over inheritance, and this principle has been reiterated by experienced developers for thirty years. If you find yourself building hierarchies more than three or four levels deep, something is probably wrong with the design.
"OOP is the right paradigm for everything"
OOP is the right paradigm for many things: modeling business entities with identity and state, building user interfaces, game development, large team codebases with clear module boundaries. It is not the right paradigm for everything. Data transformation pipelines, concurrent systems, scientific computation, and small scripts are often better served by functional or procedural approaches.
"Java/C++ style OOP is the only OOP"
There are genuinely different flavors of OOP. Smalltalk's model (everything is a message to an object) is different from Java's (everything must be in a class). JavaScript's prototype-based OOP is different from both -- objects inherit directly from other objects without classes as intermediaries. Python's OOP is more flexible and less ceremony-laden than Java's. The constraints of any one language are not the defining features of the paradigm.
OOP in Popular Programming Languages
Different languages implement OOP differently, reflecting different philosophies about what matters most:
Java: Strongly OOP. Almost everything must be in a class. Enforces type hierarchies through interfaces and abstract classes. Very structured, very explicit. Common in enterprise systems and Android development. As of 2024, Java remains the third most popular language on the TIOBE Index.
Python: OOP is available but not mandated. You can write procedural, OOP, or functional Python freely. Classes are "lighter" than Java's -- less boilerplate, fewer access restrictions. The duck typing philosophy ("if it walks like a duck and quacks like a duck, it's a duck") means polymorphism does not require formal inheritance hierarchies. Common in data science, web development, and automation.
JavaScript: Prototype-based OOP (objects inherit directly from other objects, not from classes). ES6 (2015) added class syntax as a more familiar abstraction over the prototype system. Understanding that JavaScript's class keyword is syntactic sugar over prototypes is important for debugging behavior that seems inconsistent with classical OOP.
C++: OOP with manual memory management. More control and more complexity. Supports multiple inheritance, operator overloading, and templates (parametric polymorphism). Common in systems programming, game engines, embedded systems, and performance-critical applications.
Ruby: Everything is an object (including numbers, booleans, and even nil). Very consistent OOP model with a strong emphasis on readability. Common in web development through the Ruby on Rails framework.
Go: No inheritance. Uses interfaces and composition exclusively. Deliberately minimal OOP -- the designers at Google intentionally omitted inheritance because they found it caused more problems than it solved in large codebases. Common in cloud infrastructure, distributed systems, and microservices.
Kotlin: Modern OOP with strong functional features, null safety, data classes, and coroutines. Designed to address Java's verbosity while remaining fully interoperable. Google's recommended language for Android development since 2019.
Rust: Not traditionally OOP, but supports encapsulation (through modules and visibility), polymorphism (through traits), and composition. No inheritance. Emphasizes memory safety without garbage collection. Increasingly adopted for systems programming where C/C++ was previously the default.
Practical OOP Design Principles
Beyond the four pillars, experienced OOP developers follow a set of design principles that guide good class design. These principles are the difference between code that merely uses OOP syntax and code that is genuinely well-structured.
"Favor object composition over class inheritance." -- Gang of Four (Gamma, Helm, Johnson, Vlissides), Design Patterns: Elements of Reusable Object-Oriented Software (1994), arguably the most repeated piece of OOP design advice in the history of software engineering
SOLID Principles
The SOLID principles, coined by Robert C. Martin in the early 2000s, are a widely cited set of five principles for OOP design:
- S -- Single Responsibility Principle: A class should have only one reason to change. A
UserAuthenticationclass should handle authentication, not also send emails and format reports. - O -- Open/Closed Principle: Classes should be open for extension but closed for modification. You should be able to add new behavior (through subclasses or composition) without changing existing, working code.
- L -- Liskov Substitution Principle: Subclasses should be substitutable for their parent classes without breaking the program. If code works with a
Shape, it should work equally well with aCircleorRectangle. Barbara Liskov formalized this principle in 1987. - I -- Interface Segregation Principle: Many specific interfaces are better than one large general interface. A class should not be forced to implement methods it does not use.
- D -- Dependency Inversion Principle: High-level modules should depend on abstractions, not concrete implementations. A
PaymentProcessorshould depend on aPaymentGatewayinterface, not on a specificStripeGatewayclass.
These principles address the most common ways OOP code becomes tangled and hard to change over time. They are not laws to be followed rigidly but guidelines that help developers make better design decisions.
Design Patterns
The "Gang of Four" design patterns (Factory, Observer, Strategy, Decorator, Singleton, and others) are reusable solutions to common OOP design problems. Published in 1994, the book Design Patterns: Elements of Reusable Object-Oriented Software remains one of the most influential programming books ever written -- though its patterns are sometimes over-applied by developers who learned them without understanding when not to use them.
Key patterns every OOP developer should know:
- Factory: Creates objects without specifying the exact class -- useful when the creation logic is complex or when the type depends on runtime conditions
- Observer: Allows objects to subscribe to events from other objects -- the foundation of most event-driven architectures and UI frameworks
- Strategy: Encapsulates interchangeable algorithms behind a common interface -- allows changing behavior at runtime
- Decorator: Adds behavior to objects dynamically without modifying their class -- avoids the combinatorial explosion of subclasses
- Singleton: Ensures only one instance of a class exists -- controversial because it introduces global state, which makes testing harder
Composition Over Inheritance in Practice
Rather than building deep hierarchies, build objects from smaller, specialized components. A Car object might contain an Engine, a Transmission, and a FuelSystem rather than extending a generic Vehicle that extends a generic Machine that extends a generic PhysicalObject.
This approach is more flexible because components can be mixed and replaced independently. Need an electric car? Swap the Engine component for an ElectricMotor component. With inheritance, you would need a parallel hierarchy of ElectricVehicle classes.
When to Choose OOP
OOP is a good fit when:
- You are modeling a domain with persistent entities that have identity and state (customers, accounts, products, game characters)
- You are working in a large team that benefits from clear class boundaries and interfaces as contracts between components
- You are building a large, long-lived codebase where encapsulation and modularity reduce the cost of change over time
- You are using frameworks and libraries that are structured around OOP conventions (Django, Spring, Rails, Unity)
- Your problem has natural hierarchies and specializations that inheritance or interface hierarchies can model cleanly
OOP is a weaker fit when:
- Your program is primarily about data transformation (consider functional programming or pipeline-oriented approaches)
- You are writing concurrent or parallel code where shared mutable state causes race conditions and bugs
- Your program is simple and short (procedural code is simpler and clearer for scripts and small utilities)
- The domain has no natural object model (some scientific, mathematical, and statistical computation)
- You need maximum performance and the overhead of object creation and method dispatch matters (rare outside systems programming)
Object-oriented programming is not a philosophy or a virtue. It is a tool with specific strengths and specific weaknesses. Understanding both -- and developing judgment about when to apply it and when to reach for something else -- is the skill that separates effective software developers from those who apply paradigms mechanically.
"The problem with object-oriented languages is they've got all this implicit environment that they carry around with them. You wanted a banana but what you got was a gorilla holding the banana and the entire jungle." -- Joe Armstrong, creator of Erlang (2011), articulating the accidental complexity that poorly designed OOP systems accumulate
References and Further Reading
- Gamma, E., Helm, R., Johnson, R., and Vlissides, J. (1994). Design Patterns: Elements of Reusable Object-Oriented Software. Addison-Wesley.
- Martin, R. C. (2008). Clean Code: A Handbook of Agile Software Craftsmanship. Prentice Hall.
- Martin, R. C. (2000). Design Principles and Design Patterns. Object Mentor White Paper.
- Bloch, J. (2001). Effective Java (1st ed.). Addison-Wesley. (3rd edition, 2018)
- Liskov, B. (1987). Data Abstraction and Hierarchy. ACM SIGPLAN Notices, 23(5), 17-34.
- Parnas, D. L. (1972). On the Criteria To Be Used in Decomposing Systems into Modules. Communications of the ACM, 15(12), 1053-1058.
- Kay, A. (1993). The Early History of Smalltalk. ACM SIGPLAN Notices, 28(3), 69-95.
- Spolsky, J. (2002). The Law of Leaky Abstractions. Joel on Software. https://www.joelonsoftware.com/2002/11/11/the-law-of-leaky-abstractions/
- Tornhill, A. (2018). Software Design X-Rays: Fix Technical Debt with Behavioral Code Analysis. Pragmatic Bookshelf.
- Stroustrup, B. (1994). The Design and Evolution of C++. Addison-Wesley.
- Armstrong, J. (2011). Interview, Coders at Work by Peter Seibel. Apress.
- TIOBE Index. (2024). TIOBE Programming Community Index. https://www.tiobe.com/tiobe-index/
- Freeman, E. and Robson, E. (2020). Head First Design Patterns (2nd ed.). O'Reilly Media.
- Pedroni, S. (2003). The Python 2.3 Method Resolution Order. Python documentation. https://www.python.org/download/releases/2.3/mro/
Frequently Asked Questions
What is object-oriented programming?
Object-oriented programming (OOP) is a programming paradigm that organizes software around objects -- data structures that bundle together data (attributes) and the functions that operate on that data (methods). Rather than writing a program as a sequence of instructions, OOP models a system as a collection of interacting objects. Each object is an instance of a class, which defines what properties and behaviors that type of object has. The paradigm emerged in the 1960s with Simula and became dominant in the 1980s and 1990s with languages like C++, Smalltalk, and Java.
What are the four pillars of OOP?
The four pillars are: encapsulation (bundling data and methods together, and controlling access to internal state); inheritance (allowing one class to derive properties and behaviors from another, enabling code reuse and specialization); polymorphism (the ability of different objects to respond to the same method call in different ways); and abstraction (hiding complex implementation details behind a simpler interface). These four concepts work together to create modular, reusable, and maintainable code.
What is the difference between OOP and functional programming?
OOP organizes code around objects that hold state and expose behaviors. Functional programming organizes code around functions that transform data without modifying shared state -- functions are pure (the same input always produces the same output) and data is immutable. OOP is generally considered more intuitive for modeling real-world entities with persistent identity. Functional programming is often considered safer for concurrent systems and easier to test because pure functions are predictable. Most modern languages support both styles.
What is inheritance and why is it sometimes a problem?
Inheritance allows a class (the child or subclass) to inherit properties and behaviors from another class (the parent or superclass). A Dog class might inherit from an Animal class, gaining properties like has_name and behaviors like breathe() while adding its own bark() method. The problem is that deep inheritance hierarchies become brittle: changes to a parent class ripple unexpectedly through all children. Many experienced developers follow the principle 'favor composition over inheritance' -- building objects from smaller components rather than creating deep parent-child chains.
When should you NOT use OOP?
OOP is less appropriate for highly concurrent or parallel computation (where shared mutable state creates bugs), for simple data transformation pipelines (where functional programming is cleaner), for performance-critical systems code where the overhead of object instantiation matters, and for mathematical or statistical computation where the functional style maps more naturally to the domain. Many modern software architectures use OOP and functional styles together, applying each where it fits best.