ࡱ; %&  !"#$'()*+,R F+ CCompObj\WordDocumentLObjectPoolю Cю C  FMicrosoft Word 6.0 DocumentNB6WWord.Document.6;  Oh+'0*C\ b n z  7APS Drive:Applications:Text:Word:Templates:X3J3 paperKThe first paragraph is in style First, to avoid leaving extra white space.Kurt W. HirchertKurt ܥhA e?L;HHJJJJJJJJJJJ JJsK]JJ(JJJJJJKKMKMKMKMKMKMK&KX(LsKJJ!"JJJJsKJJJJJJJJJJJJJKK$J&JJ@JJJJJKKJSJLike many other Fortran practitioners, I found my first encounters with object-oriented programming somewhat mystifying; OOPs proponents had their own terminology, that they seemed unwilling or unable to relate to more conventional programming terminology, and they seemed unable to agree among themselves on what the characteristics of object-oriented programming are or which languages were truly object oriented. If, in the intervening time, the fog has not fully lifted, it has at least significantly thinned out, so I offer my view of object-oriented programming and its relation to Fortran. I cannot claim this view to be authoritative, but I will try to make it clear, and I hope you will find it useful. Disclaimer: Although my view of OOP has certainly been shaped by discussions in the /oof subgroup, this document should in no way be interpreted as an official subgroup position. Abstraction and Encapsulation It has long been a goal in programmer to decompose programming tasks in to smaller pieces, with one of the major goals being information hiding, to minimize the extent to which that changes in one piece necessitate changes in other pieces. To this end, nearly all programming languages have some form of procedural abstraction the ability to build a complex operation out of simpler operations and to then use that operation as a black block in building still larger operations. Most languages also have some form of representational abstraction the ability to build a complex data representation out of simpler representations and then to use that representation in aggregate, without explicitly referencing the component representations. However, problems arise when the use of procedural and representational abstractions is not coordinated. For example, one common problem can be that the internals of a representational abstraction are reflected explicitly or implicitly in too many procedures, too widely spread, so that a change in that representation becomes a major programming task. To combat these coordination problems, it is desirable to package related procedural and representational abstractions together, at minimum through appropriate methodology and more ideally through the use of supporting language features. One goal of this packaging to procedurally encapsulate the data in a representation, so the internals of that representation are reflected only in the procedures immediately associated with it. A workable approach to applying such encapsulation in Fortran is based on using modules to package derived types with private components. Such an approach does not fully resemble the syntactic approach used in languages traditionally viewed as object oriented, but it provides the functionality of language-supported encapsulation. Indeed, some observers have assumed that the purpose of modules in Fortran was to support object-oriented programming. Fortrans deficiencies in this area are those points at which it is necessary to violate the encapsulation in order to make use of other language features: initialization when creating a representation cleaning up when disposing of a representation transferring a representation to or from external media Default initialization partially addressed the first point and we are looking at derived-type I/O to address the third, but we may wish to look at allowing programmers to define destructor procedures to address the second point and constructor or initialization procedures to more thoroughly address the first point. In addition to closing these holes in the encapsulation, we might also wish to consider a method of specifying that procedures are to be expanded in-line. Encapsulation frequently involves small procedures whose primary purpose is information hiding, with little real computational work to do. Expanding such procedures in-line can significantly improve performance. Objects, Messages, and Classes There are various methodologies that one might apply in using encapsulation; in object-oriented programming, the approach is that one models the behavior of real or conceptual objects, with the encapsulated data modeling the state of that object and the encapsulating procedures modeling its behavior. Traditional OOP terminology has those objects interacting with each other by sending messages to each other. For example, if John and Joe are in a fight, the John object might Send to Joe: "I am punching you in the nose." The Joe object might then update its status to reflect a bloody nose and send a return message to John, punching him in the jaw. Typically, there would be a procedure (called a method in OOP terminology) that would perform this action. So sending the punch message to Joe had the effect of CALL Joe%Take_Punch(Nose) Now, it would be possible that the Joe and John objects were separately programmed, but a more typical scenario would be to program a Fighter class of objects and then declare the Joe and John objects to be of that class. Typical OOP notations would still suggest that Joe and John each contained their own copy of the Take_Punch procedure, but the real underlying implementation normally is that there is a single copy of Take_Punch for the entire Fighter class, with a hidden argument to say which Fighter is actually taking the punch. If we represent this explicitly, we get CALL Take_Punch(Joe,Nose) Thus, if we are willing to forgo typical OOP notation and accept a more traditional description of what is happening, we can implement this aspect of OOP without any additional features in Fortran. We use modules to define our classes, with derived types as the template for object state and procedures for the objects methods. The procedures that are public represent the kinds of messages that can be sent to objects of that class, with additional arguments representing the details that can be included in such messages. (Because you might want to send the same message to different classes of objects, these public procedure names should probably also be generic.) Declaring an object of that class is really just a matter of creating the storage for the object state, i.e., declaring a variable of the derived type. Having said this, it should be noted that even though this basic OOP methodology is implemented using the same language features as the abstract data types that motivated much of our Fortran 90 work on modules, the resulting programs are typically quite different: A typical ADT implementation (such as the ISO varying string module) contains mostly functions, many of which return values of the derived type being used to represent that abstract type; the only subroutines are likely to be those implementing the assignment operation. In contrast, most of the procedures in an OOP implementation are likely to subroutines that update the value of an existing derived-type variable; the few functions are likely to be inquiries that return basic intrinsic types such as logical or integer. In ADT implementations, the operations tend to represent the ways the value of the type can be transformed. In OOP implementations, the operations tend to represent the interactions that cause those transformations; if two different kinds of interactions cause the same transformation of the state, there should still be a distinct operation for each kind interaction (although they might use a common internal method to achieve that transformation). [Making this distinction helps reduce maintenance costs if, for example, one subsequently modifies the model so that the transformations for those interactions are not identical, only similar.] Class Hierarchies and Inheritance Much of the rest of OOP is based on the idea that classes of computer objects, like their real world counterparts, may be grouped with other classes that are different but similar. For example, classes representing Horses and Zebras would be quite similar. The strategy used for exploiting this similarity in OOP is to put the state and methods common to the similar classes into a parent class (or superclass) and then use an inheritance mechanism to make them available in the more specific classes, so that only the differences and additions need be stated in the definitions of those specific classes. In our example of Horses and Zebras, we might put the common information about Horses and Zebras in an Equine class; so the definition of the Zebra class might be that a Zebra is an Equine that has additional state for recording the stripe pattern. If there is a method Feed for the Equine class, then unless we explicitly define Feed for the Zebra class, CALL FEED(aZebra) would be interpreted as meaning CALL Feed(aZebra%Equine_Part) Obviously, it is possible now for a Fortran programmer to explicitly include TYPE Zebra TYPE(Equine)::Equine_Part END TYPE Zebra and SUBROUTINE Feed (aZebra) TYPE(Zebra)::aZebra CALL Feed (aZebra%Equine_Part) END SUBROUTINE Feed However, it is equally obviously more convenient for the programmer if the language can provide this automatically from a more abstract statement like Zebra extends Equine. It may also be worth noting that in most implementations the address of aZebra and of aZebra%Equine_Part are going to be the same, so the compiler is likely to be able to get by passing aZebra directly to the Equine version of Feed, never creating any separate code for the Zebra version of Feed. Also, as will be seen in the next section, there are ways this superclass-subclass relationship can be useful, so it seems desirable for the language to provide for this kind of inheritance. Some OOP environments provide for multiple inheritance. An example of this might be if in our example, we also created a class Striped for the state and methods common to Zebras and Tigers and wished to say Zebra extends Striped in addition to saying Zebra extends Equine. Multiple inheritance adds various complications: If Equine and Striped both have Feed methods, which one applies to Zebra by default (or would you try to do them both)? Since aZebra%Equine_Part and aZebra%Striped_Part couldnt both be at the same address as aZebra, the trick for avoiding creating additional code for the specific methods wouldnt always work. Since one can still simulate the effect of additional inheritance by explicitly including components of the superclass and explicitly defining the link between methods, it seems prudent to initially provide only single inheritance in Fortran (but to use a syntax that could be extended to multiple inheritance in the future, should we later desire it). Polymorphism Polymorphism is a concept that is well-defined independently of OOP; it is programming that is independent of specific types, depending only that certain operations are defined on those types. A familiar example is that most sorting algorithms do not depend on whether you are sorting a list of integers, reals, characters, or some user-invented type, only that you can compare them and can change their position in the list. The application of polymorphism to OOP is that one frequently wishes to write code that is polymorphic across the subclasses derived from a particular superclass. For example, one might wish to define a Race procedure that applies to all Equines, so one could Race both Horses and Zebras. The most common way to get polymorphism is to use some kind of template or macro. The procedure is initially written with some kind of placeholder for the type, and this template is then expanded into ordinary procedures for each type desired. There are people who do this in Fortran by providing the entire specification part of each specific version and using INCLUDE to access the common procedure body. The limitation of this approach is that it doesnt provide for mixed collections. In our example, we can create a Race procedure for a collection of Horses or for a collection of Zebras, but it does not conveniently provide a way to use the same template to generate a Race for a collection that includes both Horses and Zebras. Thus, most OOP languages use a different approach. The polymorphic procedure is actually compiled directly, with the placeholders of the previous approach being replaced by dummy arguments or pointers whose type is somehow fuzzy, i.e. capable of being associated with entities of several different types, but with knowledge of which type of entity is currently associated. When an operation is initiated on one of the fuzzy entities, the generic overload rules must be applied at execution time to determine which version of that operation is to be used. Because this dynamic overload resolution is performed separately for each fuzzy entity referenced in the procedure, this provides the flexibility to deal with mixtures of subtypes, such as we have when we want to Race Horses and Zebras together. [N.B. Although the exact type of one of these entities is not known at compile time, it is still strongly typed at execution time, so argument mismatches and other unsafe practices are still caught.] The execution cost of this flexibility is the cost of the generic lookup plus potential lost optimization opportunities comparable to those that occur when you invoke a procedure associated with a dummy procedure. In my opinion, the lack of some facility for doing this run-time resolution is the most serious deficiency of Fortran as a language for object-oriented programming. However, in adding such a facility, we must take care to try to constrain it in such a way that the cost of doing the resolution is minimized. Late Binding Some OOP languages employ dynamic resolution for all procedure calls. This has some benefits in enhancing the reusability of code, but these benefits are not large enough to justify their performance costs in a language like Fortran. Some OOP languages allow the procedures associated with a particular subclass or particular object to change during the course of execution. In those problems where the kind of flexibility is useful, this can be simulated using pointers to procedures stored either in the module that defines the subclass or as a component of objects of that subclass. The fixed procedure associated with a subclass or object can be one that simply invokes the procedure associated with the pointer. Thus, changing the pointer effectively changes the procedure invoked as a result of the run-time resolution. Concurrence At least one of the OOP tutorials I have read insists that one of the requisite properties of an OOP language is concurrence. In this view, the act of one object sending a message to another should not require the first object to wait until the second object finishes processing that message, thus allowing the first object to continue executing concurrently with the second objects processing of the message. It is argued both that this is more consistent with the way objects interact in real life and that this creates a very natural way for object-oriented programs to take advantage of the power of multi-processor systems. This view does not appear to be generally held; I believe we can reasonably omit concurrence now and add it later if there is sufficient demand. From: Kurt W. Hirchert X3J3/96-086 (Page of  NUMPAGES \* MERGEFORMAT 6) Subject: Object-Oriented Programming and Fortran Meeting 137 X3J3/96-086 (Page of  NUMPAGES \* MERGEFORMAT 6)  |HH(FG(HH(d'@ࡱ; SummaryInformation(W. Hirchert'@>>>>>> ? ? ? ?a?b?f?g??????? @uuDc$ e1dRqP~Xar !"$$%2%%%%!&(*~*@+,,|/1_2)7^8 `'`' `' `'`'`'`'`'`'`'`'`'`'`'`'`'`'`'`' `'`'`'`'`'`'`'`'`'`'`'`'`'`'`'`'`'`'`'`' `'`'`'`'`',^8k8V9;;->>>?M?N?????`'`'`'`'`'`'`'`'h3& 33(* 3K&@&Normal ]a c"A@"Default Paragraph Font(@ Line NumberVc @ Footer `' @ Header `'"O"HeadingU^OFirstOBItem0"O" After Examplex(OR(Example x]cOAr2Item O Text]c,O,namesPcOindented`<??'%&'&1 "+7<3;< @!^8?"#/JLSKurt W. Hirchert?APS Drive:Documents and Data:X3J3 stuff:meeting 137:96-086 OOF@g2g2g2d25Z]MTimes New Roman Symbol MArialMNew YorkMPalatino MCourier" d  !+6APS Drive:Applications:Text:Word:Templates:X3J3 paperJThe first paragraph is in style First, to avoid leaving extra white space.Kurt W. HirchertKurt W. Hirchertࡱ;