36 An object-oriented environment ate into Beethoven'sChoral Symphony,a baritone breaks the stream of astounding but until then purely instrumental sounds to awake us to something even grander: O my friends!No more of these tunes! Let us strike up instead Some more pleasant and friendly songs. After reviewing in the preceding chapters some of the common approaches to O-O development,we should similarly end with a perhaps more modern and comprehensive approach(with no intended disparagement of the others;after all the Ninth's first three movements,before it goes vocal,already were pretty decent stuff.) The diagram is on This chapter presents an environment(ISE's)that relies on the principles developed page 1149. in the rest of this book,and makes them available concretely to O-O software developers. A complete diagram ofthe environment appears later in this chapter;some of the principal components are included for trial purposes in the CD-ROM attached to this book The purpose of this presentation is to put the final touch to our study of object technology by showing how environment support can make the concepts convenient to use in practice.A caveat:nothing in this discussion suggests that the environment discussed below is perfect (in fact,it is still evolving).It is only one example of a modem O-O environment;others-such as Borland's Delphi to name just one-have met wide and deserved success.But we need to explore one environment in some depth to understand the connection between the method's principles and their day-to-day application by a developer sitting at a terminal.Many of the concepts will,I hope,be useful to readers using other tools. 36.1 COMPONENTS The environment combines the following elements: An underlying method:the object-oriented method,as described in this book A language,the notation presented in this book,for analysis,design and implementation. A set of tools for exploiting the method and the language:compiling,browsing, documenting,designing. Libraries of reusable software components. The next sections sketch these various elements,except for the first which,of course, has been the subject of the rest of this book
36 An object-oriented environment Late into Beethoven’s Choral Symphony, a baritone breaks the stream of astounding but until then purely instrumental sounds to awake us to something even grander: O my friends! No more of these tunes! Let us strike up instead Some more pleasant and friendly songs. After reviewing in the preceding chapters some of the common approaches to O-O development, we should similarly end with a perhaps more modern and comprehensive approach (with no intended disparagement of the others; after all the Ninth’s first three movements, before it goes vocal, already were pretty decent stuff.) This chapter presents an environment (ISE’s) that relies on the principles developed in the rest of this book, and makes them available concretely to O-O software developers. A complete diagram of the environment appears later in this chapter; some of the principal components are included for trial purposes in the CD-ROM attached to this book. The purpose of this presentation is to put the final touch to our study of object technology by showing how environment support can make the concepts convenient to use in practice. A caveat: nothing in this discussion suggests that the environment discussed below is perfect (in fact, it is still evolving). It is only one example of a modern O-O environment; others — such as Borland’s Delphi to name just one — have met wide and deserved success. But we need to explore one environment in some depth to understand the connection between the method’s principles and their day-to-day application by a developer sitting at a terminal. Many of the concepts will, I hope, be useful to readers using other tools. 36.1 COMPONENTS The environment combines the following elements: • An underlying method: the object-oriented method, as described in this book. • A language, the notation presented in this book, for analysis, design and implementation. • A set of tools for exploiting the method and the language: compiling, browsing, documenting, designing. • Libraries of reusable software components. The next sections sketch these various elements, except for the first which, of course, has been the subject of the rest of this book. The diagram is on page 1149
1144 AN OBJECT-ORIENTED ENVIRONMENT $36.2 36.2 THE LANGUAGE The language is the notation that we have devised in part C and applied throughout the book.We have essentially seen all of it;the only exceptions are a few technical details such as how to represent special characters. Evolution The first implementation of the language dates back to late 1986.Only one significant revision has occurred since then(in 1990);it did not change any fundamental concepts but simplified the expression of some of them.Since then there has been a continuous attempt at clarification,simplification and cleanup,affecting only details,and bringing two recent extensions:the concurrency mechanism of chapter 30(concretely,the addition of a single keyword,separate)and the Precursor construct to facilitate redefinition.The stability of the language,a rare phenomenon in this field,has been a major benefit to users. Openness Although a full-fledged programming language,the notation is also designed to serve as a wrapping mechanism for components that may be written in other languages.The mechanism for including external elements-the external clause-was described in an earlier chapter.It is also possible,through the Cecil library,for external software to use the O-O mechanisms:create instances of classes,and call features on these objects, through dynamic binding(but of course with only limited static type checking). Of particular interest are the C and C++interfaces.For C++,a tool called Legacy++ is available to produce,out of an existing C++class,a "wrapper"class that will automatically include the encapsulation of all the exported features of the original.This is particularly useful to developers whose organizations may have used C++as their first stop on the road to object orientation in the late eighties or early nineties,and now want to move on to a more complete and systematic form of the technology-without sacrificing their investment.Legacy++smoothes the transition. 36.3 THE COMPILATION TECHNOLOGY The first task of the environment is,of course,to let us execute our software. Compilation challenges Developed over many years and bootstrapped through several iterations,the compilation technology is an answer to a set of challenges: C1.The efficiency of the generated code must be excellent,comparable to what developers could obtain by using a classical language suchas C.There is no reason to pay a significant performance price for O-O techniques. C2.The recompilation time after a change must be short.More precisely,it should be proportional to the size of the change,not to the size of the entire system.The crucial compilation concern,for developers working on a possibly large system,is the need to perform changes and see the results immediately
1144 AN OBJECT-ORIENTED ENVIRONMENT §36.2 36.2 THE LANGUAGE The language is the notation that we have devised in part C and applied throughout the book. We have essentially seen all of it; the only exceptions are a few technical details such as how to represent special characters. Evolution The first implementation of the language dates back to late 1986. Only one significant revision has occurred since then (in 1990); it did not change any fundamental concepts but simplified the expression of some of them. Since then there has been a continuous attempt at clarification, simplification and cleanup, affecting only details, and bringing two recent extensions: the concurrency mechanism of chapter 30 (concretely, the addition of a single keyword, separate) and the Precursor construct to facilitate redefinition. The stability of the language, a rare phenomenon in this field, has been a major benefit to users. Openness Although a full-fledged programming language, the notation is also designed to serve as a wrapping mechanism for components that may be written in other languages. The mechanism for including external elements — the external clause — was described in an earlier chapter. It is also possible, through the Cecil library, for external software to use the O-O mechanisms: create instances of classes, and call features on these objects, through dynamic binding (but of course with only limited static type checking). Of particular interest are the C and C++ interfaces. For C++, a tool called Legacy++ is available to produce, out of an existing C++ class, a “wrapper” class that will automatically include the encapsulation of all the exported features of the original. This is particularly useful to developers whose organizations may have used C++ as their first stop on the road to object orientation in the late eighties or early nineties, and now want to move on to a more complete and systematic form of the technology — without sacrificing their investment. Legacy++ smoothes the transition. 36.3 THE COMPILATION TECHNOLOGY The first task of the environment is, of course, to let us execute our software. Compilation challenges Developed over many years and bootstrapped through several iterations, the compilation technology is an answer to a set of challenges: C1 • The efficiency of the generated code must be excellent, comparable to what developers could obtain by using a classical language such as C. There is no reason to pay a significant performance price for O-O techniques. C2 • The recompilation time after a change must be short. More precisely, it should be proportional to the size of the change, not to the size of the entire system. The crucial compilation concern, for developers working on a possibly large system, is the need to perform changes and see the results immediately
$36.3 THE COMPILATION TECHNOLOGY 1145 C3.A third requirement,which appeared more recently,is quickly becoming important:the need to support the fast delivery of applications through the Internet to users or potential users,for immediate execution. The first two requirements,in particular,are hard to reconcile.CI is usually addressed through extensive compiler optimizations that make the recompilation and linking process prohibitively long.C2 is well served by interpretive environments,which execute software on-the-fly with little or no processing,but to obtain this result they must sacrifice execution-time performance(C1)and static type checking. The Melting Ice Technology The compilation technology that deals with the preceding issues,known as the Melting Ice Technology,uses a mix of complementary techniques.Once you have compiled a system, it is said to be frozen,like a block of ice stored in the freezer.As you take out the system to start working on it (so the metaphor goes),you produce some heat;the melted elements represent the changes.Those elements will not cause a compile-link cycle,which would defeat the goal of fast recompilation(C2);the melted code is,instead,directly executable by the environment's execution engine. YOUR SYSTEM THE ENVIRONMENT The Frozen and the Melted FREEZING Machine code FROZEN (from C code) Execution, browsing, symbolic debugging. BENCH documentation... MELTING “Bytecode” MELTED The tricky part(for the compiler implementers)is of course to make sure that the various components can work together,in particular that frozen code can call melted elements-even though it was not known,at freezing time,that they would later be melted!But the result is definitely worthwhile: Recompilation is fast.The waiting time is typically a few seconds. This is still a compilation approach:any recompilation will perform full type checking(without undue penalty on recompilation time because the checking,like the recompilation in general,is incremental:only the changed parts are rechecked)
§36.3 THE COMPILATION TECHNOLOGY 1145 C3 • A third requirement, which appeared more recently, is quickly becoming important: the need to support the fast delivery of applications through the Internet to users or potential users, for immediate execution. The first two requirements, in particular, are hard to reconcile. C1 is usually addressed through extensive compiler optimizations that make the recompilation and linking process prohibitively long. C2 is well served by interpretive environments, which execute software on-the-fly with little or no processing, but to obtain this result they must sacrifice execution-time performance (C1) and static type checking. The Melting Ice Technology The compilation technology that deals with the preceding issues, known as the Melting Ice Technology, uses a mix of complementary techniques. Once you have compiled a system, it is said to be frozen, like a block of ice stored in the freezer. As you take out the system to start working on it (so the metaphor goes), you produce some heat; the melted elements represent the changes. Those elements will not cause a compile-link cycle, which would defeat the goal of fast recompilation (C2); the melted code is, instead, directly executable by the environment’s execution engine. The tricky part (for the compiler implementers) is of course to make sure that the various components can work together, in particular that frozen code can call melted elements — even though it was not known, at freezing time, that they would later be melted! But the result is definitely worthwhile: • Recompilation is fast. The waiting time is typically a few seconds. • This is still a compilation approach: any recompilation will perform full type checking (without undue penalty on recompilation time because the checking, like the recompilation in general, is incremental: only the changed parts are rechecked). The Frozen and the Melted YOUR SYSTEM Execution, browsing, symbolic debugging, documentation… MELTING FREEZING Machine code (from C code) FROZEN MELTED BENCH “Bytecode” THE ENVIRONMENT
1146 AN OBJECT-ORIENTED ENVIRONMENT $36.3 Run-time performance remains acceptable because for a non-trivial system a typical modification will only affect a small percentage of the code;everything else will be executed in its compiled form.(For maximum efficiency,you will use the finalization form of compilation,as explained below.) As you perform more and more changes,the proportion of melted code will grow; after a while the effect on performance,time and space,may become perceptible.So it is wise to re-freeze every few days.Because freezing implies a C-compilation and linking, the time it takes is typically more on the order of minutes(or even an hour after several days of extensive changes).You can start this task in the background,or at night. Dependency analysis As should be the case in any modern development environment,the recompilation process is automatic;you will simply click on the Melt button of the Project Tool,in the interface described below,and the compiling mechanisms will silently determine the smallest set of elements that need to be recompiled;there is no need for "Make files"and the notation has no notion of“include file”. To compute what needs to be recompiled,the environment's tools first find out what you have changed,either from within the environment,using its own class editor,or through outside tools such as text editors (each class text being stored in a file,the time stamps provide the basic information).Then they use the two dependency relations,client and inheritance,to determine what else may have been affected and needs recompilation. In the client case,information hiding is an important help to minimize propagation:if a change to a class only affects secret features,its clients do not need recompilation To reduce melting time further,the grain of recompilation is not the class but the individual routine. Note that if you add an external element,for example a C function,a freeze will be required.Again this will be determined automatically. Precompilation In accordance with the method's emphasis on reusability,it is essential to allow software developers to put together carefully crafted sets of components-libraries-,compile them once and for all,and distribute them to other developers who will simply include them in their systems without having to know anything about their internal organization. The precompilation mechanism achieves this goal.A special compilation option On Ace files see generates a compiled form of a set of classes;then it is possible (through the Ace file)to “Assembling a sys- include a precompiled library in a new system. tem",page 198. There is no limit to the number of precompiled libraries that you may include in a new system.The mechanism that combines precompiled libraries supports sharing:if two precompiled libraries B and C both rely on a third one A (as with the Vision graphical library and the Net client-server library,discussed later,which both rely on the Base libraries for data structures and fundamental algorithms),only one copy of A will be included provided both B and C use the same version of A
1146 AN OBJECT-ORIENTED ENVIRONMENT §36.3 • Run-time performance remains acceptable because for a non-trivial system a typical modification will only affect a small percentage of the code; everything else will be executed in its compiled form. (For maximum efficiency, you will use the finalization form of compilation, as explained below.) As you perform more and more changes, the proportion of melted code will grow; after a while the effect on performance, time and space, may become perceptible. So it is wise to re-freeze every few days. Because freezing implies a C-compilation and linking, the time it takes is typically more on the order of minutes (or even an hour after several days of extensive changes). You can start this task in the background, or at night. Dependency analysis As should be the case in any modern development environment, the recompilation process is automatic; you will simply click on the Melt button of the Project Tool, in the interface described below, and the compiling mechanisms will silently determine the smallest set of elements that need to be recompiled; there is no need for “Make files” and the notation has no notion of “include file”. To compute what needs to be recompiled, the environment’s tools first find out what you have changed, either from within the environment, using its own class editor, or through outside tools such as text editors (each class text being stored in a file, the time stamps provide the basic information). Then they use the two dependency relations, client and inheritance, to determine what else may have been affected and needs recompilation. In the client case, information hiding is an important help to minimize propagation: if a change to a class only affects secret features, its clients do not need recompilation. To reduce melting time further, the grain of recompilation is not the class but the individual routine. Note that if you add an external element, for example a C function, a freeze will be required. Again this will be determined automatically. Precompilation In accordance with the method’s emphasis on reusability, it is essential to allow software developers to put together carefully crafted sets of components — libraries —, compile them once and for all, and distribute them to other developers who will simply include them in their systems without having to know anything about their internal organization. The precompilation mechanism achieves this goal. A special compilation option generates a compiled form of a set of classes; then it is possible (through the Ace file) to include a precompiled library in a new system. There is no limit to the number of precompiled libraries that you may include in a new system. The mechanism that combines precompiled libraries supports sharing: if two precompiled libraries B and C both rely on a third one A (as with the Vision graphical library and the Net client-server library, discussed later, which both rely on the Base libraries for data structures and fundamental algorithms), only one copy of A will be included provided both B and C use the same version of A. On Ace files see “Assembling a system”, page 198
$36.3 THE COMPILATION TECHNOLOGY 1147 “Formats for reus-. The author of a precompiled library may want to prevent his customers from having able component dis- access to the source code of the library (an early chapter discussed the pros and cons of tribution",page 79. this policy).It is indeed possible,when precompiling,to make the source code inaccessible.In that case users of the environment will be able,through the visual tools described later in this chapter,to browse the short form and the flat-short form of the library's classes,that is to say their interface (public)properties;but they will not be able to see their full text,let alone their flat form. Remote execution At the time ofwriting The interpretive code generated by melting-conventionally known as bytecode and the plug-in mecha- identified as such on the preceding figure-is platform-independent.To execute nism has not yet been released. bytecode,it suffices to have a copy of the environment's Execution Engine,known as 3E and freely downloadable through the Internet. By adding 3E as a plug-in to a Web browser,it will be possible to make code directly executable:if a browser's user clicks on a hyperlink corresponding to bytecode,3E will automatically execute the corresponding code.This is the remote execution mechanism first popularized by Java. 3E actually comes in two flavors,distinguished by the accompanying precompiled libraries.The first,secure,is meant for Internet usage;to avoid security risks it only allows input and output to the terminal.The second,meant for Intranet(corporate network) usage,supports general I/O and other precompiled libraries. An effort is also in progress to translate the bytecode into Java bytecode,to offer the supplementary possibility of executing the result of a development using a Java virtual machine. Optimization To generate the best possible code-goal CI of the earlier discussion-frozen mode is not sufficient.Some crucial optimizations require having a complete,stable system: Dead code removal removes any routines that can never be called,directly or indirectly,from the system's root creation procedure.This is particularly important if you rely on many precompiled libraries,of which your system may only need a subset;a space gain of 50%is not uncommon. "Static binding as Static binding which,as we studied in detail in the discussion of inheritance,should be an optimization”, applied by the compiler for features that are not redefined,or non-polymorphic entities. page 511 (also dis- cusses inlining). Routine inlining,also subject to compiler algorithms. When you are still changing your system,these optimizations are not applicable, since your next editing move could invalidate the compiler's work.For example by adding just one call you may resuscitate a supposedly dead routine;by adding a routine redefinition,you cause a statically bound routine to require dynamic binding.Besides, such optimizations may require a complete pass through a system,for example to determine that no class redefines a certain routine;this makes them incompatible with incremental development
§36.3 THE COMPILATION TECHNOLOGY 1147 The author of a precompiled library may want to prevent his customers from having access to the source code of the library (an early chapter discussed the pros and cons of this policy). It is indeed possible, when precompiling, to make the source code inaccessible. In that case users of the environment will be able, through the visual tools described later in this chapter, to browse the short form and the flat-short form of the library’s classes, that is to say their interface (public) properties; but they will not be able to see their full text, let alone their flat form. Remote execution The interpretive code generated by melting — conventionally known as bytecode and identified as such on the preceding figure — is platform-independent. To execute bytecode, it suffices to have a copy of the environment’s Execution Engine, known as 3E and freely downloadable through the Internet. By adding 3E as a plug-in to a Web browser, it will be possible to make code directly executable: if a browser’s user clicks on a hyperlink corresponding to bytecode, 3E will automatically execute the corresponding code. This is the remote execution mechanism first popularized by Java. 3E actually comes in two flavors, distinguished by the accompanying precompiled libraries. The first, secure, is meant for Internet usage; to avoid security risks it only allows input and output to the terminal. The second, meant for Intranet (corporate network) usage, supports general I/O and other precompiled libraries. An effort is also in progress to translate the bytecode into Java bytecode, to offer the supplementary possibility of executing the result of a development using a Java virtual machine. Optimization To generate the best possible code — goal C1 of the earlier discussion — frozen mode is not sufficient. Some crucial optimizations require having a complete, stable system: • Dead code removal removes any routines that can never be called, directly or indirectly, from the system’s root creation procedure. This is particularly important if you rely on many precompiled libraries, of which your system may only need a subset; a space gain of 50% is not uncommon. • Static binding which, as we studied in detail in the discussion of inheritance, should be applied by the compiler for features that are not redefined, or non-polymorphic entities. • Routine inlining, also subject to compiler algorithms. When you are still changing your system, these optimizations are not applicable, since your next editing move could invalidate the compiler’s work. For example by adding just one call you may resuscitate a supposedly dead routine; by adding a routine redefinition, you cause a statically bound routine to require dynamic binding. Besides, such optimizations may require a complete pass through a system, for example to determine that no class redefines a certain routine; this makes them incompatible with incremental development. “Formats for reusable component distribution”, page 79. At the time of writing the plug-in mechanism has not yet been released. “Static binding as an optimization”, page 511 (also discusses inlining)