To save content items to your account,
please confirm that you agree to abide by our usage policies.
If this is the first time you use this feature, you will be asked to authorise Cambridge Core to connect with your account.
Find out more about saving content to .
To save content items to your Kindle, first ensure no-reply@cambridge.org
is added to your Approved Personal Document E-mail List under your Personal Document Settings
on the Manage Your Content and Devices page of your Amazon account. Then enter the ‘name’ part
of your Kindle email address below.
Find out more about saving to your Kindle.
Note you can select to save to either the @free.kindle.com or @kindle.com variations.
‘@free.kindle.com’ emails are free but can only be saved to your device when it is connected to wi-fi.
‘@kindle.com’ emails can be delivered even when you are not connected to wi-fi, but note that service fees apply.
Fortran 90 includes several features to give the programmer the tools necessary to manage dynamic memory usage. However, one tends to think of these tools as completely free-standing statements or functions. In practice, a large code often has several related arrays or pointers that need to be created and released from memory at the same time. Basically, that means we should supply subprograms that generalize the operations provided by the intrinsic functions allocated and associated.
Here we illustrate this concept with a segment of a class that came from a classic finite element analysis system. The attributes are various types of allocatable arrays – local integers that will establish the array sizes. Additional items required to manage the memory are accessed through the use association of the module, called system_constants. The encapsulated members include initialization, debugging, and printing subprograms as well as the actual memory management members.
Figure 9.1 shows segments of the code Elem_Type_Data_Class. Here the word “type” is not used in the language sense but to identify one of about 18 possible finite elements from an existing library (such as a line, triangle, tetrahedron, etc.). Among the class attributes note that the local integer array item, line 5, serves the purpose of checking for local fatal error checks. It is sized to receive the number of subgroup allocations. Recall that the allocate function has an optional status return code, stat=, lines 36, 37, and so forth.
In Section 1.7 we outlined procedures that should be considered while conducting the object-oriented analysis and object-oriented design phases that are necessary before the OOP can begin. Here we will expand on those concepts, but the reader is encouraged to read some of the books on those subjects. Many of the references on OOA and OOD rely heavily on detailed graphical diagrams to describe the classes, their attributes and states, and how they interact with other classes. Often those OO methods do not go into any programming language–specific approaches. Our interest is on OOP, and so we usually will assume that the OOA and OOD have been completed and supplied to us as a set of tables that describe the application and possibly a software interface contract. Sometimes we will use a subset of the common OO methods diagrams to represent the attributes and members of our classes graphically. Since they are being used for OOP, the graphical representations will contain, in part, the intrinsic-data type descriptions of the language being employed as well as the derived types created with them.
The Drill Class
Our first illustration of typical OO methods will be to apply them to a common electric drill. It feeds a rotating cutting bit through a workpiece, thereby removing a volume of material. The effort (power or torque) required to make the hole clearly depends on the material of the workpiece as well as the attributes of the drill.
The preceding chapter described the programming process as starting with a clearly specified task, expressing it mathematically as a set of algorithms, translating the algorithms into pseudocode, and finally, translating the pseudocode into a “real” programming language. The final stages of this prescription work because most (if not all) computational languages have remarkable similarities: they have statements, the sequencing of which is controlled by various loop and conditional constructs, and functions that foster program modularization. We indicated how similar Matlab, C++, and Fortran are at this level, but these languages differ the more they are detailed. It is the purpose of this chapter to describe those details and bring you from a superficial acquaintance with a computational language to fluency. Today, the practicing engineer needs more than one programming language or environment. Once achieving familiarity with one, you will find that learning other languages is easy.
When selecting a programming tool for engineering calculations, one is often faced with two different levels of need. One level occurs when you need to solve a small problem quickly once, such as a homework assignment, and computational efficiency is not important. You may not care if your code takes 10 seconds or 100 seconds to execute; you want convenience. At that level it may make sense to use an engineering environment like Matlab or Mathematica.
The use of object-oriented (OO) design and object-oriented programming (OOP) methods is becoming increasingly popular. Thus, it is useful to have an introductory understanding of OOP and some of the programming features of OO languages. You can develop OO software in any high-level language like C or Pascal. However, newer languages such as Ada, C++, and F90 have enhanced features that make OOP much more natural, practical, and maintainable. Appearing before F90, C++ currently is probably the most popular OOP language, yet F90 was clearly designed to have almost all of the abilities of C++. However, rather than study the new standards, many authors simply refer to the two-decade-old F77 standard and declare that Fortran can not be used for OOP. Here we will overcome that misinformed point of view.
Modern OO languages provide the programmer with three capabilities that improve and simplify the design of such programs: encapsulation, inheritance, and polymorphism (or generic functionality). Related topics involve objects, classes, and data hiding. An object combines various classical data types into a set that defines a new variable type or structure. A class unifies the new entity types and supporting data that represent its state with routines (functions and subroutines) that access or modify those data, or both. Every object created from a class, by providing the necessary data, is called an instance of the class. In older languages like C and F77, the data and functions are separate entities.
We have seen that F90 has a very strong intrinsic base for supporting the use of subscripted arrays. Fortran arrays can contain intrinsic data types as well as user-defined types (i.e., ADTs). One cannot directly have an array of pointers, but an array containing defined types that are pointers or that have components that are pointers is allowable. Arrays offer an efficient way to contain information and to insert and extract information. However, there are many times when creating an efficient algorithm dictates that we use some specialized storage method, or container, and a set of operations to act with that storage mode. The storage representation and the set of operations that are allowed for it are known as a data structure. How you store and retrieve an item from a container is often independent of the nature of the item itself. Thus, different instances of a data structure may produce containers for different types of objects. Data structures have the potential for a large amount of code reuse, which is a basic goal of OOP methods. In the following sections we will consider some of the more commonly used containers. We will begin with stacks and queues, which are illustrated in Figure 7.1.
Stacks
A stack is a data structure in which access is restricted to the last inserted object. It is referred to as a last-in first-out (LIFO) container. In other words, a stack is a container to which elements may only be inserted or removed at one end of the container called the top of the stack.
There has been an explosion of interest in, and books on, object-oriented programming (OOP). Why have yet another book on the subject? In the past a basic education was intended to result in mastery of the three r's: reading, 'riting, and 'rithmetic. Today a sound education in engineering programming leads to producing code that satisfies the four r's: readability, reusability, reliability, and real efficiency. Although some object-oriented programming languages have some of these abilities, Fortran 90/95 offers all of them for engineering applications. Thus, this book is intended to take a different tack by using the Fortran 90/95 language as its main OOP tool. With more than 100 pure and hybrid object-oriented languages available, one must be selective in deciding which ones merit the effort of learning to utilize them. There are millions of Fortran programmers, and so it is logical to present the hybrid object-oriented features of Fortran 90/95 to them to update and expand their programming skills. This work provides an introduction to Fortran 90 as well as to OOP concepts. Even with the current release (Fortran 95) we will demonstrate that Fortran offers essentially all of the tools recommended for OOP techniques. It is expected that Fortran 200X will offer additional object-oriented capabilities such as declaring “extensible” (or virtual) functions. Thus, it is expected that the tools learned here will be of value far into the future.
As we saw earlier in our introduction to OOP, inheritance is a mechanism for deriving a new class from an older base class. That is, the base class, sometimes called the super class, is supplemented or selectively altered to create the new derived class. Inheritance provides a powerful code reuse mechanism since a hierarchy of related classes can be created that share the same code. A class can be derived from an existing base class using the module construct illustrated in Figure 6.1.
We note that the inheritance is invoked by the USE statement. Sometimes an inherited entity (attribute or member) needs to be slightly amended for the purposes of the new classes. Thus, at times one may want to bring into the new class selectively only certain entities from the base class. The modifier ONLY in a USE statement allows one to select the desired entities from the base class as illustrated in Figure 6.2. It is also common to develop name conflicts when combining entities from one or more related classes. Thus, a rename modifier, =>, is also provided for a USE statement to allow the programmer to pick a new local name for an entity inherited from the base class. The form for that modifier is given in Figure 6.3.
It is logical to extend any or all of the aforementioned inheritance mechanisms to produce multiple inheritance. Multiple Inheritance allows a derived class to be created by using inheritance from more than a single base class.
Any computer program is going to have to operate on the available data. The valid data types that are available will vary from one language to another. Here we will examine the intrinsic or built-in data types and user-defined data types or structures and, finally, introduce the concept of the abstract data type, which is the basic foundation of object-oriented methods. We will also consider the precision associated with numerical data types. The Fortran data types are listed in Table 2.1. Such data can be used as constants, variables, pointers, and targets.
Intrinsic Types
The simplest data type is the LOGICAL type, which has the Boolean values of either .true. or .false. and is used for relational operations. The other nonnumeric data type is the CHARACTER. The sets of valid character values will be defined by the hardware system on which the compiler is installed. Character sets may be available in multiple languages such as English and Japanese. There are international standards for computer character sets. The two most common ones are the English character sets defined in the ASCII and EBCDIC standards that have been adapted by the International Standards Organization (ISO). Both of these standards for defining single characters include the digits (0 to 9), the 26 uppercase letters (A to Z), the 26 lowercase letters (a to z), common mathematical symbols, and many nonprintable codes known as control characters.
It is common in engineering and mathematics to employ a notation in which one or more subscripts are appended to a variable that is a member of some larger set. Such a variable may be a member of a list of scalars, or it may represent an element in a vector, matrix, or Cartesian tensor. In engineering computation, we usually refer to subscripted variables as arrays. Since programming languages do not have a convenient way to append the subscripts, we actually denote them by placing them in parentheses or square brackets. Thus, an element usually written as Ajk becomes A(j,k) in Fortran and Matlab, and A[j] [k] in C++.
Arrays have properties that need to be understood in order to utilize them correctly in any programming language. The primary feature of an array is that it must have at least one subscript. The “rank” of an array is the number of subscripts, or dimensions, it has. Fortran allows an array to have up to seven subscripts, C++ allows four, and Matlab allows only two since it deals only with matrices. An array with two subscripts is called a rank-two array, and one with a single subscript is called a rank-one array, or a vector. Matrices are rank-two arrays that obey special mathematical operations. A scalar variable has no subscripts and is sometimes called a rank-zero array. Rank-one arrays with an extent of one are also viewed as a scalar.
Among other characteristics, an intelligent entity – whether an intelligent autonomous agent, or an intelligent assistant – must have the ability to go beyond just following direct instructions while in pursuit of a goal. This is necessary to be able to behave intelligently when the assumptions surrounding the direct instructions are not valid, or there are no direct instructions at all. For example even a seemingly direct instruction of ‘bring me coffee’ to an assistant requires the assistant to figure out what to do if the coffee pot is out of water, or if the coffee machine is broken. The assistant will definitely be referred to as lacking intelligence if he or she were to report to the boss that there is no water in the coffee pot and ask the boss what to do next. On the other hand, an assistant will be considered intelligent if he or she can take a high level request of ‘make travel arrangements for my trip to International AI conference 20XX’ and figure out the lecture times of the boss; take into account airline, hotel and car rental preferences; take into account the budget limitations, etc.; overcome hurdles such as the preferred flight being sold out; and make satisfactory arrangements. This example illustrates one benchmark of intelligence – the level of request an entity can handle.