Copyright © 2010 David Schmidt

Chapter 0:
An Introduction to Language Paradigms


0.1 Software architecture paradigms
0.2 Software architectures must be coded in distinct styles
0.3 Programming-language paradigms
    0.3.1 Programming language anatomy
    0.3.2 Programming-language-design stages
0.4 Designing your own language to fit the job


A paradigm is a pattern or stylistic approach to doing or stating something. For example, when you prepare your resumé, you use a standard pattern, a paradigm, for formatting it. Another paradigm is the layout of the engine in a car --- although there are many different models of car, virtually all of them use the same design for their internal-combustion engine. Paradigms are useful to architects, who design and build skyscrapers with one paradigm and wood-frame, family residences with another. Writers use paradigms for short stories, novels, and newspaper stories. Paradigms are used by scientists and engineers, too.

Paradigms are useful to computer hardware --- there are standard chip layouts, network layouts, etc. --- and they are also useful to software architects, who lay out components in patterns that work well for specific applications. In the next section, we review some paradigms for building large software systems.

There are also paradigms for thinking about and solving problems. We call these programming (language) paradigms. One of the purposes of this course is to expose you to several programming paradigms, and in this chapter we learn why this is useful.


0.1 Software architecture paradigms

Before we consider programming-language paradigms, we start with a related subject that is easier to appreciate: the paradigms (architectures) for building large software systems. The material that follows is taken from a longer presentation, Software architecture: an informal introduction, which you are welcome to read.

When a complex piece of software is designed, coded, and assembled, there must be some architectural plan that is followed. If you have completed the CIS501 course on software architecture, you learned about the reactive-system architecture --- it is a collection of components, some of which receive inputs (``boundary classes''), some of which hold data structures and algorithms that compute answers (``entity classes''), and some that coordinate input-output between boundary and entity classes (``controller classes'').

In CIS501, you drew blueprints --- class diagrams and object diagrams --- that showed the architecture of reactive systems; here's an object diagram:

When a complex piece of software is designed, coded, and assembled, some architectural plan must be followed. There are several classic ones, and no doubt you have used one or more of these:

Each paradigm solves well some implementation problem. For example, if you must write an operating system or device driver, you won't use the sequential software architecture, because prior experience has proved that a hierarchical architecture works better. Similarly, there is good reason why data-base systems are repositories, and client-server systems are independent-component architectures.

When you work within a problem domain, you must choose the appropriate software architecture for solving the problems in that domain. For this reason, we will survey domain-specific models and languages at the end of this course.


0.2 Software architectures must be coded in distinct styles

Just like there are different architectural paradigms for laying out a software system, there are different paradigms for writing the code.

Just like you would be crippled if you go to work and know only one architectural paradigm, you will be crippled if you go to work knowing just one programming paradigm.

One unfortunate aspect of a course-based, four-year, college education in computing is that everyone is in a hurry to learn enough to get a job and pay off their loans. This means the instructors are pressured to structure their courses to provide just enough material so that you can program well in one language (e.g., Java), in one style (e.g., object-oriented), in one software architecture (e.g., reactive system). You are all trained to do exactly the same thing! Then, a person gets a job, finds that they aren't prepared for what the job demands, and they have to undertake remedial training.

The purpose of this course is to broaden your background so you don't fall into this trap.

Let's reconsider the software architectures listed above. How would we code them?

So, you must become knowledgeable about a variety of software architectures and you must become knowledgeable about a variety of programming styles. You can try to use Java-style to code everything, but the results will sometimes be ugly, just like the auto mechanic who tries to do all possible car repairs using just a hammer and crescent wrench.


0.3 Programming-language paradigms

The above examples hinted at these standard programming paradigms:

No one paradigm is the ``best'' way to think about problem solving; you use the paradigm that matches the job you are asked to do. You have to be good at more than one style of programming paradigm to build any nontrivial software architecture. And that is the point of this course.


0.3.1 Programming language anatomy

Although Prolog looks radically different from C, which looks radically different from ML or Smalltalk, all programming languages are languages, and languages have standard foundations. There is a traditional list of these foundations, which states that every language has a

To understand syntax, we will learn a notation for stating syntactic structure: grammar notation. This comes in the next chapter.

To understand semantics, we will learn about semantic domains of expressible, denotable, and storable values. We will learn that these domains consist of primitive and structured values. We will also learn about extension principles that enrich a language based on its semantic domains. Finally, we will see how languages like Java, ML, and Prolog are grown from ``core'' grammars and semantic domains.

To understand pragmatics, we will learn about standard models for computing the semantics of a program in a language. The models might be machines or they might be equations or they might be logic laws. In any case, the models show us how to compute execution traces of programs and understand how a language is useful.


0.3.2 Programming-language-design stages

There is another approach to understanding the foundations of a language, where the language is analyzed and even designed in stages:
  1. data structures: the values and operations of the language that compute values and the constructions of the language that group values into collections (data structures) that can be indexed and updated
  2. control structures: the constructions of the language that let one order/select/control the operations on data and structures
  3. component structures: the constructions of the language that let one join together program fragments into a complete program
The chapters that follow show how a modern, powerful language can be designed from a small core language that has minimal data, control, and component structure and then extended in the above stages into a full language with a rich set of data, control, and component structures.


0.4 Designing your own language to fit the job

There is another critical reason why we study the material in this course: When you are established at a firm or a lab, you will become expert at solving problems in one application area, one domain. You will find that your solutions will match a particular software architecture, and you will be using a particular programming paradigm. You will also find that you will develop a library of components that you reuse when you build similar solutions to similar problems in the domain.

You will reach the point where it will be useful for you to share your knowledge, your libraries, your styles with others. Maybe you will share them with non-software engineers who use your work. At this point, you might wish to develop a language that is specialized to the domain and its problems. Such a language is called a domain-specific language. You use the language to talk about programs and their solutions. If you can state solutions (algorithms) in your domain-specific language, and if a computer can understand your domain-specific language (that is, you write an interpreter for your domain-specific language), then it is a domain-specific programming language.

Most of us will never design a language like C or Java, but many of us have designed or will design domain-specific languages to solve a narrow class of problems in a specialty domain. If you want the language you design to be good quality, you must learn the concepts in this course about paradigms, syntax, and semantics --- you will rely on all three to design a useful domain-specific language.

You have probably hacked code in HTML --- it's a domain-specific language for web-page layout. You might have used a gamer package to create players and an environment for an interactive game; you have thus used a domain-specific language for gaming. And so it goes. Indeed, any nontrivial input format for an application is a domain-specific language, with its own a syntax and semantics --- language design and systems design go hand in hand.