(Adapted from Randy Odendahl’s CSC344 notes: http://www.cs.oswego.edu/~odendahl/coursework/csc344/notes/01-e-criteria.html, significantly influenced by [RS] – Sebesta, Robert. Concepts of Programming Languages 8e.)
Robert Sebesta’s Language Evaluation Criteria
- Readability
- – program logic should be “easy” to follow.
– Among the elements that aid readability are: abstraction, info hiding, manifest interface, orthogonality.
- – program logic should be “easy” to follow.
- Writability
- Reliability
Others would add items such as maintainability to this list.
- Maintainability
- – programs should be easy to maintain.
– Maintenance includes bug fixes, enhancements to functionality, enhancements to speed or memory requirements, etc.
– The issues of readability, info hiding, manifest interface. generality, and regularity all figure heavily in maintainability.
- – programs should be easy to maintain.
Attributes of High-Level Programming Languages
[RS] also creates a table showing how each of several characteristics (or attributes) contributes to each of the criteria.The following list of characteristics is not exhaustive; not all languages have each of these attributes; in some cases these attributes may be detrimental.
- You should examine each as to its: definition, possible benefit and/or hindrance.
- Discuss each of the attributes as to how it applies to any language you know or we study. [E.g., a typical CS student at Oswego should initially be able to surmise about a “feature” and its presence or absence and its utility within the Java programming language. Later he/she would be able to “extrapolate” how it might apply to other languages as they are studied.]
- Attributes which were mentioned in the [RS] have an RS appended.
- Simplicity/orthogonality RS — readability, writability, reliability
- Simplicity [RS] – Simplicity of syntax, and few ways to do the same thing reduces errors. RS cites example of several ways to increment a counter (in Java). What is wrong with the following?
123for (int i = 0; i < 10; i = i++) {<do something>} - Control Structures RS — readability, writability, reliability
- Using special tokens/characters/delimiters and a form which reflects meaning can improve the users ability to read and write reliable code.
An example, from [www.csl.sri.com/neumann/illustrative.html], tells about a Project Mercury incident:
In FORTRAN, variables are automatically declared. And, presumably orthogonally, ALL white space is ignored. [Note: It should also be orthogonal as to what marks the end of a loop.]
Thus, if the programmer intended to write
12345DO 20 I = 1 , 100compute stuff20 CONTINUE[Note: DO is an iterative construct comparable to Pascal:
123for i := 1 to 100 do begincompute stuffendor C/Java:
123for (i = 1;i <= 100;i++) {compute stuff}]But, if instead, the programmer wrote
1DO 20 I = 1 . 100The compiler would automatically declare a REAL variable
1REAL DO20Iand generate the code to assign 1.100 to DO20I.
– No loop would be created but the code would be legal.
– No error would be flagged.The above also highlights the impossibility of absolute black-box testing to prove code is correct.testing can be used to show the presence of bugs, but never to show their absence. –Dijkstra
The overall lesson is that, to date, programmers must rely heavily on structure to ensure program correctness.
- Data types & structuresRS — readability, writability, reliability
- There must be an adequate number of facilities for defining datatypes in the language. Consider something as mundane as java.awt.Point, without which, it would be cumbersome to perform many geometric operations.
- Syntax designRS — readability
- Compare Java’s break statement to C’s. (This is also apropos to the control structures criterion.)
Java
1234567891011outer: for (i = 0; i < 10; i++) {for (j = 0; j < 10; j++) {k = nextItemThisRow();if (k == -1) { break; } // finished this rowelse if (k == -2) { break outer; } // finished whole array - exit everythingelse if (k < 0) { continue outer; } // bad data, discard entire rowelse if (k == 0) { continue; } // no more processing of this itema[i][j] = a[i][j] / k; // Note: a[i][j] /= k;}System.out.println("total # of items in row " + i + " is " + j);}C
1234567891011121314for (i = 0; i < 10; i++) {for (j = 0; j < 10; j++) {k = next_item_this_row();if (k == -1) { break; } // finished this rowelse if (k == -2) { goto after_outer; } // finished whole array - exit everythingelse if (k < 0) { goto last_of_outer; } // bad data, discard entire rowelse if (k == 0) { continue; } // no more processing of this itema[i][j] = a[i][j] / k;}fprintf(stdout,"total # of items in row %d is %d\n", i, j);last_of_outer: /* null statement */ ;}after_outer: /* null statement */ ;
- Support for abstraction RS — writability, reliability
- The ability to express problem solutions independently of the underlying hardware and system software environment. Equally important is for a language to function at levels of abstraction beyond the elements of the language itself.For example, a linked list may be made to function transparently by using different levels of abstraction.[Aside: see Dijkstra, Edgar “Go To Statement Considered Harmful“, CACM 11(3) March, 1968]
In many ways this is the most important attribute of HLL in general. Abstraction has connections to the idea of generality (below), an important concept throughout science and design.
- Expressivity RS — writability, reliability
- A good example are the features of Perl’s regular expressions. Because they are so expressive, Perl is semi-jokingly referred to as a write-only language.
- Type checking RS — reliability
- Exception handling RS — reliability
- Restricted aliasing RS — reliability
Aliasing is using the same name for multiple entities in a program. These constructs can be limited, or allowed to various degrees.
- Automation
- compile-time and run-time (and even extra-program) mechanisms which may perform tasks on behalf of the programmer/maintainer. Tasks may be done automatically include
- compile time: storage requirements, address calculation. maintenance algorithms.
- run time: initialization of variables, execution of constructor code [note importance of constructors in OOP languages]
- Generality
- describing the solution to a problem as an instance of a solution to a more general problem.This applies equally to system design, OOD, etc. A more generic definition of the principle of generality would be:
A system is general when it has several parameters which, when grounded appropriately, completely specify an instance of that system.
- Information Hiding
- variables, procedures, etc., can be hidden from view and possible corruption. In Java, packages partially aid in information hiding. But, public, private, protected and package scope are more important. As is the concept of blocks of scope in most programming languages.
- Labeling
- Things can be referred to by name, not just memory locations.This can be as simple as being able to use symbolic names for variables, to as complicated as network connection mechanisms.
- Manifest Interface
- access to procedures, data, etc., is “well-defined”.The Java API is good example of the concept of manifest interface.
- Portability
- code written for one machine can be recompiled and run on any other.
- Regularity
- a languages syntax, semantics and other aspects can be concisely catalogued.Regular syntax and semantics may obviate the need for special rules that the programmer must memorize; e.g., register names, addressing modes.
- Security
- programs can be checked for adherence to the rules of the language.
- Structure
- the syntax and semantics of the language impose a structure on a program.
- Syntactic Consistency
- similar constructs should perform similar functions.