Paradigms of Programming Languages


Paradigms

Although many different computer architectures are being developed, the most prevalent is still the traditional von Neumann architecture - consisting of a single sequential cpu separate from memory, with data piped between cpu and memory. This is reflected in the design of the dominant computer languages, with dynamic variables (representing memory cells with changing values); sequential iteration (reflecting the single sequential cpu); assignment statements (reflecting piping). This combination of choices gives rise to the imperative language paradigm - C, Ada, Pascal, FORTRAN, Cobol, Basic etc.

But other choices are possible - variables do not have to directly reflect memory cells (logic programming); repetition need not be iterative (logic, functional, concurrent); assignment need not be important (logic, functional); data and control need not be separated (object oriented, functional).

A paradigm is essentially a high level model of what computation is about - the unifying factor that makes Ada and C seem very similar, ignoring details such as what data or control structures are available, exactly how variables are passed to procedures, and so on.

Some Paradigms

1. In the Beginning -- Machine Languages

The first programmers had to program in machine language. The language was extremely machine independent. The programmer had to virtually think like the machine. The programmer had to know both the instruction set of the computer, and how data was represented. So, the programmer was working under the basic premise of the machine, which was: there is data, and there are instructions that process the data.

2. Assembly Languages

As computers grew in power, assemblers and assembly language came into being. This created a level of abstraction between the base machine and the programmer, allowing the programmer to think more like a human being and less like the computer. No longer did the programmer have to worry about getting the zeros and ones right -- he or she could use mnemonics, constants, literals and pseudo-ops. Assembly languages also allowed functionality to be isolated and reused through the use of subroutines. Subroutines basically extended the instruction set of the computer. However, the assembly languages carried the basic premise of the machine into its abstraction: There is data, and there are instructions and subroutines that process the data.

3. Higher Level Languages

Around 1954, the first FORTRAN compiler was developed, and higher level languages came into being. These compiled and interpreted languages created another level of abstraction between the programmer and the base machine. The programmer could replace miles of assembly code with one expression or statement. Again, programming languages took another step towards the way people normally think, and the way the computer thinks. In addition, the higher level languages were (theoretically) machine independent. The compiled and interpreted languages also had functions and subroutines, which further allowed the programmer to extend the instruction set of the computer. However, the higher level languages had one basic premise: There is data, and there are functions / subroutines / expressions / statements that process the data.

4. Structured Languages

In the late 1960s, structured languages came into being. These languages (C, Pascal) eliminated the "goto" helping to localize and clarify code. Programmer productivity went up by a factor of 10 as a result. However, the structured languages still carried the basic premise of the Von Neuman machine: there is data, and there are instructions / functions / subroutines that process data.

5. Earlier Analysis and Design

As programs got more complex, programmers realized that there might be a better way to write programs than getting a problem statement and sitting down and writing code. In other words, a little abstract planning might help. Along these lines, some abstract modeling techniques were developed. Earlier methods included flowcharts and functional specifications, functional decomposition. Later techniques involved: The later techniques arose from the structured programming languages, and became used in structured analysis and design. The intention of the models was to create extra levels of abstraction between the real-world problem/system and the computer implementation of the system. They served as a bridge between the real world situation, and the computer code. The problem was mapped into a verbal problem statement, then into a requirements analysis model, which was far removed from the machine implementation. The analysis model was then mapped into a design model, which was one step closer to the machine implementation (the code). Finally, code was written from the design model. However, these earlier abstract models all ran on one premise -- there is data, and there are functions that process the data. The first models attempted only to model the functionality of the real-world systems. Later, entity relationship diagrams were added -- these modeled the data, or the static nature of the system. However, the functionality models and the data models were distinct and separate entities. Coad and Yourdon note in their book Object-Oriented Analysis (Prentice Hall, 1991) that the fact that there were two basic sets of models in structured analysis -- functional models and data models, created a split or rift among analysis teams. This split caused tremendous headaches.

6. OO The Object Oriented Paradigm

Is it possible to make a computer think the way people naturally think, rather than in terms of data and instructions that process data? The base machine will probably always think in terms of data and instructions that process data. However, are there high-level languages that can add another layer of abstraction on top of the machine, so that the high level languages can be written in code that mirrors the way people think? Yes, of course -- these are the OO languages! Some OO languages are better at hiding the basic premise of the machine. Smalltalk is probably the best, while C++ is probably the worst (more on this later).

1. History of OO languages.

First OO language was Simula -- 1967. Used widely in Europe, it never caught on in the U.S. Then came Smalltalk -- 1972. In 1986, Bjarne Stroustrup invented C++, and Brad Cox created Objective-C. OO languages began taking off at this time. But as of 1994, OO languages have been around for 24 years. Earlier versions, such as Smalltalk, may have been unpopular because machines weren't powerful enough to handle them.

2. What Makes a Language Object-Oriented?

According to Bertrand Meyer, an OO programming language should contain the following 7 qualities [7]:

Objects

Basic building block of OO languages is the object. Like objects of human thought, OO objects combine both data (nouns and adjectives) and actions (verbs) into one package. Data is implemented as data, while actions are implemented as functions. The machine still sees a data-functionality split. But the outside world sees data and functionality merged into one whole.

Classes

OO Languages promote classification at two levels. First, there is the class construct. Classes are like "cookie cutters" from which objects are moulded. We have a "cat" class from which we create cat objects, each with different attributes. The class specifies the attributes (and the functionality) while the objects fill in the attribute values. For example, we have a cat class that has weight, color, and name attributes specified. From the cat class, we create cat objects, through which the program is actually run.

Inheritance

A looser classification scheme is obtained through inheritance. We can tie in our cat class into a whole inheritance hierarchy which includes the entire cat family, the mammals, all animals, and then all living things.

Polymorphism

Polymorphism is the method by which OO languages mirror the human thought processes' tendency to group certain actions together. We can call similar functionality by the same name -- e.g. cats eat and cows eat, but the way they eat is different. However, we still call their actions "eating". OO languages allow for similar functions (actions) to be given similar names. This allows for conceptual clarity in writing code. Note that C and other traditional languages use polymorphism to some extent. For example, the arithmetic operators act on both floating point numbers and integers with the same operators (+, - , /, *, etc) even though the underlying implementation is radically different.

Abstraction

Software objects mirror the human mind's tendency to abstract out details. Software objects hide the internal details of an object behind the walls of an interface. The "user" or "client" of an object does not have to worry about the inner details of the object, only the abstract principles of the object, as defined by the interface.