Encapsulation, inheritance, and polymorphism are usually given as the three fundamental principles of object-oriented languages (OOLs) and object-oriented methodology. These principles depend somewhat on the type of the language.
Object-oriented languages (OOLs) fall into two broad categories:
In a class-based OOL objects are instances of and created by classes.
In a classless OOL objects serve as prototypes for other objects; objects are cloned from their prototypes.
Like many distinctions there is no true dichotomy here - the two categories are extremes of a spectrum. The JavaScript programming language, for example, does not fit cleanly into either category. It lies somewhere in between.
Some class-based OOLs (C++, Java, Scala, and Eiffel) require that all variables be typed. Others (Smalltalk and Ruby) do not. Typing variables does not make sense in classless OOLs.
Typing is a compile-time concept. It allows the compiler to make some checks for correctness that would otherwise not be detected until a program is executed.
Untyped OOLs are often used for prototyping an application. Typed OOLs are usually preferred for production applications because the compile-time error checks precisely locate errors. If these errors are not caught until run time, their cause can be very difficult to determine.
There are two important aspects of encapsulation:
Encapsulation mechanisms are essential for reducing couplings between software components. Many encapsulation mechanisms originated with non-object-oriented languages. Object-oriented languages add additional encapsulation mechanisms.
Modern non-object-oriented languages provide several encapsulation mechanisms.
Objects are a fundamental encapsulation mechanism of object-oriented languages (OOLs).
OOLs may provide additional encapsulation mechanisms.
Object-oriented encapsulation is not simple. Following rules like "one object should never access another object except through its public interface" may weaken encapsulation by compelling you to make some methods public that should be made private.
To deal with this kind of problem, most OOLs provide mechanisms that allow some objects to access private methods of another object. Java's nested classes and anonymous constructors are one example. C++ allows special access to classes that are defined as friends. These mechanisms are essential to some design patterns.
There are two types of inheritance in OOLs
Interface inheritance is only necessary in typed OOLs. This is best understood when considering delegation-based design patterns.
Implementation inheritance mechanisms depend on the type of OOL.
Polymorphism refers to the ability of different objects to respond to the same message in different ways. Polymorphism is essential for modeling our world including our social environment. We frequently use the same phrases and sentences to mean different things in different contexts. Often there is an abstract sameness, but concrete differences.
For example, say the following sentence to two different architects and you will likely get two houses: "Build me a house". Abstractly, both architects will do the same thing but many of the details will differ.
In early structured design methodology there were three principle types of control or data structure elements: sequence, alteration, and repetition. Polymorphism is often used as an alternative to alternation.
Polymorphism is implemented with a dispatch mechanism. This mechanism may only be dependent on the object that receives a message or it may also be dependent on message parameters.
Alternation is one of the early principles of programming: sequence, alternation, and repetition. A program consists of instructions that are executed sequentially (sequence) except for language constructions that allow different sequences of instructions based on conditions (alternation) and constructions that repeat sequences of instruction (repetition). Most non-object-oriented programming language provide if, if..else and case or switch statement forms as alternation constructions.
In object-oriented languages there is another alternation construction: send a message to a variable. You get different code to execute by assigning a new object to the variable. The different objects that can be assigned to a variable can respond to the message in different ways. This idea is lies at the heart of many design patterns.
A few OOLs, for example Scala, support parametric polymorphism. This means that selection of code executed in response to a message depends on both the receiver and the parameters of the message. The easiest form of polymorphism to implement makes code selection dependent only on the receiver of a message. This is called non-parametric polymorphism.
For languages that do not directly support parametric polymorphism the techniques of the Visitor design pattern can be used to achieve the same effect.
Dispatch refers to the mechanism for selecting the code executed in response to a message. The dispatch is called multiple dispatch when parametric polymorphism is supported.