CSC 332 NOTE B.pdf
Document Details
Uploaded by SuperbField
Air Force Institute of Technology
Tags
Full Transcript
Language Evaluation Criteria The evaluation of these features, focuses on their impact on the software development process, including maintenance. To do this, we need a set of evaluation criteria. Such a list of criteria is necessarily controversial, because it is difficult to get even two computer...
Language Evaluation Criteria The evaluation of these features, focuses on their impact on the software development process, including maintenance. To do this, we need a set of evaluation criteria. Such a list of criteria is necessarily controversial, because it is difficult to get even two computer scientists to agree on the value of some given language characteristic relative to others. Some of these characteristics are broad and somewhat vague (unclear/hazy), such as writability, whereas others are specific language constructs, such as exception handling. Although the discussion implied that the criteria have equal importance. Table 1: Language evaluation criteria and the characteristics that affect them --------------------------------------------------------------------------------------------------------------------- CRITERIA --------------------------------------------------------------------------------------------------------------------- Characteristic READABILITY WRITABILITY RELIABILITY Simplicity Orthogonality Data types Syntax design Support for abstraction Expressivity Type checking Exception handling Restricted aliasing ---------------------------------------------------------------------------------------- i. Readability One of the most important criteria for judging a programming language is the ease with which programs can be read and understood. Before 1970, software development was largely thought of in terms of writing code. The primary positive characteristic of programming languages was efficiency. Language constructs were designed more from the point of view of the computer than of the computer users. Software life- cycle concept was developed; maintenance is determined in large part by the readability of programs, readability became an important measure of the quality of programs and programming languages. There was a distinct crossover from a focus on machine orientation to a focus on human orientation. Readability must be considered in the context of the problem domain. For example, if a program that describes a computation is written in a language not designed for such use, the program may be unnatural and convoluted, making it unusually difficult to read. Other things that contribute to the readability of a programming language. 1 a. Simplicity The overall simplicity of a programming language strongly affects its readability. A language with a large number of basic constructs is more difficult to learn than one with a smaller number. Programmers who must use a large language often learn a subset of the language and ignore its other features. This learning pattern is sometimes used to excuse the large number of language constructs, but that argument is not valid. Readability problems occur whenever the program’s author has learned a different subset from that subset with which the reader is familiar. A second complicating characteristic of a programming language is feature multiplicity—that is, having more than one way to accomplish a particular operation. For example, in Java, a user can increment a simple integer variable in four different ways: count = count + 1 count += 1 count++ ++count Although the last two statements have slightly different meanings from each other and from the others in some contexts, all of them have the same meaning when used as stand-alone expressions. A third potential problem is operator overloading, in which a single operator symbol has more than one meaning. Although this is often useful, it can lead to reduced readability if users are allowed to create their own overloading and do not do it sensibly. For example, it is clearly acceptable to overload + to use it for both integer and floating- point addition. In fact, this overloading simplifies a language by reducing the number of operators. However, suppose the programmer defined + used between single-dimensioned array operands to mean the sum of all elements of both arrays. Because the usual meaning of vector addition is quite different from this, it would make the program more confusing for both the author and the program’s readers. b. Orthogonality Orthogonality in a programming language means that a relatively small set of primitive constructs can be combined in a relatively small number of ways to build the control and data structures of the language. Furthermore, every possible combination of primitives is legal and meaningful. For example, consider data types. Suppose a language has four primitive data types (integer, float, double, and character) and two type operators (array and pointer). If the two type operators can be applied to themselves and the four primitive data types, a large number of data structures can be defined. A lack of orthogonality leads to exceptions to the rules of the language. Too much orthogonality can also cause problems. Perhaps the most orthogonal programming language is ALGOL 68. Some believe that functional languages offer a good combination of simplicity and orthogonality. A functional language, such as LISP, is one in which computations are made primarily by applying functions to given parameters. In contrast, in imperative languages such as C, C++, and Java, computations are usually specified with variables and assignment statements. Functional languages offer potentially the greatest overall simplicity, because they can accomplish everything with a single construct, the function call, which can be combined simply with other function calls. This simple elegance is the reason why some language researchers are attracted to functional languages as the primary alternative to complex nonfunctional languages such as C++. Other factors, such as efficiency, however, have prevented functional languages from becoming more widely used. c. Data Types The presence of adequate facilities for defining data types and data structures in a language is another significant aid to readability. For example, suppose a numeric type is used for an indicator flag because there is no Boolean type in the language. In such a language, we might have an assignment such as the following: 2 timeOut = 1 The meaning of this statement is unclear, whereas in a language that includes Boolean types, we would have the following: timeOut = true The meaning of this statement is perfectly clear. d. Syntax Design The syntax, or form, of the elements of a language has a significant effect on the readability of programs. Following are some examples of syntactic design choices that affect readability: Special words. Program appearance and thus program readability are strongly influenced by the forms of a language’s special words (for example, while, class, and for). Especially important is the method of forming compound statements, or statement groups, primarily in control constructs. Some languages have used matching pairs of special words or symbols to form groups. C and its descendants use braces to specify compound statements. All of these languages suffer because statement groups are always terminated in the same way, which makes it difficult to determine which group is being ended when an end or a right brace appears. Fortran 95 and Ada make this clearer by using a distinct closing syntax for each type of statement group. For example, Ada uses end if to terminate a selection construct and end loop to terminate a loop construct. ii.. Writability Writability is a measure of how easily a language can be used to create programs for a chosen problem domain. Most of the language characteristics that affect readability also affect writability. This follows directly from the fact that the process of writing a program requires the programmer frequently to reread the part of the program that is already written. As is the case with readability, writability must be considered in the context of the target problem domain of a language. It is simply not reasonable to compare the writability of two languages in the realm of a particular application when one was designed for that application and the other was not. For example, the writabilities of Visual BASIC (VB) and C are dramatically different for creating a program that has a graphical user interface, for which VB is ideal. Their writabilities are also quite different for writing systems programs, such as an operation system, for which C was designed. The following subsections describe the most important characteristics influencing the writability of a language. a. Simplicity and Orthogonality If a language has a large number of different constructs, some programmers might not be familiar with all of them. This situation can lead to a misuse of some features. b. Support for Abstraction Briefly, abstraction means the ability to define and then use complicated structures or operations in ways that allow many of the details to be ignored. The degree of abstraction allowed by a programming language and the naturalness of its expression are therefore important to its writability. Programming languages can support two distinct categories of abstraction, process and data. A simple example of process abstraction is the use of a subprogram to implement a sort algorithm that is required several times in a program. Without the subprogram, the sort code would need to be replicated in all places where it was needed, which would make the program much longer and more tedious to write. 3 c. Expressivity It means that there are very powerful operators that allow a great deal of computation to be accomplished with a very small program. More commonly, it means that a language has relatively convenient, rather than cumbersome, ways of specifying computations. For example, in C, the notation count++ is more convenient and shorter than count = count + 1. Also, the and then Boolean operator in Ada is a convenient way of specifying short-circuit evaluation of a Boolean expression. The inclusion of the for statement in Java makes writing counting loops easier than with the use of while, which is also possible. All of these increase the writability of a language. iii. Reliability A program is said to be reliable if it performs to its specifications under all conditions. The following subsections describe several language features that have a significant effect on the reliability of programs in a given language. a. Type Checking Type checking is simply testing for type errors in a given program, either by the compiler or during program execution. Type checking is an important factor in language reliability. Because run-time type checking is expensive, compile-time type checking is more desirable. Furthermore, the earlier errors in programs are detected, the less expensive it is to make the required repairs. The design of Java requires checks of the types of nearly all variables and expressions at compile time. This virtually eliminates type errors at run time in Java programs. If the software fails in a critical system, such as a nuclear power plant or an X-ray machine for medical use, the cost could be very high. The failures of noncritical systems can also be very expensive in terms of lost future business or lawsuits over defective software systems. The final consideration is the cost of maintaining programs, which includes both corrections and modifications to add new functionality. The cost of software maintenance depends on a number of language characteristics, primarily readability. Because maintenance is often done by individuals other than the original author of the software, poor readability can make the task extremely challenging. The importance of software maintainability cannot be overstated. It has been estimated that for large software systems with relatively long lifetimes, maintenance costs can be as high as two to four times as much as development costs. Of all the contributors to language costs, three are most important: program development, maintenance, and reliability. Because these are functions of writability and readability, these two evaluation criteria are, in turn, the most important. Of course, a number of other criteria could be used for evaluating programming languages. One example is portability, or the ease with which programs can be moved from one implementation to another. Portability is most strongly influenced by the degree of standardization of the language. Some languages, such as BASIC, are not standardized at all, making programs in these languages very difficult to move from one implementation to another. Standardization is a time-consuming and difficult process. A committee began work on producing a standard version of C++ in 1989. It was approved in 1998. Generality (the applicability to a wide range of applications) and welldefinedness (the completeness and precision of the language’s official defining document) are two other criteria. Trade-offs in Language Design Reliability vs. cost of execution: – e.g: Java demands all references to array elements be checked for proper indexing, which leads to increased execution costs. 4 Readability vs. writability: e.g: APL provides many powerful operators (and a large number of new symbols), allowing complex computations to be written in a compact program but at the cost of poor readability. Writability (flexibility) vs. reliability:e.g: C++ pointers are powerful and very flexible but are unreliable. Influences on Language Design In addition to those factors described above, several other factors influence the basic design of programming languages. The most important of these are computer architecture and programming design methodologies. Computer Architecture The basic architecture of computers has had a profound effect on language design. Most of the popular languages of the past 50 years have been designed around the prevalent computer architecture, called the von Neumann architecture, after one of its originators, John von Neumann (pronounced “von Noyman”). These languages are called imperative languages. In a von Neumann computer, both data and programs are stored in the same memory. The central processing unit (CPU), which executes instructions, is separate from the memory. Therefore, instructions and data must be transmitted, or piped, from memory to the CPU. Results of operations in the CPU must be moved back to memory. See Fig below Because of the von Neumann architecture, the central features of imperative languages are variables, which model the memory cells; assignment statements, which are based on the piping operation; and the iterative form of repetition, which is the most efficient way to implement repetition on this architecture. Operands in expressions are piped from memory to the CPU, and the result of evaluating the expression is piped back to the memory cell represented by the left side of the assignment. Iteration is fast on von Neumann computers because instructions are stored in adjacent cells of memory and repeating the execution of a section of code requires only 5 a branch instruction. This efficiency discourages the use of recursion for repetition, although recursion is sometimes more natural. The execution of a machine code program on a von Neumann architecture computer occurs in a process called the fetch-execute cycle. As stated earlier, programs reside in memory but are executed in the CPU. Each instruction to be executed must be moved from memory to the processor. The address of the next instruction to be executed is maintained in a register called the program counter. The fetch-execute cycle can be simply described by the following algorithm: initialize the program counter repeat forever fetch the instruction pointed to by the program counter increment the program counter to point at the next instruction decode the instruction execute the instruction end repeat The “decode the instruction” step in the algorithm means the instruction is examined to determine what action it specifies. Program execution terminates when a stop instruction is encountered, although on an actual computer a stop instruction is rarely executed. Rather, control transfers from the operating system to a user program for its execution and then back to the operating system when the user program execution is complete. In a computer system in which more than one user program may be in memory at a given time, this process is far more complex. As stated earlier, a functional, or applicative, language is one in which the primary means of computation is applying functions to given parameters. Programming can be done in a functional language without the kind of variables that are used in imperative languages, without assignment statements, and without iteration. Although many computer scientists have expounded on the myriad benefits of functional languages, such as Scheme, it is unlikely that they will displace the imperative languages until a non–von Neumann computer is designed that allows efficient execution of programs in functional languages. Among those who have bemoaned this fact, the most eloquent is John Backus (1978), the principal designer of the original version of Fortran. In spite of the fact that the structure of imperative programming languages is modeled on a machine architecture, rather than on the abilities and inclinations of the users of programming languages, some believe that using imperative languages is somehow more natural than using a functional language. So, these people believe that even if functional programs were as efficient as imperative programs, the use of imperative programming languages would still dominate. Programming Design Methodologies Progressively larger and more complex problems were being solved by computers. Rather than simply solving sets of equations to simulate satellite tracks, as in the early 1960s, programs were being written for large and complex tasks, such as controlling large petroleum-refining facilities and providing worldwide airline reservation systems. The new software development methodologies that emerged as a result of the research of the 1970s were called top- down design and stepwise refinement. The primary programming language deficiencies that were discovered were incompleteness of type checking and inadequacy of control statements (requiring the extensive use of gotos). In the late 1970s, a shift from procedure-oriented to data-oriented program design methodologies began. 6 However, most languages designed since the late 1970s support data abstraction. The latest step in the evolution of data-oriented software development, which began in the early 1980s, is object-oriented design. Object-oriented methodology begins with data abstraction, which encapsulates processing with data objects and controls access to data, and adds inheritance and dynamic method binding. Inheritance is a powerful concept that greatly enhances the potential reuse of existing software, thereby providing the possibility of significant languages, support for object-oriented programming is now part of most popular imperative languages, including Ada 95 (ARM, 1995), Java, C++, and C#. Object-oriented concepts have also found their way into functional programming in CLOS and F#, as well as logic programming in Prolog++ Procedure-oriented programming (POP) is, in a sense, the opposite of Data oriented programming (DOP). Although data-oriented methods now dominate software development, procedure-oriented methods have not been abandoned. On the contrary, in recent years, a good deal of research has occurred in procedure-oriented programming, especially in the area of concurrency. These research efforts brought with them the need for language facilities for creating and controlling concurrent program units. Ada, Java, and C# include such capabilities. All of these evolutionary steps in software development methodologies led to new language constructs to support them. Language Categories/Paradigms Programming languages are often categorized into bins or paradigms: Procedural, Functional, Object Oriented, Declarative-non-algorithmic languages, scripting languages a. imperative, b. functional, c. logic, d. Procedural e. object oriented. It is important to note that some programming languages support multiple paradigms. For instance, Python and Java are in this category. These two languages are predominantly object oriented in nature but they have support for some other programming paradigms to some extent. Python is a High Level Programming Language that supports imperative, object oriented and functional programming paradigms Language Paradigms A. Imperative Programming Languages Designed around the von Neumann architecture.– Computation is performed through statements that change a program’s state. – Central features are variables, assignment statements, and iteration; sequencing of commands, explicit state update via assignment. Imperative programming is called so because it is based on commands that update variables held in storage. In the 1950s, the first programming language designers recognized that variables and assignment commands constitute a simple but useful abstraction from the memory fetch and update of computers' instruction sets. This close relationship with computer architecture has largely led to efficient implementation. Languages that fall into the imperative paradigm have two main features: they state the order in which operations occur, with constructs that explicitly control that order and they allow side effects. In which state can be modified at one point in time, within one unit of code, and then later read at a different point in time inside a different unit of code. The communication between the units of code in an imperative language is not explicit. The key concepts of imperative programming languages are 7 i. Variables ii. Commands iii. Procedures iv. Data abstraction. Examples of languages in this category include: FORTRAN (FORTRAN 77, FORTRAN 98), ALGOL (ALGOL 58, ALGOL 60), C and ADA and so on. – May include : OO programming languages, scripting languages, and visual languages. E.g. Pascal, C/C++, Java, Perl, JavaScript, Visual BASIC.NET B. Functional Programming Languages – The main means of making computations is by applying functions to given parameters. E.g: LISP, Scheme, ML, Haskell – May include OO concepts. The model of computation in functional programming languages is the application of functions to arguments. The key concepts of functional programming are: i. Expressions are key concept of functional programming because their purpose is to compute new values from old ones. This is the very essence of functional programming. ii. Functions are key concept of functional programming because functions abstract over expressions. iii. Parametric polymorphism is a key concept of functional programming because it enables a function to operate on values of a family of types. In practice, many useful functions are naturally polymorphic, and parametric polymorphism greatly magnifies the power and expressiveness of a functional language. iv. Data abstraction is a key concept in the more modern functional languages such as ML and HASKELL. Data abstraction supports separation of important issues, which is essential for the design and implementation of large programs. v. Lazy evaluation is based on the simple notion that an expression whose value is never used need never be evaluated. C. Logic Programming Languages Rule-based (rules are specified in no particular order). – Computations are made through a logical inference process. – Example: Prolog, CLIPS. – May include OO concepts. A logic program implements a relation. Since relations are more general than mappings, logic programming is potentially higher-level than imperative or functional programming. The key concepts of logic programming are therefore: i. Assertions ii. Horn clauses iii. Relations 8 Prolog is an example of a programming language that follows the Logic paradigm. PROLOG's primitive values are numbers and atoms. Atoms can be compared with one another, but have no other properties. They are used to represent real-world objects that are primitive. D. Procedural Programming Paradigm Procedural programming can be defined as a subtype of imperative programming as a programming paradigm based upon the concept of procedure calls, in which statements are structured into procedures (also known as subroutines or functions). Procedure calls are modular and are bound by scope. Procedural programming (PP), also known as inline programming takes a top-down approach. It is about writing a list of instructions to tell the computer what to do step by step. It relies on procedures or routines. Example CLS input “enter a number”; x input “Enter another number”;y y=x*y Print “The result = “;y End It simply contains a series of computational steps to be carried out. Any given procedure might be called at any point during a program's execution, including by other procedures or itself. The first major procedural programming languages are Fortran, ALGOL, COBOL and BASIC around 60s, while Pascal and C were published closer to the 1970s. Computer processors provide hardware support for procedural programming through a stack register and instructions for calling procedures and returning from them. Often, the terms "procedural programming" and "imperative programming" are used synonymously. However, procedural programming relies heavily on blocks and scope, whereas imperative programming as a whole may or may not have such features. As such, procedural languages generally use reserved words that act on blocks, such as if, while, and for, to implement control flow, whereas non-structured imperative languages use goto statements and branch tables for the same purpose. Sample programs Two Programs to use block if for procedural and GOTO statement for imperative to perform the same task using QBASIC. 9 i. Use of block if (Procedural paradigm) CLS Input “Enter your name”; n$ Input “Enter your age”; age If age>=18 then Print n$, “you are eligible to vote in Nigeria” Else Print n$, “you are not eligible to vote in Nigeria” End if End ii. Use of GOTO (Imperative paradigm) CLS Input “Enter your name”; n$ Input “Enter your age”; age If age 7 x 824.20 this is an assignment statement and it has 3 components 1. Assignment operator (=) 2. Result = identifier (Total) and 3. Expression at the right hand side (N*AM) - Performing this instruction involves fetching the values associated with the operands in the expression from main storage, performing the required operations (multiplication in this case) and then storing the result in the location(s) in storage associated with the identifier Total. - Sometimes, identifier appear on both sides e.g. T=T+X This helps in count or array of numbers. 28 Control Structure Order in which program instructions are performed need control sometime. All programming problems no matter how complex may be reduced to combinations of controlled sequence, selections or repetitions of basic operations on data. This is the theory behind the concept of "structured programming". This regulate the order in which program statements are executed. Sequence:- Where there is no selections or repetitions in program, they are executed in sequence as they appear in the program. e.g. statement 1 " 2 " 3... Selection : This is decision making facilities within programming languages by allowing alternative actions base on conditions that exist at a particular stage in programming. e.g. true or false (Boolean), if..then...else statement, case..true or false.. endcase etc, it may be nesting when we have more than one of such statement e.g. Nested if..then..elses. if GL