13 Supporting mechanisms xcept for onecrucial set of mechanisms,we havewsnthe basic ecof object-oriented software construction.The major missing piece is inheritance and all that goes with it.Before moving to that last component of the approach,we should review a few mechanisms that will be important to the writing of actual systems:external routines and the encapsulation of non-O-O software;argument passing;control structures; expressions;string manipulation;input and output. These are technical aspects,not essential to the understanding of the method;but we will need them for some later examples,and they blend well with the fundamental concepts.So even on your first reading you should spend some time getting at least generally familiar with them. 13.1 INTERFACING WITH NON-O-O SOFTWARE So far,we have expressed software elements entirely in the object-oriented notation.But the software field grew up long before object technology became popular,and you will often need to interface your software with non-O-O elements,written in such languages as C,Fortran or Pascal.The notation should support this process. We will first look at the language mechanism,then reflect on its broader significance as a part of the object-oriented software development process. External routines Our object-oriented systems are made of classes,consisting of features,particularly routines,that contain instructions.What is,among these three,the right level of granularity for integrating external software? The construct must be common to both sides;this excludes classes,which exist only in object-oriented languages.(They may,however,be the right level of integration between two different O-O languages.)Instructions are too low-level;a sequence in which two object-oriented instructions bracket a C instruction: Warning:this style !!x.make (clone (a)) is neither supported (struct A)*x =&y;/A piece of C * nor recommended. For purposes of dis- x.display cussion only. would be very hard to understand,validate and maintain
13 Supporting mechanisms Except for one crucial set of mechanisms, we have now seen the basic techniques of object-oriented software construction. The major missing piece is inheritance and all that goes with it. Before moving to that last component of the approach, we should review a few mechanisms that will be important to the writing of actual systems: external routines and the encapsulation of non-O-O software; argument passing; control structures; expressions; string manipulation; input and output. These are technical aspects, not essential to the understanding of the method; but we will need them for some later examples, and they blend well with the fundamental concepts. So even on your first reading you should spend some time getting at least generally familiar with them. 13.1 INTERFACING WITH NON-O-O SOFTWARE So far, we have expressed software elements entirely in the object-oriented notation. But the software field grew up long before object technology became popular, and you will often need to interface your software with non-O-O elements, written in such languages as C, Fortran or Pascal. The notation should support this process. We will first look at the language mechanism, then reflect on its broader significance as a part of the object-oriented software development process. External routines Our object-oriented systems are made of classes, consisting of features, particularly routines, that contain instructions. What is, among these three, the right level of granularity for integrating external software? The construct must be common to both sides; this excludes classes, which exist only in object-oriented languages. (They may, however, be the right level of integration between two different O-O languages.) Instructions are too low-level; a sequence in which two object-oriented instructions bracket a C instruction: !! x ● make (clone (a)) (struct A) *x = &y; /* A piece of C */ x ● display would be very hard to understand, validate and maintain. Warning: this style is neither supported nor recommended. For purposes of discussion only
440 MORE O-O MECHANISMS $13.1 This leaves the feature level,the right one since encapsulating features is compatible with O-O principles:a class is an implementation of a data type protected by information hiding;features are the unit of interaction of the class with the rest of the software;since clients rely on the features'official specification (the short form)independently of their implementation,it does not matter to the outside world whether a feature is internally written in the object-oriented notation or in another language. Hence the notion of external routine.An external routine will have most of the trappings of a normal routine:name,argument list,result type if it is a function, precondition and postcondition if appropriate.Instead of a do clause it will have an ex ternal clause stating the language used for the implementation.Here is an example, extracted from a class describing character files: put (c:CHARACTER)is --Add c to end of file. require write open:open for write external "Cm alias"char write"; ensure one more:count old count +1 end The alias clause is optional,useful only if the name of the external routine,in its language of origin,is different from the name given in the class.This happens for example when the extemal name would not be legal in the object-oriented notation,as here with a name beginning with an underscore (legal in C). Advanced variants The mechanism just described covers most cases and will suffice for the purposes of this book.In practice some refinements are useful: Some external software elements may be macros rather than routines.They will appear to the O-O world as routines,but any call will be expanded in-line.This may be achieved by varying the language name (as in "C:[macro]..."). It is also necessary to permit calls to routines of"Dynamic Link Libraries"(DLL) available on Windows and other platforms.Instead ofbeing a static part ofthe system, a DLL routine is loaded at run time,on the first call.It is even possible to define the routine and library names at run time.DLL support should include both a way to specify the names statically (as in external "C:[dll]...")and a completely dynamic approach using library classes DYNAMIC LIBRARY and DYNAMIC ROUTINE which you can instantiate at run time,to create objects representing dynamically determined libraries and routines. You may also need communication in the reverse direction,letting non-O-O software create objects and call features on them.For example you may want the callback mechanism of a non-O-O graphical toolkit to call certain class features. All these facilities are present in the O-O environment described in the last chapter. Their detailed presentation,however,falls beyond the scope of this discussion
440 MORE O-O MECHANISMS §13.1 This leaves the feature level, the right one since encapsulating features is compatible with O-O principles: a class is an implementation of a data type protected by information hiding; features are the unit of interaction of the class with the rest of the software; since clients rely on the features’ official specification (the short form) independently of their implementation, it does not matter to the outside world whether a feature is internally written in the object-oriented notation or in another language. Hence the notion of external routine. An external routine will have most of the trappings of a normal routine: name, argument list, result type if it is a function, precondition and postcondition if appropriate. Instead of a do clause it will have an external clause stating the language used for the implementation. Here is an example, extracted from a class describing character files: put (c: CHARACTER) is -- Add c to end of file. require write_open: open_for_write external "C" alias "_char_write"; ensure one_more: count = old count + 1 end The alias clause is optional, useful only if the name of the external routine, in its language of origin, is different from the name given in the class. This happens for example when the external name would not be legal in the object-oriented notation, as here with a name beginning with an underscore (legal in C). Advanced variants The mechanism just described covers most cases and will suffice for the purposes of this book. In practice some refinements are useful: • Some external software elements may be macros rather than routines. They will appear to the O-O world as routines, but any call will be expanded in-line. This may be achieved by varying the language name (as in "C:[macro]… "). • It is also necessary to permit calls to routines of “Dynamic Link Libraries” (DLL) available on Windows and other platforms. Instead of being a static part of the system, a DLL routine is loaded at run time, on the first call. It is even possible to define the routine and library names at run time. DLL support should include both a way to specify the names statically (as in external "C:[dll]…") and a completely dynamic approach using library classes DYNAMIC_LIBRARY and DYNAMIC_ROUTINE which you can instantiate at run time, to create objects representing dynamically determined libraries and routines. • You may also need communication in the reverse direction, letting non-O-O software create objects and call features on them. For example you may want the callback mechanism of a non-O-O graphical toolkit to call certain class features. All these facilities are present in the O-O environment described in the last chapter. Their detailed presentation, however, falls beyond the scope of this discussion
$13.1 INTERFACING WITH NON-O-O SOFTWARE 441 Uses of external routines External routines are an integral part of the method,fulfilling the need to combine old software with new.Any software design method emphasizing reusability must allow accessing code written in other languages.It would be hard to convince potential users that reusability begins this minute and that all existing software must be discarded. Openness to the rest of the world is a requirement for most software.This might be termed the Principle of Modesty:authors of new tools should make sure that users can still access previously available facilities. External routines are also necessary to provide access to machine-dependent or operating system capabilities.The file class is a typical example.Another is class ARRAY, whose interface was presented in earlier chapters but whose implementation will rely on external routines:the creation procedure make use a memory allocation routine,the access function item will use an external mechanism for fast access to array elements,and so on “Polite society”is This technique ensures a clean interface between the object-oriented world and other not classless. approaches.To clients,an external routine is just a routine.In the example,the C routine char write has been elevated to the status of a feature of a class,complete with precondition and postcondition,and the standard name put.So even facilities which internally rely on non-O-O mechanisms get repackaged in data abstractions;the rest ofthe object-oriented software will see them as legitimate members of the group,their lowly origins never to be mentioned in polite society. Object-oriented re-architecturing The notion of external routine fits well with the rest of the approach.The method's core contribution is architectural:object technology tells us how to devise the structure of our systems to ensure extendibility,reliability and reusability.It also tells us how to fill that structure,but what fundamentally determines whether a system is object-oriented is its modular organization.It is often appropriate,then,to use an O-O architecture-what is sometimes called a wrapper-around interal elements that are not all O-O. One extreme but not altogether absurd way to use the notation would rely solely on external routines,written in some other language,for all actual computation.Object technology would then serve as a pure packaging tool,using its powerful encapsulation mechanisms:classes,assertions,information hiding,client,inheritance In general there is no reason to go that far,since the notation is perfectly adequate to express computations of all kinds and execute them as efficiently as older languages such as Fortran or C.But object-oriented encapsulation ofexternal software is useful in several cases.We have seen one of them:providing access to platform-specific operations. Another is to address a problem that faces many organizations:managing so-called legacy sofnware.During the sixties,seventies and eighties,companies have accumulated a legacy
§13.1 INTERFACING WITH NON-O-O SOFTWARE 441 Uses of external routines External routines are an integral part of the method, fulfilling the need to combine old software with new. Any software design method emphasizing reusability must allow accessing code written in other languages. It would be hard to convince potential users that reusability begins this minute and that all existing software must be discarded. Openness to the rest of the world is a requirement for most software. This might be termed the Principle of Modesty: authors of new tools should make sure that users can still access previously available facilities. External routines are also necessary to provide access to machine-dependent or operating system capabilities. The file class is a typical example. Another is class ARRAY, whose interface was presented in earlier chapters but whose implementation will rely on external routines: the creation procedure make use a memory allocation routine, the access function item will use an external mechanism for fast access to array elements, and so on. This technique ensures a clean interface between the object-oriented world and other approaches. To clients, an external routine is just a routine. In the example, the C routine _char_write has been elevated to the status of a feature of a class, complete with precondition and postcondition, and the standard name put. So even facilities which internally rely on non-O-O mechanisms get repackaged in data abstractions; the rest of the object-oriented software will see them as legitimate members of the group, their lowly origins never to be mentioned in polite society. Object-oriented re-architecturing The notion of external routine fits well with the rest of the approach. The method’s core contribution is architectural: object technology tells us how to devise the structure of our systems to ensure extendibility, reliability and reusability. It also tells us how to fill that structure, but what fundamentally determines whether a system is object-oriented is its modular organization. It is often appropriate, then, to use an O-O architecture — what is sometimes called a wrapper — around internal elements that are not all O-O. One extreme but not altogether absurd way to use the notation would rely solely on external routines, written in some other language, for all actual computation. Object technology would then serve as a pure packaging tool, using its powerful encapsulation mechanisms: classes, assertions, information hiding, client, inheritance. In general there is no reason to go that far, since the notation is perfectly adequate to express computations of all kinds and execute them as efficiently as older languages such as Fortran or C. But object-oriented encapsulation of external software is useful in several cases. We have seen one of them: providing access to platform-specific operations. Another is to address a problem that faces many organizations: managing so-called legacy software. During the sixties, seventies and eighties, companies have accumulated a legacy “Polite society” is not classless
442 MORE O-O MECHANISMS $13.1 of Cobol,Fortran,PL/I and C code,which is becoming harder and harder to maintain,and not just because the original developers are gone or going.Object technology offers an opportunity to re-engineer such systems by re-architecturing them,without having to rewrite them completely Think of this process as the reverse of turkey stuffing:instead of keeping the structure and changing the internals,you keep the entrails and replace the skeleton,as if repackaging the content ofa turkey into the bones of a zebra or a mouse.It must be noted, however,that such non-software applications of the idea appear neither useful nor appetizing. This technique,which we may call object-oriented re-architecturing,offers an interesting solution for preserving the value of existing software assets while readying them for future extension and evolution. It will only work,however,under specific conditions: You must be able to identify good abstractions in the existing software.Since you are not dealing with object-oriented software,they will typically be function abstractions,not data abstractions;but that is normal:it is your task to find the underlying data abstractions and repackage the old software's routines into the new software's classes.If you cannot identify proper abstractions already packaged in routines,you are out of luck,and no amount of object-oriented re-architecturing attempts will help. The legacy software must be of good quality.Re-architectured junk is still junk- possibly worse than the original,in fact,as the junkiness will be hidden under more layers of abstraction. These two requirements are partly the same,since quality in software,O-O or not,is largely determined by quality of structure. When they are satisfied,it is possible to use the external mechanism to build some very interesting object-oriented software based on earlier efforts.Here are two examples, both part of the environment described in the last chapter. The Vision library provides portable graphics and user interface mechanisms,On these libraries enabling developers to write graphical applications that will run on many different see“PORTABIL- platforms,with the native look-and-feel,for the price of a recompilation.Internally, ITY AND PLAT- FORM it relies on the native mechanisms,used through external routines.More precisely, ADAPTATION”, its lower level-WEL for Windows,MEL for Motif,PEL for OS/2 Presentation Manager-encapsulates the mechanisms of the corresponding platforms.WEL, MEL,PEL and consorts are also usable directly,providing developers who do not care about portability with object-oriented encapsulations of the Windows,Motif and Presentation Manager Application Programming Interfaces. Another library,Math,provides an extensive set of facilities for numerical computation in such areas as probability,statistics,numerical integration,linear and non-linear equations,ordinary differential equations,eigenproblems,fitting and interpolation,orthogonal factorizations,linear least squares,optimization
442 MORE O-O MECHANISMS §13.1 of Cobol, Fortran, PL/I and C code, which is becoming harder and harder to maintain, and not just because the original developers are gone or going. Object technology offers an opportunity to re-engineer such systems by re-architecturing them, without having to rewrite them completely. Think of this process as the reverse of turkey stuffing: instead of keeping the structure and changing the internals, you keep the entrails and replace the skeleton, as if repackaging the content of a turkey into the bones of a zebra or a mouse. It must be noted, however, that such non-software applications of the idea appear neither useful nor appetizing. This technique, which we may call object-oriented re-architecturing, offers an interesting solution for preserving the value of existing software assets while readying them for future extension and evolution. It will only work, however, under specific conditions: • You must be able to identify good abstractions in the existing software. Since you are not dealing with object-oriented software, they will typically be function abstractions, not data abstractions; but that is normal: it is your task to find the underlying data abstractions and repackage the old software’s routines into the new software’s classes. If you cannot identify proper abstractions already packaged in routines, you are out of luck, and no amount of object-oriented re-architecturing attempts will help. • The legacy software must be of good quality. Re-architectured junk is still junk — possibly worse than the original, in fact, as the junkiness will be hidden under more layers of abstraction. These two requirements are partly the same, since quality in software, O-O or not, is largely determined by quality of structure. When they are satisfied, it is possible to use the external mechanism to build some very interesting object-oriented software based on earlier efforts. Here are two examples, both part of the environment described in the last chapter. • The Vision library provides portable graphics and user interface mechanisms, enabling developers to write graphical applications that will run on many different platforms, with the native look-and-feel, for the price of a recompilation. Internally, it relies on the native mechanisms, used through external routines. More precisely, its lower level — WEL for Windows, MEL for Motif, PEL for OS/2 Presentation Manager — encapsulates the mechanisms of the corresponding platforms. WEL, MEL, PEL and consorts are also usable directly, providing developers who do not care about portability with object-oriented encapsulations of the Windows, Motif and Presentation Manager Application Programming Interfaces. • Another library, Math, provides an extensive set of facilities for numerical computation in such areas as probability, statistics, numerical integration, linear and non-linear equations, ordinary differential equations, eigenproblems, fitting and interpolation, orthogonal factorizations, linear least squares, optimization, On these libraries see “PORTABILITY AND PLATFORM ADAPTATION
$13.1 INTERFACING WITH NON-O-O SOFTWARE 443 special functions,Fast Fourier Transforms and time series analysis.Internally,it is based on a commercial subroutine library,the NAG library from Nag Ltd.of Oxford,but it provides a completely object-oriented interface to its users.The library hides the underlying routines and instead is organized around such abstract concepts as integrator,matrix,discrete function,exponential distribution and many others;each describes "objects"readily understandable to a mathematician. physicist or economist,and is represented in the library by a class:INTEGRATOR, BASIC MATRIX,DISCRETE FUNCTION,EXPONENTIAL DISTRIBUTION.The result builds on the quality of the external routines-NAG is the product of hundreds of person-years of devising and implementing numerical algorithms- and adds the benefits of O-0 ideas:classes,information hiding,multiple inheritance,assertions,systematic error handling through exceptions,simple routines with short argument lists,consistent naming conventions. These examples are typical of how one can combine the best of traditional software and object technology. The compatibility issue:hybrid software or hybrid languages? Few people would theoretically disagree with the principle of modesty and deny the need for some integration mechanism between O-O developments and older software.The matter becomes more controversial when it comes to deciding on the level of integration. See chapter 35. A whole set of languages-the best known are Objective-C,C++,Java,Object Pascal and Ada 95-have taken the approach of adding O-O constructs to an existing non-O-O language(respectively C in the first three cases,Pascal and Ada).Known as hybrid languages,they are discussed in varying degree of detail in a later chapter. The integration technique described above,rely ing on external routines and object- oriented re-architecturing,follows from a different principle:that the need for sofiware compatibility does not mean that we should burden the language with mechanisms that may be at odds with the principles of object technology.In particular: A hybrid adds a new language level to the weight of an existing language such as C. The result can be quite complex,limiting one of the principal attractions of object technology-the essential simplicity of the ideas. Beginners as a result often have trouble mastering a hybrid language,since they do not clearly see what is truly O-O and what comes from the legacy. Some of the older mechanisms may be incompatible with at least some aspects of object-oriented ideas.We have seen how the type concepts inherited from C make it hard to equip C++environments with garbage collection,even though automatic memory management is part of the appeal of object technology.There are many other examples of clashes between the C or Pascal type system and the O-O view
§13.1 INTERFACING WITH NON-O-O SOFTWARE 443 special functions, Fast Fourier Transforms and time series analysis. Internally, it is based on a commercial subroutine library, the NAG library from Nag Ltd. of Oxford, but it provides a completely object-oriented interface to its users. The library hides the underlying routines and instead is organized around such abstract concepts as integrator, matrix, discrete function, exponential distribution and many others; each describes “objects” readily understandable to a mathematician, physicist or economist, and is represented in the library by a class: INTEGRATOR, BASIC_MATRIX, DISCRETE_FUNCTION, EXPONENTIAL_DISTRIBUTION. The result builds on the quality of the external routines — NAG is the product of hundreds of person-years of devising and implementing numerical algorithms — and adds the benefits of O-O ideas: classes, information hiding, multiple inheritance, assertions, systematic error handling through exceptions, simple routines with short argument lists, consistent naming conventions. These examples are typical of how one can combine the best of traditional software and object technology. The compatibility issue: hybrid software or hybrid languages? Few people would theoretically disagree with the principle of modesty and deny the need for some integration mechanism between O-O developments and older software. The matter becomes more controversial when it comes to deciding on the level of integration. A whole set of languages — the best known are Objective-C, C++, Java, Object Pascal and Ada 95 — have taken the approach of adding O-O constructs to an existing non-O-O language (respectively C in the first three cases, Pascal and Ada). Known as hybrid languages, they are discussed in varying degree of detail in a later chapter. The integration technique described above, relying on external routines and objectoriented re-architecturing, follows from a different principle: that the need for software compatibility does not mean that we should burden the language with mechanisms that may be at odds with the principles of object technology. In particular: • A hybrid adds a new language level to the weight of an existing language such as C. The result can be quite complex, limiting one of the principal attractions of object technology — the essential simplicity of the ideas. • Beginners as a result often have trouble mastering a hybrid language, since they do not clearly see what is truly O-O and what comes from the legacy. • Some of the older mechanisms may be incompatible with at least some aspects of object-oriented ideas. We have seen how the type concepts inherited from C make it hard to equip C++ environments with garbage collection, even though automatic memory management is part of the appeal of object technology. There are many other examples of clashes between the C or Pascal type system and the O-O view. See chapter 35
444 MORE O-O MECHANISMS $13.2 The non-O-O mechanisms are still present,often in apparent competition with their higher-level object-oriented counterparts.For example C++offers,along with dynamic binding,the ability to choose a function at run time through arithmetic on function pointers.This is disconcerting for the non-expert who lacks guidance on which approach to choose in a particular case.The resulting software,although compiled by an O-O environment,is still,deep-down,C code,and does not yield the expected quality and productivity benefits-giving object technology a bad name through no fault of its own. If the aim is to obtain the best possible software process and products,compromising at the language level does not seem the right approach.Interfacing object-oriented tools and techniques with previous achievements is not the same thing as mixing widely different levels of technology. With the usual precautions about attaching too much weight to a metaphor,we can think of the precedent of electronics.It is definitely useful to combine different technology levels in a single system,as in an audio amplifier which still includes a few diodes together with transistors and integrated circuits.But the levels remain separate:there is little use for a basic component that would be half-diode,half-transistor. O-O development should provide compatibility with software built with other approaches,but not at the expense of the method's power and integrity.This is what the external mechanism achieves:separate worlds,each with its own consistency and benefits,and clear interfaces between these worlds 13.2 ARGUMENT PASSING One aspect of the notation may require some clarification:what may happen to values passed as arguments to routines? Consider a routine call of the form r (al a2....,an) corresponding to a routine r(xrTx2T,xmTm)is… where the routine could be a function as well as a procedure,and the call could be qualified,as in b.r(...).The expressions aj,a2,...,a are called actual arguments,and the x are called formal arguments.(Recall that we reserve the term "parameter"for generic type parameters.) The relevant questions are:what is the correspondence between actual and formal arguments?What operations are permitted on formal arguments?What effect will they have on the corresponding actuals?For all three we should stick to simple and safe rules. We already know the answer to the first question:the effect of actual-formal argument association is the same as that of a corresponding assignment.Both operations are called attachments.For the above call we can consider that the routine's execution starts by executing instructions informally equivalent to the assignments
444 MORE O-O MECHANISMS §13.2 • The non-O-O mechanisms are still present, often in apparent competition with their higher-level object-oriented counterparts. For example C++ offers, along with dynamic binding, the ability to choose a function at run time through arithmetic on function pointers. This is disconcerting for the non-expert who lacks guidance on which approach to choose in a particular case. The resulting software, although compiled by an O-O environment, is still, deep-down, C code, and does not yield the expected quality and productivity benefits — giving object technology a bad name through no fault of its own. If the aim is to obtain the best possible software process and products, compromising at the language level does not seem the right approach. Interfacing object-oriented tools and techniques with previous achievements is not the same thing as mixing widely different levels of technology. With the usual precautions about attaching too much weight to a metaphor, we can think of the precedent of electronics. It is definitely useful to combine different technology levels in a single system, as in an audio amplifier which still includes a few diodes together with transistors and integrated circuits. But the levels remain separate: there is little use for a basic component that would be half-diode, half-transistor. O-O development should provide compatibility with software built with other approaches, but not at the expense of the method’s power and integrity. This is what the external mechanism achieves: separate worlds, each with its own consistency and benefits, and clear interfaces between these worlds. 13.2 ARGUMENT PASSING One aspect of the notation may require some clarification: what may happen to values passed as arguments to routines? Consider a routine call of the form r (a1, a2, …, an) corresponding to a routine r (x1: T1, x2: T2, …, xn: Tn) is … where the routine could be a function as well as a procedure, and the call could be qualified, as in b ● r (…). The expressions a1, a2, …, an are called actual arguments, and the xi are called formal arguments. (Recall that we reserve the term “parameter” for generic type parameters.) The relevant questions are: what is the correspondence between actual and formal arguments? What operations are permitted on formal arguments? What effect will they have on the corresponding actuals? For all three we should stick to simple and safe rules. We already know the answer to the first question: the effect of actual-formal argument association is the same as that of a corresponding assignment. Both operations are called attachments. For the above call we can consider that the routine’s execution starts by executing instructions informally equivalent to the assignments
$13.2 ARGUMENT PASSING 445 x1=a5X2=a2…xm=am On the second question:within the routine body,any formal argumentx is protected. The routine may not apply to it any direct modification,such as: An assignment to x,of the formx=... A creation instruction with x as its target:!x.make (... Readers familiar with the passing mechanism known as call by value will note that the restriction is harsher here:with call by value,formals are initialized to actuals but may then be the target of arbitrary operations. “ATTACHMENT: The answer to the third question-what can the routine actually do to the actuals? REFERENCE AND -follows from the use of attachment to define the semantics ofactual-formal association VALUE SEMAN- TlCS”,&.&pag Attachment means copying either a reference or an object.As you will remember from the 261,in particular discussion of attachment,this depends on whether the types involved are expanded: table on page 264. For reference types (the more common case),argument passing will copy a reference,either void or attached to an object. For expanded types(which include in particular the basic types:INTEGER,REAL and the like),argument passing will actually copy an object. In the first case,the prohibition of direct modification operations means that you cannot modify the reference through reattachment or creation;but if the reference is not void you can modify the attached object through appropriate routines. Permissible The routine may not change this operations on a reference (e.g. reattach it to reference another object) argument The routine may change fields of this object (through calls to other Ifx,is one of the formal arguments to routine r,the body of the routine could contain a call of the form xp(.) where p is a procedure applicable tox,,meaning a procedure declared in the base class of x's type T.This routine may modify the fields of the object attached tox,at execution time,which is the object attached to the corresponding actual argument a
§13.2 ARGUMENT PASSING 445 x1 := a1; x2 := a2; … xn := an On the second question: within the routine body, any formal argument x is protected. The routine may not apply to it any direct modification, such as: • An assignment to x, of the form x := … • A creation instruction with x as its target: !! x ● make (…) Readers familiar with the passing mechanism known as call by value will note that the restriction is harsher here: with call by value, formals are initialized to actuals but may then be the target of arbitrary operations. The answer to the third question — what can the routine actually do to the actuals? — follows from the use of attachment to define the semantics of actual-formal association Attachment means copying either a reference or an object. As you will remember from the discussion of attachment, this depends on whether the types involved are expanded: • For reference types (the more common case), argument passing will copy a reference, either void or attached to an object. • For expanded types (which include in particular the basic types: INTEGER, REAL and the like), argument passing will actually copy an object. In the first case, the prohibition of direct modification operations means that you cannot modify the reference through reattachment or creation; but if the reference is not void you can modify the attached object through appropriate routines. If xi is one of the formal arguments to routine r, the body of the routine could contain a call of the form xi ● p (…) where p is a procedure applicable to xi , meaning a procedure declared in the base class of xi ’s type Ti . This routine may modify the fields of the object attached to xi at execution time, which is the object attached to the corresponding actual argument ai . “ATTACHMENT: REFERENCE AND VALUE SEMANTICS”, 8.8, page 261, in particular table on page 264. Permissible operations on a reference argument xi The routine may not change this reference (e.g. reattach it to another object) O1 The routine may change fields of this object (through calls to other
446 MORE O-O MECHANISMS $13.2 So although a call g(a)can never change the value of a-the corresponding object if a is expanded,the reference otherwise-it can,in the reference case,change the attached object. There are many reasons for not permitting routines to modify their arguments directly.One of the most striking is the Conflicting Assignments To Actual trick.Assume a language that permits assignments to arguments,and a procedure dont I look innocuous (a,b:INTEGER)is WARNING:invalid --But do not trust me too much. routine text.For pur- poses of illustration do only. a=0:b=1 end Then consider the call dont I look innocuous (x,x)for some entity x.What is the value ofx on return:0 or 1?The answer depends on how the compiler implements formal- to-actual update on routine exit.This has fooled more than a few Fortran programmers, among others. Permitting argument-modifying routines would also force us to impose restrictions On constant attrib- on actual arguments:the actual corresponding to a modifiable formal must be an element utes see chapter 18. that can change its value(a writable entity);this allows variable attributes,but not constant attributes,Current,or general expressions such as a +b.By precluding argument- modifying routines we can avoid imposing such restrictions and accept any expression as actual argument As a consequence of these rules,there are only three ways to modify the value of a reference x:through a creation instruction !x...;through an assignment x:=y;and through a variant of assignment,assignment attempt x ?=y,studied in a later chapter. Passingx as actual argument to a routine will never modify x. This also means that a routine returns at most one result:none if it is a procedure;the official result(represented in the routine's body by the entity Resulr)if it is a function.To achieve the effect of multiple results,you can either: Use a function that returns an object with several fields (or more commonly a reference to such an object). Use a procedure that sets several fields of an object,corresponding to attributes that the client may then query. The first technique is appropriate when the result is truly made of several See chapter 23,espe- components;a function may not for example return two values corresponding to the title cially"The aposteri- and publication year of a book,but it may return a single value of type BOOK,with"page 800. attributes title and publication year.The second technique is applicable for a routine that, besides its principal job,sets some status indicators.We will study it,as well as the more general question of side effects,in the discussion of module design principles
446 MORE O-O MECHANISMS §13.2 So although a call q (a) can never change the value of a — the corresponding object if a is expanded, the reference otherwise — it can, in the reference case, change the attached object. There are many reasons for not permitting routines to modify their arguments directly. One of the most striking is the Conflicting Assignments To Actual trick. Assume a language that permits assignments to arguments, and a procedure dont_I_look_innocuous (a, b: INTEGER) is -- But do not trust me too much. do a := 0; b := 1 end Then consider the call dont_I_look_innocuous (x, x) for some entity x. What is the value of x on return: 0 or 1? The answer depends on how the compiler implements formalto-actual update on routine exit. This has fooled more than a few Fortran programmers, among others. Permitting argument-modifying routines would also force us to impose restrictions on actual arguments: the actual corresponding to a modifiable formal must be an element that can change its value (a writable entity); this allows variable attributes, but not constant attributes, Current, or general expressions such as a + b. By precluding argumentmodifying routines we can avoid imposing such restrictions and accept any expression as actual argument. As a consequence of these rules, there are only three ways to modify the value of a reference x: through a creation instruction !! x…; through an assignment x := y; and through a variant of assignment, assignment attempt x ?= y, studied in a later chapter. Passing x as actual argument to a routine will never modify x. This also means that a routine returns at most one result: none if it is a procedure; the official result (represented in the routine’s body by the entity Result) if it is a function. To achieve the effect of multiple results, you can either: • Use a function that returns an object with several fields (or more commonly a reference to such an object). • Use a procedure that sets several fields of an object, corresponding to attributes that the client may then query. The first technique is appropriate when the result is truly made of several components; a function may not for example return two values corresponding to the title and publication year of a book, but it may return a single value of type BOOK, with attributes title and publication_ year. The second technique is applicable for a routine that, besides its principal job, sets some status indicators. We will study it, as well as the more general question of side effects, in the discussion of module design principles. WARNING: invalid routine text. For purposes of illustration only. On constant attributes see chapter 18. See chapter 23, especially “The a posteriori scheme”, page 800
$13.3 INSTRUCTIONS 447 13.3 INSTRUCTIONS The object-oriented notation developed in this book is imperative:we specify computations through commands,also called instructions.(The word "statement"is commonly used in this sense but we will steadfastly avoid it since it is misleading:a statement is an expression of facts,not a command.) Except for some specific properties of loops,intended to make their verification easier,instructions will look familiar to anyone who has had some experience with a modern language of the Algol line such as Pascal,Ada or Modula,or even just with C or a derivative.They include:Procedure call;Assignment;Creation;Conditional; Multi branch;Loop;Check;Debug;Retry;Assignment attempt. Procedure call A routine call involves a routine,possibly with actual arguments.In a call instruction,the routine must be a procedure;if it is a function,the call is an expression.Although for the moment we are interested in instructions,the following rules apply to both cases. A call is either qualified or unqualified.An unqualified call to a routine of the enclosing class uses the current instance as target;it appears under the form (without arguments),or r(,y,) (with arguments) A qualified call explicitly names its target,denoted by an expression:if a is an expression of a certain type,C is the base class of that type,and q is one of the routines of C,then a qualified call is of the form a.q.Again,g may be followed by a list of actual arguments;a may be an unqualified function call with arguments,as in p(m).q(n)where the target is p(m).You may also use as target a more complex expression,provided you enclose it in parentheses,as in (vecforl vector2).count. Multidot qualified calls,of the form a.are also permitted,where a as well as any of the q,may include a list of actual arguments. Export controls apply to qualified calls.Recall that a feature declared in a class B is availa ble to a class 4 if the feature clause declaring f begins with feature(without further qualification)or feature Y,Y,..where one of X,Y,...is 4 or an ancestor of 4.Then: Qualified Call rule A qualified call of the form b.qq2.....appearing in a class C is valid only if it satisfies the following conditions: RI.The feature appearing after the first dot,q,must be available to C. R2.In a multidot call,every feature after the second dot,that is to say every qi for i>1,must also be available to C. To understand the reason for the second rule,note that a.g.r.s is a shorthand for
§13.3 INSTRUCTIONS 447 13.3 INSTRUCTIONS The object-oriented notation developed in this book is imperative: we specify computations through commands, also called instructions. (The word “statement” is commonly used in this sense but we will steadfastly avoid it since it is misleading: a statement is an expression of facts, not a command.) Except for some specific properties of loops, intended to make their verification easier, instructions will look familiar to anyone who has had some experience with a modern language of the Algol line such as Pascal, Ada or Modula, or even just with C or a derivative. They include: Procedure call; Assignment; Creation; Conditional; Multi_branch; Loop; Check; Debug; Retry; Assignment attempt. Procedure call A routine call involves a routine, possibly with actual arguments. In a call instruction, the routine must be a procedure; if it is a function, the call is an expression. Although for the moment we are interested in instructions, the following rules apply to both cases. A call is either qualified or unqualified. An unqualified call to a routine of the enclosing class uses the current instance as target; it appears under the form r (without arguments), or r (x, y, …) (with arguments) A qualified call explicitly names its target, denoted by an expression: if a is an expression of a certain type, C is the base class of that type, and q is one of the routines of C, then a qualified call is of the form a ● q. Again, q may be followed by a list of actual arguments; a may be an unqualified function call with arguments, as in p (m) ● q (n) where the target is p (m). You may also use as target a more complex expression, provided you enclose it in parentheses, as in (vector1 + vector2) ● count. Multidot qualified calls, of the form a ● q1 ● q2 … ● qn are also permitted, where a as well as any of the qi may include a list of actual arguments. Export controls apply to qualified calls. Recall that a feature f declared in a class B is available to a class A if the feature clause declaring f begins with feature (without further qualification) or feature {X, Y, …} where one of X, Y, … is A or an ancestor of A. Then: To understand the reason for the second rule, note that a ● q ● r ● s is a shorthand for Qualified Call rule A qualified call of the form b ● q1 ● q2 …. ● qn appearing in a class C is valid only if it satisfies the following conditions: R1 • The feature appearing after the first dot, q1, must be available to C. R2 • In a multidot call, every feature after the second dot, that is to say every qi for i > 1, must also be available to C
448 MORE O-O MECHANISMS $13.3 b:=a.q.c:=b.r;c.s which is only valid if g,r and s are all available to C,the class where this fragment appears. Whether r is available to the base class of g's type,and s available to the base class ofr's type,is irrelevant. As you will remember it is also possible to express calls in infix or prefix form;an See“Operator fea- expression such as a+b is a different syntax for a call that would otherwise be written tures",page 187. a.plus (b).The same validity rules apply to such expressions as to the dot form. Assignment The assignment instruction is written x=e wherex is a writable entity and e an expression of compatible type.A writable entity is either: A non-constant attribute of the enclosing class. A local entity of the enclosing routine,including Result for a function. Other,non-writable kinds of entity include constant attributes (introduced in Chapter /8 dis- declarations such as Zero:INTEGER is 0)and formal arguments of a routine-to which, cusses constant attributes. as we just saw,the routine may not assign a new value. Creation instruction See“The creation The creation instruction was studied in an earlier chapter in its two forms:without a instruction,page 232 and"CREATION creation procedure,as in!!x,and with a creation procedure,as in !!xp(...).In both PROCEDURES". cases,x must be a writable entity. 8.4.page 236.A vari- ant will be seen in Conditional “Polymorphic cre. ation",page 479. A conditional instruction serves to specify that different forms of processing should be applied depending on certain conditions.The basic form is if boolean expression then instruction,instruction;... else instruction;instruction,.. end where each branch may have an arbitrary number of instructions(possibly none). This will execute the instructions in the first branch if the boolean expression evaluates to true,and those in the second branch otherwise.You may omit the else part if the second instruction list is empty,giving: if boolean expression then instruction;instruction;.. end
448 MORE O-O MECHANISMS §13.3 b := a ● q; c := b ● r; c ● s which is only valid if q, r and s are all available to C, the class where this fragment appears. Whether r is available to the base class of q’s type, and s available to the base class of r’s type, is irrelevant. As you will remember it is also possible to express calls in infix or prefix form; an expression such as a + b is a different syntax for a call that would otherwise be written a ● plus (b). The same validity rules apply to such expressions as to the dot form. Assignment The assignment instruction is written x := e where x is a writable entity and e an expression of compatible type. A writable entity is either: • A non-constant attribute of the enclosing class. • A local entity of the enclosing routine, including Result for a function. Other, non-writable kinds of entity include constant attributes (introduced in declarations such as Zero: INTEGER is 0) and formal arguments of a routine — to which, as we just saw, the routine may not assign a new value. Creation instruction The creation instruction was studied in an earlier chapter in its two forms: without a creation procedure, as in !! x, and with a creation procedure, as in !! x ● p (…). In both cases, x must be a writable entity. Conditional A conditional instruction serves to specify that different forms of processing should be applied depending on certain conditions. The basic form is if boolean_expression then instruction; instruction; … else instruction; instruction; … end where each branch may have an arbitrary number of instructions (possibly none). This will execute the instructions in the first branch if the boolean_expression evaluates to true, and those in the second branch otherwise. You may omit the else part if the second instruction list is empty, giving: if boolean_expression then instruction; instruction; … end See “Operator features”, page 187. Chapter 18 discusses constant attributes. See “The creation instruction”, page 232 and “CREATION PROCEDURES”, 8.4, page 236. A variant will be seen in “Polymorphic creation”, page 479