Introduction: language evaluation criteria and influences on language design
Why we study programming languages, application domains, the readability/writability/reliability/cost criteria, orthogonality, design trade-offs, the influence of the von Neumann architecture and language categories.
This course does not teach a language; it teaches you to compare languages. Why did one language design a feature this way and another that way? Someone who asks this learns a new language quickly, chooses the right language, and uses the features of the language they use more consciously. The first week sets up the yardsticks we will use to weigh languages. On the midterm it comes as short-answer questions: “Which criterion does this feature affect?”, “What is orthogonality? Give an example from C.”
Golden rules:
- Four criteria: readability, writability, reliability, cost.
- Everything that affects readability also affects writability and reliability.
- Orthogonality = no exceptions to the rule.
- Language design is a series of trade-offs; while one criterion is gained, another is lost.
Why programming languages?
- The power to express ideas: the structures you can think of are limited by the structures of the language you know. Someone who knows the structures of other languages can imitate them in their own language.
- Choosing the right language: someone who knows only one language looks at every problem through that language.
- Learning new languages gets easier: concepts (binding, scope, parameter passing) carry over from language to language.
- Understanding implementation: knowing how a feature is implemented lets you use it efficiently (like the cost of recursion).
- Using a known language better and understanding the general development of computing.
Application domains (programming domains)
| Domain | Need | Languages |
|---|---|---|
| Scientific | Floating-point computation, arrays, efficiency | Fortran |
| Business | Reports, decimal numbers, character data | COBOL |
| Artificial intelligence | Symbolic processing, linked lists | LISP, Prolog |
| Systems programming | Efficiency, access to hardware | C |
| Web | Markup, scripting, dynamic content | HTML, JavaScript, PHP |
Evaluation criteria
Readability
The ease with which a program can be read and understood. Most of the maintenance cost is determined here.
- Simplicity: a small number of basic constructs. It has two enemies: feature multiplicity (more than one way to do the same job) and badly used operator overloading (a user-defined operator that does subtraction with
+).
int count = 0;
count = count + 1;
count += 1;
count++;
++count;
System.out.println(count);
4
Four different spellings, the same job. Assembly, on the other hand, is extremely simple in the opposite direction: few constructs, but the program is long and unreadable.
- Orthogonality: a relatively small number of primitive constructs can be combined in a relatively small number of ways, and every possible combination is legal and meaningful. Shortcomings in C: a function can return a struct but not an array; parameters are passed by value, except arrays; a struct member can be any type except void, but an array element cannot be void or a function. Too much is also harmful: the exploding combinations in ALGOL 68.
- Data types: adequate type support. If there is no Boolean type, you write
timeOut = 1;timeOut = trueis much clearer. - Syntax design: special words and the ends of compound statements.
end ifandend loop(Ada) give more information than a}. The form should reflect the meaning: the same word should not have different meanings depending on context (like the two meanings ofstaticin C).
Writability
The ease of writing programs in a domain. In addition to what affects readability:
- Support for abstraction: being able to define and use complex structures while hiding the details. Process abstraction (a subprogram), data abstraction (a class for a tree node; in Fortran 77 you would need parallel integer arrays instead).
- Expressivity: being able to express the job in a short and suitable way.
count++is easier to write thancount = count + 1, and aforloop is easier to write than the equivalentwhile.
Reliability
The program performing to its specification under all conditions.
- Type checking: catching type errors, preferably at compile time. Run-time checking is expensive, compile-time checking is cheap.
- Exception handling: being able to catch run-time errors and take corrective action.
- Aliasing: two names for the same cell. Restricting it increases reliability.
int[] a = {1, 2};
int[] b = a;
b[0] = 9;
System.out.println(a[0]);
9
- Readability and writability also affect reliability: a program written in unnatural ways is more likely to be wrong.
Cost
Programmer training, writing programs, compiling, executing, the language implementation system (a free compiler helped Java spread), the price of poor reliability (a failure in a critical system) and maintenance. In large systems the largest item is maintenance.
Summary table
| Feature | Readability | Writability | Reliability |
|---|---|---|---|
| Simplicity | ✔ | ✔ | ✔ |
| Orthogonality | ✔ | ✔ | ✔ |
| Data types | ✔ | ✔ | ✔ |
| Syntax design | ✔ | ✔ | ✔ |
| Support for abstraction | ✔ | ✔ | |
| Expressivity | ✔ | ✔ | |
| Type checking | ✔ | ||
| Exception handling | ✔ | ||
| Restricted aliasing | ✔ |
Other criteria: portability (ease of moving a program from one implementation to another), generality (wide range of applications), well-definedness (completeness of the formal definition).
Design trade-offs
| Trade-off | Example |
|---|---|
| Reliability vs cost of execution | Java checks every array index: safe but slow. C does not |
| Readability vs writability | APL: very powerful operators, short programs, but very hard to read |
| Writability vs reliability | C++ pointers: flexible and powerful, but unsafe |
int[] big = new int[3];
try { big[3] = 1; } catch (ArrayIndexOutOfBoundsException e) { System.out.println("checked"); }
checked
Influences on language design
Computer architecture
Most of today’s computers have the von Neumann architecture: data and program are in the same memory, and the processor is separate. Instructions and data are moved from memory to the processor, and results are written back. This architecture gave rise to imperative languages:
- Variables model memory cells.
- Assignment models the movement of data between memory and the processor.
- Iteration is efficient on this architecture (instructions are in consecutive cells); recursion is more expensive.
Because the processor can execute instructions much faster than they can be fetched from memory, the speed of the connection between memory and processor limits the system: the von Neumann bottleneck.
Programming methodologies
| Era | Focus | Language features |
|---|---|---|
| 1950s and early 60s | Simple applications, machine efficiency | |
| Late 60s | Human efficiency; readability, better control structures | Structured programming, top-down design |
| Late 70s | From process-oriented to data-oriented | Data abstraction |
| Mid 80s | Object-oriented | Data abstraction + inheritance + polymorphism |
Language categories
| Category | Idea | Example |
|---|---|---|
| Imperative | Variables, assignment, iteration | C, Java, Perl, JavaScript |
| Functional | Computation by applying functions to parameters | LISP, Scheme, ML, F# |
| Logic | Rule-based; the order of the rules is not specified | Prolog |
| Markup/programming hybrid | Extending a markup language with programming constructs | JSTL, XSLT |
Object-oriented languages are not a separate category but are seen as an extension of imperative languages; scripting languages (Perl, Python, Ruby) and visual languages (.NET) are also in the imperative family.
Common mistakes
| Wrong | Correct |
|---|---|
| Aliasing affects readability | Its place in the table is reliability |
| Orthogonality = many features | Few constructs, combinations without exceptions |
| More orthogonality is always good | ALGOL 68: complexity |
| Type checking affects writability | Its place in the table is reliability |
| The biggest cost is compiling | Usually maintenance |
| Von Neumann bottleneck = slow processor | The memory-processor connection |
| OOP is a separate paradigm, not imperative | Mostly built on top of imperative |
| Feature multiplicity harms writability | The real harm is to readability/simplicity |
Test yourself
Exam-style questions. Solve them on paper first, then reveal the answer.
Which language evaluation criterion is mainly harmed by aliasing (two names for the same memory cell)?
Show answer
If a variable can be changed through another name, the programmer may not notice it and the program behaves unexpectedly. In the aliasing table it appears only in the reliability column. Most languages allow aliasing because of pointers and references; restricted aliasing increases reliability.
What is printed in Java, and which criterion does this design weaken?
int count = 0;
count = count + 1;
count += 1;
count++;
++count;
System.out.println(count);Show answer
All four lines do the same job: they increase count by 1, so the result is 4. Having more than one way to do the same operation is called feature multiplicity. The reader has to recognize all of them; the language becomes less simple (simplicity) and harder to read.
Define orthogonality and give one example of a lack of orthogonality in C.
Show answer
In an orthogonal language the rules have no exceptions. In C: a function can return a struct but not an array; parameters are passed by value, except arrays (the address of the array is passed); a struct member can be any type except void. Each exception is an extra rule to learn.
Java checks every array index at run time. Which two criteria are traded off by this decision?
Show answer
Index checking catches out-of-bounds accesses (reliability increases), but it adds an extra comparison to every array access (execution cost increases). C does not check: it is fast, but an overflow silently corrupts other memory. Language design is full of trade-offs like this.
What is printed in Java?
int[] a = {1, 2};
int[] b = a;
b[0] = 9;
System.out.println(a[0]);Show answer
b = a does not copy the array; it creates a second name for the same array (an alias). A change made through b is visible from a. A reader cannot tell that a[0] changed by looking at a; a small example of why aliasing lowers reliability.
What is the von Neumann bottleneck?
Show answer
In the von Neumann architecture, instructions and data are in the same memory and the processor is separate. Every instruction and every operand must pass through this connection. Because the connection is slower than the speed at which the processor can execute instructions, it limits the speed of the system.
Which three features of imperative languages come directly from the von Neumann architecture?
Show answer
A variable models a memory cell, and assignment models data going from memory to the processor and the result being written back. Because instructions sit in consecutive cells, iteration is fast; recursion is more expensive on this architecture. That is why C, Java and Python are imperative languages.
Classify each language by category: C, Scheme, Prolog, Java, XSLT.
Show answer
Imperative: variables, assignment, loops. Functional: computation by function application. Logic: rule-based, the result comes from logical inference. OOP languages are mostly built on top of imperative languages. Markup-based languages such as XSLT and JSTL also contain limited programming constructs.
According to the standard table, which language characteristics affect writability and reliability but not readability?
Show answer
Simplicity, orthogonality, data types and syntax design affect all three criteria. Support for abstraction and expressivity affect writability and reliability. Type checking, exception handling and restricted aliasing affect only reliability.
Of the cost components of a programming language (training, writing, compiling, executing, implementation system, poor reliability, maintenance), which is usually the largest for large software systems?
Show answer
In large systems the maintenance cost can be several times the development cost. Maintenance depends largely on readability, because maintenance is usually not done by the person who first wrote the code. That is why readability is considered one of the most important criteria.
Why can too much orthogonality also be a problem? Give the classic example language.
Show answer
In ALGOL 68 almost every construct can be used anywhere (for example an if can be on the left side of an assignment). The combinations explode and the language becomes hard to learn and read; also, typing mistakes may turn into another valid meaning and go uncaught. Functional languages, on the other hand, balance orthogonality and simplicity well.
Name the three fundamental features of object-oriented languages, and the programming methodology era that led to them.
Show answer
In the 1950s-60s efficiency, in the 1970s structured programming and top-down design, and in the late 1970s data-oriented design (abstract data types) came to the front. In the 1980s OOP: data abstraction + inheritance + dynamic binding. Methodologies shape languages.
Verification: The feature multiplicity, aliasing and array bounds checking examples were run with the JDK (java verify/SEN2001/W01.java). The criteria-feature table and the definitions are conceptual; they were compared with the textbook's standard classification.