1. Introduction
    How does one compare programming languages? Should one succumb to Flon's axiom and Turing Tar-pit? And thus choose any language available. Alternatively, should one choose best possible language amongst the available languages? We shall discuss following criteria for choosing the language of interest:
    1. Evaluate language based on its features as readability, simplicity, expressibility and portability.
    2. Available support tools such as compilers and debuggers.
    3. Intended purpose of a given language for example whether language is a general purpose or specialized language?
    4. Availability of object-oriented libraries and designs of abstract data types.

  2. Flon's Axiom
    Flon's Axiom states:
    There does not now, nor will there ever, exist a programming language in which it is least bit hard to write bad programs.
    What does it say about evaluating programming languages?
    In essence, it implies that it is not the programming languages but the programmers that can be classified as good or bad. There is an equal possibility of misusing language constructs in almost all the languages. These constructs can include a wide range of possibilities as goto's, global variables, conditionals, block structures, procedures, pointers and so on. The list seems endless.

    For example, one can make a program highly unreadable by using nested blocks or using procedures with too many parameters. Similarly, low cohesion within a module or high coupling between different modules of a program can make it difficult to understand and modify. Unrestricted use of pointers can result in intractable bugs.

    Thus, Flon's axiom suggest that energy should be directed in the direction of educating programmers rather than attempting to find perfect language or even formally defining structured programming.

    Do we agree with it?
    We agree with Flon's axiom per se but not with its consequences. That is, while it is true that it is possible to write bad programs in all the languages, it does not mean that we should not attempt to find a perfect language or define structured programming. If we had not done so, high level languages would not have evolved, since we can surely write all programs in assembly level language.

    Moreover, we should also find ways to design constructs so that probability of their misuse is decreased if not entirely eliminated. For example, in Java, one cannot use pointers at the user's level, even though they are used internally to the language. This way misuse of pointer decreases.

  3. Turing Tar-pit
    Turing Tar-pit states:
    All computing languages or computers can compute anything in theory but nothing of practical interest is easy.
    What does it say about comparing programming languages?
    It says that all programming languages are all computing languages are, in theory, universal that is equivalent in their computing abilities and just differ from each other in speed. Each language is equivalent to others in term of its computing abilities, that is computing everything that can be computed by lambda calculus. However, in practice, its highly painful and uneasy to actually compute anything of interest i.e. one gets sucked into tar-pit while getting any real work done by these languages.

    This means that no language is perfect. In other words, while all languages have capabilities of Turing's machine, each have their own inadequacies as well.

    What does Turing's tar-pit say about arguments on language features?
    It says that each language has limitations, thus making it difficult to get any interesting work done, by it. For example, restrictions in Pascal, as written by Kernighan, are as following:

    The language is inadequate but circumscribed, because there is no way to escape its limitations. There are no casts to disable the type-checking when necessary. There is no way to replace the defective run-time environment with a sensible one, unless one controls the compiler that defines the "standard procedures". The language is closed.

    People who use Pascal for serious programming fall into a fatal trap. Because the language is impotent, it must be extended. But, each group extends Pascal in its own direction, to make it look like whatever language they really want. Extensions for separate compilation, FORTRAN-like COMMON, string data types, internal static variables, initialization, octal numbers, bit operators, etc., all add to the utility of the language for one group but destroy its portability to others.

    Is there any way out of Turing's Tar-pit?
    The ways out of Turing's Tar-pit are as following :

    1. Choose the language carefully, depending on the intended purpose of its use. For example, for performing Artificial Intelligence related work, it would be advisable to use Lisp and Prolog. This is because Prolog has less adequacies in terms of logic programming and Lisp in symbolic representation of problem search space. Similarly, for handling databases, SQL, Sybase will be better than C or C++.
    2. Design languages for specific purposes.

    These approaches will ease the task of getting specific work done.

  4. Language Criteria
    Here we present several factors that we feel are important in comparing programming languages. These factors are relevant even when comparing across the programming paradigms. The factors have been divided into four areas to demonstrate their relationship to one another.

    1. Programming Efficiency
      1. Maintainability
        • How easily new features can be added to the program and how easily errors can be found and corrected.
        • Achieved by good structure, readable syntax, comments, modularity, ...
        • Software Engineering

      2. Expressiveness/Writability
        • How quickly, concisely, correctly, and clearly complex structures and processes can be expressed in the language.
        • "The language is to provide a framework of abstractions and structures that are appropriately adapted to our mental habits, capabilities, and limitations." -- Wirth
        • Recursion 1st introduced in LISP and Algol60
        • Block Structure

      3. Readability
        • How easy it is to comprehend the computations in a program.
        • COBOL tried to look like English
        • "Since, in principle, programs should be read by others, or reread by their authors, before being submitted to the computer, it would be wise for the programming language designer to concentrate on the easier task of designing a readable language to begin with." -- Hoare

    2. Simplicity
      1. The language constructs should be simple to understand and there should be few ambiguities.

      2. The syntax should aid the programmer and not be a burden. -- Wirth

      3. Generality
        • Language has few special cases
        • "==" in C is not general because it applies to all types except arrays and structs
        • Constants in Pascal are not general because constants cannot be assigned an expression whereas other variables can be assigned expressions.

      4. Orthogonality
        • Language constructs should behave the same when used in different contexts
        • Orthogonality deals with the behavior of structures/features
        • C is not orthogonal with respect to arrays and functions
          • The default is to pass parameters by value, but when an array is used C passes it by reference. In this case, functions are behaving differently.
          • Functions also behave differently with respect to 'return'. In the context of arrays, in other words, when arrays are being used, the function will not return an array. To be orthogonal functions must behave the same when asked to return arrays as when asked to return integers.

      5. Uniformity
        • Language constructs with similar meanings should look similar
        • Language constructs with different meanings should look different
        • Uniformity deals with syntactical structure
        • Pascal is not uniform in its treatment of while and repeat loops -- while requires begin-end but repeat does not
        • Pascal does not use ":=" uniformly. ":=" is used both for assignment to variables and as a 'return' inside functions.
        • C does not treat '*' uniformly. It is used for multiplication and for dereferencing pointers.

    3. Extensibility
      1. How easily a programmer can add new features to the language

      2. LISP is extensible -- it basically allows addition of keywords

      3. C++ is extensible -- functions are added through libraries

      4. C and several other languages are extensible by allowing user-defined types

    4. Intended Purpose
      1. How well the language supports the activities that are needed for this project

      2. JAVA would work well for GUI programming vs. SQL would work well for DataBase programming

    Note that these factors can and often do contradict one another!
    ...Much of this information was found in the Louden source.

  5. Compiler Criteria
    Language is as good as its compiler [6]. A language without compiler has no practical value. However, language and compiler are different -- language allows programmers to express what they desire to perform, and compiler realizes their desires by carrying out the functions stated by the language. Hence, compiler is an important factor when choosing programming languages.

    1. Efficiency
      There are 3 types of efficiency for compiler: translation, execution and optimization.

      1. Translation
        During the program development stage, programs would be compiled frequently. Re-compilation is unavoidable -- either for incremental development or bug-fix. Slow compilation deters the progress of program development. Hence, fast translation is critical, especially for big project.

      2. Execution
        The eventual purpose of program is to execute/perform the tasks/functions as stated in the program. Execution of the program must be sufficiently fast to achieve its intended purpose. Speed is the main factor why manual tasks are being automated, why we bother to spend effort writing programs. Slow program execution defeats such purpose. Latency of the program should never exceed beyond where its performance is jeopardized.

        Space is another measure of execution efficiency. Neither the program should take up large space nor consume large run-time storage. Excess storage requirement incurs expensive hardware cost. Nevertheless, often, time and space are contrary of each other -- one is sacrificed for the other. Good compiler should balance between both efficiencies.

      3. Optimization
        Closely related to execution, program is optimized in order to realize efficient execution. Optimization is either performed as part of translation or after translation. Optimization should not overly lengthen the overall translation process -- the same reasoning for translation efficiency. Optimization must also be appreciable in term of time and space of execution efficiency -- the main objective of optimization. In addition, optimization should be reliable -- intended functionality of program should not be altered.

    2. Reliability
      Assuring the integrity of translating from what the program is stated (source code) to what the program will do (executable) is a must criterion of a compiler. Compiler must translate the program in the way the language is defined. No unexpected behavior should occur during program execution as the result of compilation. Program should do only what you told to do but no more and no less. In another words, compiler itself must be bug-free.

      Compiler should detect all errors as well as possible errors (warnings) in program due to inadvertence of programmers, and report meaningfully to the programmers. No errors should be leniently forgiven. Good compiler should help programmers discovering the bugs in their programs.

    3. Portability / Machine-independence
      With different variety of machines available, programs are also desired to run on all the hardware platforms, mainly to reach out larger market of clients/customers. Programs should need no modification to compile on different machine architectures. Although it is programmers responsibility to write portable codes, compilers on different platforms for the same language must do the same thing -- create programs that function identically. It is a huge cost saving (in terms of labor and time) for the same program to be retargetable on different platforms.

    4. Conditional Compilation
      Most languages/compilers provide a way to enable conditional compilation thru the use of pragmas/compiler directives. Some pragmas are defined as part of the language, and others are extension offered by specific compilers. An example of pragma defined as part of language is #include which is defined in C for sharing function prototypes of separately defined functions.

      This might sound like this feature is directly against the portabilty criterion above, and it is! However, when carefully used, it increase programming efficiency. For example, due to marketing reason, 2 similar but with slight different programs are needed. With pragmas, programmers need not to maintain 2 copies of source codes. This makes upgrade to the program easy and consistent.

      It can be useful in improving execution efficiency by avoiding the overhead of run-time configuration. The "dead" code that due to a specific executing environment can be omitted in the target executable, which improves the translation efficiency.

  6. Tool Support Criteria
    Nowadays on the software market, there are a lot of tools available which have the purpose of assisting the programmers to write the programs. One can learn what is available from the advertisement placed in special computer magazines or on the web. There is an example catalog of C++ products . So compilers, linkers, debuggers, libraries and other tools are available. How does one choose among these?

    1. Compiler
      The compiler is really the major tool for the project implementation. Since it is not the same as the language which it implements, becides of choosing the language the compiler should also be choosen very carefully depending on the criteria described above.

    2. Debugger
      Debugging the programs usually takes much more time than the programming itself. So the tool to support the debugging is useful. The debugger such as GDB allows programmer to see what is going on "inside" the program while it executes, or what program was doing at the moment it crashed. Debugger should allow the following:

      1. Make your program stop on specified conditions or at specified points of the program.

      2. Examine state of variables, when your program has stopped.

      3. Change values of variables in your program, so you can experiment with the effects of it.

      Since debuggers insert the instruction into the program, it is important that they will not change the meaning of the program itself (orthogonality). They also should not slow down the execution of the program to the impractical point(efficiency). It is also helpful if the debugger is easy to use (simplicity and readability of instructions and documentation).

    3. Documentation
      Here we consider the documentation as language description and supporting tools manuals. Documentation is the language textbooks available through bookstores, the online books, and the tool manuals that are supplied by the tool vendors. The documentation should satisfy the following criteria:

      1. Simplicity: easy to understand, contains adequate amount of examples, not overgeneralized (the textbook containing only grammars would be of little practical use).

      2. Readability: good design, fonts, colors, sufficient amount of white space, pictures and diagrams.

      3. Reliability: the features should be explained accurately.

      4. Uniformity: the related features are described using the same style and close together (in terms of page space).

    4. Libraries(OO Libraries)
      A lot of companies supply the libraries which extend widely used languages. Since the usage of the existing libraries saves programming time it is a good idea to buy suitable ones. The useful library should:

      1. Implement the classes and/or functions that are needed for the project.

      2. Be reliable (have the correct implementation).

      3. Be efficient (in terms of time and space).

      4. Have good documentation.

      5. Be simple to use (meaninful function/class names, not too many parameters to the functions)

    5. Integrated Development Environments
      Integrated Development Environments now exist for many programming languages. For example there are C++ Builder available from Borland, Watcom C/C++ from Powersoft, and others. Those environments include editor, compiler, linker, debugger, context sensitive help, toolboxes, application wisards. As for most programming tools the criteria for comparisons of such environments would be simplicity of understanding and usage, reliability, efficiency and uniformity. Maintainability is also important (Hotline support from vendor on the web or 1-800 phone).

  7. Conclusion
    In all the above discussion we tried to determine the criteria to compare the programming languages, compilers and tools (like libraries or debuggers).

    1. The project manager should be able to choose the suitable programming language and accompanying software, provided that he knows:
      1. The goals of the project.
      2. The criteria for comparison of the programming languages and software tools.
      3. Which of the above criteria are important in order to accomplich the goals of the project well and fast.
      4. What programming languages and tool are available and how well they suit to the project. Do those languages and tools meet the needs of the project in important aspects (criteria)?

    2. Assuming that the manager knows how to compare languages and tools we can suggest the following:
      1. Study the project and decide what criteria are important.
      2. Create a table of available languages and tools and mark how well they correspond to the chosen criteria.
      3. Compare and choose the most sutable language and tools. Most probably there will be tradeoffs in this proces. The manager should consider all pros and contras carefully and without a haste.

    3. We think that the correct choice of the programming language and tools is one of the most important condition for the project not to be drown in the "turing tar-pit".

    4. Another important condition is the right team of programmers. P. Brooks and J.Frederick in their book "The Mythical Man-Month" explain the ways how to organize the proper programers team.

      They compare the big and badly organized team of programmers with the big beast caught in the tar pit. No matter how big and strong is the beast and how much it struggles - it will eventually drown.

      Brooks and Frederick suggested the small and well organized team of highly skilled specialists, and showed the way how this team should work. They say that if their advises are followed, then there is the possibility to build the bridge across the tar-pit.

      We cannot be absolutly sure if the software companies do follow the Brooks' and Frederick's advises, and how those companies choose the programming languages and tools for their projects. But it seems to be true that there is the way out of tar-pits. The indication of it is the considerable amount of good (and big) software products appearing on the maket.

    5. If the intended purposes are well understood it is possible to prepare a checklist for choosing a language because the purposes dictate what the checklist (criteria) should be. In addtion, the checklist should evaluate the "weight" instead of just a yes/no check for each criterion. Even 2 languages may both fulfill the criterion, but one may out-perform the other. Finally, priority must also be assigned to the criteria. Different languages may be excel in different criteria, and decision must be made on which criteria are much important than the others based on the needs of the projects.

  8. Resources
    1. L. Flon. On research in structured programming. ACM SIGPLAN Notices, 10(10):16-17, Oct. 1975.

    2. J. Frederick P. Brooks. The Mythical Man-Month. Addison-Wesley Publishing Co., Reading, Mass., 1975.

    3. C. A. R. Hoare. Hints on programming language design. In A. I. Wasserman, editor, Tutorial Programming Language Design, pages 43-52. IEEE, Oct. 1980.

    4. K. Louden. Programming Languages Principles and Practice. PWS Publishing Company, Boston, Mass., 1993.

    5. B. J. MacLennan. Principles of Programming Languages. Holt, Rinehart and Winston, New York, N.Y., second edition, 1987.

    6. N. Wirth. On the design of programming languages. In Information Processing 74, pages 386-393, New York, N.Y., 1974. North-Holland Publishing Co.