SEN2001 · Week 1 · Introduction

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.

programming domainreadabilitywritabilityreliabilitycostsimplicityfeature multiplicityoperator overloadingorthogonalitydata typessyntax designabstractionexpressivitytype checkingexception handlingaliasingportabilityvon Neumann architecturevon Neumann bottleneckimperativefunctionallogicobject-orienteddesign trade-off

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:

  1. Four criteria: readability, writability, reliability, cost.
  2. Everything that affects readability also affects writability and reliability.
  3. Orthogonality = no exceptions to the rule.
  4. 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)

DomainNeedLanguages
ScientificFloating-point computation, arrays, efficiencyFortran
BusinessReports, decimal numbers, character dataCOBOL
Artificial intelligenceSymbolic processing, linked listsLISP, Prolog
Systems programmingEfficiency, access to hardwareC
WebMarkup, scripting, dynamic contentHTML, 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 = true is much clearer.
  • Syntax design: special words and the ends of compound statements. end if and end 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 of static in 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 than count = count + 1, and a for loop is easier to write than the equivalent while.

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

FeatureReadabilityWritabilityReliability
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-offExample
Reliability vs cost of executionJava checks every array index: safe but slow. C does not
Readability vs writabilityAPL: very powerful operators, short programs, but very hard to read
Writability vs reliabilityC++ 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

EraFocusLanguage features
1950s and early 60sSimple applications, machine efficiency
Late 60sHuman efficiency; readability, better control structuresStructured programming, top-down design
Late 70sFrom process-oriented to data-orientedData abstraction
Mid 80sObject-orientedData abstraction + inheritance + polymorphism

Language categories

CategoryIdeaExample
ImperativeVariables, assignment, iterationC, Java, Perl, JavaScript
FunctionalComputation by applying functions to parametersLISP, Scheme, ML, F#
LogicRule-based; the order of the rules is not specifiedProlog
Markup/programming hybridExtending a markup language with programming constructsJSTL, 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

WrongCorrect
Aliasing affects readabilityIts place in the table is reliability
Orthogonality = many featuresFew constructs, combinations without exceptions
More orthogonality is always goodALGOL 68: complexity
Type checking affects writabilityIts place in the table is reliability
The biggest cost is compilingUsually maintenance
Von Neumann bottleneck = slow processorThe memory-processor connection
OOP is a separate paradigm, not imperativeMostly built on top of imperative
Feature multiplicity harms writabilityThe real harm is to readability/simplicity

Test yourself

Exam-style questions. Solve them on paper first, then reveal the answer.

Question 1easy

Which language evaluation criterion is mainly harmed by aliasing (two names for the same memory cell)?

Show answer
reliability

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.

Question 2medium

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
4; readability (simplicity, through feature multiplicity)

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.

Question 3medium

Define orthogonality and give one example of a lack of orthogonality in C.

Show answer
a small set of primitive constructs can be combined in a small number of ways and every combination is legal and meaningful; e.g. C functions can return structs but not arrays

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.

Question 4medium

Java checks every array index at run time. Which two criteria are traded off by this decision?

Show answer
reliability versus cost of execution

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.

Question 5easy

What is printed in Java?

int[] a = {1, 2};
int[] b = a;
b[0] = 9;
System.out.println(a[0]);
Show answer
9

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.

Question 6easy

What is the von Neumann bottleneck?

Show answer
the speed of the connection between memory and the CPU, which limits how fast programs run

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.

Question 7medium

Which three features of imperative languages come directly from the von Neumann architecture?

Show answer
variables (memory cells), assignment (moving data between memory and CPU), iteration (efficient on this architecture)

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.

Question 8easy

Classify each language by category: C, Scheme, Prolog, Java, XSLT.

Show answer
C: imperative; Scheme: functional; Prolog: logic; Java: object-oriented (imperative); XSLT: markup/programming hybrid

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.

Question 9medium

According to the standard table, which language characteristics affect writability and reliability but not readability?

Show answer
support for abstraction and expressivity

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.

Question 10easy

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
maintenance

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.

Question 11hard

Why can too much orthogonality also be a problem? Give the classic example language.

Show answer
it allows a huge number of combinations, which adds complexity; ALGOL 68

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.

Question 12medium

Name the three fundamental features of object-oriented languages, and the programming methodology era that led to them.

Show answer
data abstraction (encapsulation), inheritance, dynamic method binding; the shift from process-oriented to data-oriented design in the 1970s-1980s

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.

Review card

4 criteria: readability, writability, reliability, cost readability: simplicity, orthogonality, data types, syntax design writability: + support for abstraction, expressivity reliability: + type checking, exception handling, restricted aliasing feature multiplicity: count = count+1, count += 1, count++, ++count → simplicity drops operator overloading: useful, but if misused readability drops orthogonality: few primitive constructs, few ways to combine, EVERY combination legal and meaningful Missing in C: a struct can be returned, an array cannot. Too much is also bad: ALGOL 68 trade-off: reliability vs execution cost (Java index checking) readability vs writability (APL) ; writability vs reliability (C++ pointers) largest item in cost: maintenance von Neumann: data and instructions in the same memory → variables, assignment, iteration von Neumann bottleneck: speed of the connection between memory and CPU categories: imperative, functional, logic, OO, markup/programming hybrid