35 Simula to Java and beyond:major O-O languages and environments ncouraged by the introduction of Simula in17anumber of obectrend languages have appeared on the scene,highlighting various aspects of the approach.This chapter reviews some of the languages that have attracted the most attention:Simula; Smalltalk;C++and other O-O extensions of C;Java. The literature still lacks an in-depth comparative study of important O-O languages. The ambition of this chapter is of necessity more modest.In particular,the space allotted to each language is not an indication of the language's practical significance,and some of the most publicized will indeed get a fairly short treatment.Our goal is to learn about issues and concepts,finding them where we can,even if that means turning our attention for a while to one of the less hyped approaches.The risk of under-representing one of the principal players is not great,since one only has to look around to pick up articles and books describing it in generous detail.The real risk would be the reverse:to miss a promising idea just because the language supporting it(say Simula)does not currently enjoy top favor.In its coverage of notable languages,then,this survey is not equal-opportunity;it is instead, in its choice of notable language traits,a case of affirmative action. Even when the concepts are the same or similar,the terms used to denote them in official language descriptions can vary.The discussion will use the native terms when they reflect language peculiarities;for simplicity and consistency,however,it uses the terminology of the rest of this book (designed as an attempt at unification)when differences are unimportant.For example you will read about Simula routines,procedures and functions,although the corresponding terms in official Simula usage are procedure, unty ped procedure and typed procedure. 35.1 SIMULA The undisputed founder of the House of Classes (Object Palace)is Simula,whose design was completed(if we ignore a few later updates,entirely minor)in 1967.This may seem hard to believe:a full-fledged object-oriented language was around,and implemented, before structured programming,before Parnas had published his articles on information hiding,many years before anyone had come up with the phrase"abstract data type".The Vietnam War was still a page-4 item;barricades had not yet sprung up in the streets of Paris;a mini-skirt could still cause a stir:away by the Northern shores of the Baltic a few
35 Simula to Java and beyond: major O-O languages and environments Encouraged by the introduction of Simula in 1967, a number of object-oriented languages have appeared on the scene, highlighting various aspects of the approach. This chapter reviews some of the languages that have attracted the most attention: Simula; Smalltalk; C++ and other O-O extensions of C; Java. The literature still lacks an in-depth comparative study of important O-O languages. The ambition of this chapter is of necessity more modest. In particular, the space allotted to each language is not an indication of the language’s practical significance, and some of the most publicized will indeed get a fairly short treatment. Our goal is to learn about issues and concepts, finding them where we can, even if that means turning our attention for a while to one of the less hyped approaches. The risk of under-representing one of the principal players is not great, since one only has to look around to pick up articles and books describing it in generous detail. The real risk would be the reverse: to miss a promising idea just because the language supporting it (say Simula) does not currently enjoy top favor. In its coverage of notable languages, then, this survey is not equal-opportunity; it is instead, in its choice of notable language traits, a case of affirmative action. Even when the concepts are the same or similar, the terms used to denote them in official language descriptions can vary. The discussion will use the native terms when they reflect language peculiarities; for simplicity and consistency, however, it uses the terminology of the rest of this book (designed as an attempt at unification) when differences are unimportant. For example you will read about Simula routines, procedures and functions, although the corresponding terms in official Simula usage are procedure, untyped procedure and typed procedure. 35.1 SIMULA The undisputed founder of the House of Classes (Object Palace) is Simula, whose design was completed (if we ignore a few later updates, entirely minor) in 1967. This may seem hard to believe: a full-fledged object-oriented language was around, and implemented, before structured programming, before Parnas had published his articles on information hiding, many years before anyone had come up with the phrase “abstract data type”. The Vietnam War was still a page-4 item; barricades had not yet sprung up in the streets of Paris; a mini-skirt could still cause a stir: away by the Northern shores of the Baltic a few
1114 SIMULA TO JAVA AND BEYOND:MAJOR O-O LANGUAGES AND ENVIRONMENTS $35.1 fortunate software developers led by a handful of visionaries were already profiting from the power of classes,inheritance,polymorphism,dynamic binding and most of the other marvels of object orientation. Background Simula is actually a second design.In the early sixties,a language now known as Simula I was developed to support the programming of discrete-event simulations.Although not quite object-oriented in the full sense of the term,it already showed some of the key insights."Simula"proper is Simula 67,designed in 1967 by Kristen Nygaard and Ole- Johan Dahl from the University of Oslo and the Norwegian Computing Center (Norsk Regnesentral).Nygaard has explained since how the decision to keep the name was meant to ensure continuity with the previous language and the link to its user community;but an unfortunate effect was that for a long time that name evoked for many people the image of a language meant only for discrete-event simulation-a relatively narrow application area-even though Simula 67 is definitely a general-purpose programming language, whose only simulation-specific features are a handful of instructions and a S/MUL4T/ON library class,used by a minority of Simula developers. The name was shortened to just Simula in 1986;the current standard is from 1987. Availability Simula is often presented as a respectable but defunct ancestor.In fact it is still alive and enjoys the support of a small but enthusiastic community.The language definition is maintained by the "Simula Standards Group".Compilers are available for a variety of hardware and software environments from several companies,mostly Scandinavian. Major language traits We will take a general look at the basic properties of Simula.To some readers Simula will be passe,and the author of this book will not feel insulted if you skip to the next section, on Smalltalk.But if you do want to gain a full appreciation of object technology you will find Simula worth your time;the concepts are there in their original form,and a few of them show possibilities that may not yet,thirty years later,have been fully exploited. Simula is an object-oriented extension of Algol 60.Most correct Algol programs are also correct Simula programs.In particular,the basic control structures are those of Algol: loop,conditional,switch(a multiple branch instruction,low-level precursor to Pascal's case instruction).The basic data types(integer,real etc.)are also drawn from Algol. Like Algol,Simula uses at the highest level a traditional software structure based on the notion of main program.An executable program is a main program containing a number of program units (routines or classes).Simula environments do support,however, a form of separate class compilation. Simula uses full block structure in the Algol 60 style:program units such as classes may be nested within one another
1114 SIMULA TO JAVA AND BEYOND: MAJOR O-O LANGUAGES AND ENVIRONMENTS §35.1 fortunate software developers led by a handful of visionaries were already profiting from the power of classes, inheritance, polymorphism, dynamic binding and most of the other marvels of object orientation. Background Simula is actually a second design. In the early sixties, a language now known as Simula 1 was developed to support the programming of discrete-event simulations. Although not quite object-oriented in the full sense of the term, it already showed some of the key insights. “Simula” proper is Simula 67, designed in 1967 by Kristen Nygaard and OleJohan Dahl from the University of Oslo and the Norwegian Computing Center (Norsk Regnesentral). Nygaard has explained since how the decision to keep the name was meant to ensure continuity with the previous language and the link to its user community; but an unfortunate effect was that for a long time that name evoked for many people the image of a language meant only for discrete-event simulation — a relatively narrow application area — even though Simula 67 is definitely a general-purpose programming language, whose only simulation-specific features are a handful of instructions and a SIMULATION library class, used by a minority of Simula developers. The name was shortened to just Simula in 1986; the current standard is from 1987. Availability Simula is often presented as a respectable but defunct ancestor. In fact it is still alive and enjoys the support of a small but enthusiastic community. The language definition is maintained by the “Simula Standards Group”. Compilers are available for a variety of hardware and software environments from several companies, mostly Scandinavian. Major language traits We will take a general look at the basic properties of Simula. To some readers Simula will be passé, and the author of this book will not feel insulted if you skip to the next section, on Smalltalk. But if you do want to gain a full appreciation of object technology you will find Simula worth your time; the concepts are there in their original form, and a few of them show possibilities that may not yet, thirty years later, have been fully exploited. Simula is an object-oriented extension of Algol 60. Most correct Algol programs are also correct Simula programs. In particular, the basic control structures are those of Algol: loop, conditional, switch (a multiple branch instruction, low-level precursor to Pascal’s case instruction). The basic data types (integer, real etc.) are also drawn from Algol. Like Algol, Simula uses at the highest level a traditional software structure based on the notion of main program. An executable program is a main program containing a number of program units (routines or classes). Simula environments do support, however, a form of separate class compilation. Simula uses full block structure in the Algol 60 style: program units such as classes may be nested within one another
$35.1 SIMULA 1115 All Simula implementations support automatic garbage collection.There is a small standard library,including in particular two-way linked lists used by the S/MULATION class studied later in this chapter. See“References and As in the notation of this book,the most common entities of non-basic types denote simple values", references to class instances,rather than the instances themselves.Instead of being page 272. implicit,however,this property is emphasized by the notation.You will declare the type of such an entity as ref(C),rather than just C,for some class C;and the corresponding operations will use special symbols::-for an assignment where integer or real operands would use:=;==rather than for equality;=/rather than /for inequality.An earlier chapter presented the rationale for and against this convention. To create an instance,you will use,rather than a creation instruction,a new expression: ref(C)a;...a:-new C Evaluation of the new expression creates an instance of C and returns a reference to it.A class may have arguments(playing the role of the arguments to creation procedures in our notation),as in class C(x,y);integer x,y begin ..end: In this case,the new expression must provide corresponding actual arguments: a:-new C(3,98) The arguments may then be used in routines of the class;but unlike with creation instructions this gives only one initialization mechanism. Besides routines and attributes,a class may contain a sequence of instructions,the body of the class;if so,the new call will execute these instructions.We will see how to use this possibility to make classes represents process-like computational elements rather than just passive objects as in most other O-O languages. No assertion mechanism is provided.Simula supports single inheritance;to declare B as an heir of 4,use A class B: begin...end To redefine a feature of a class in a descendant class,simply provide a new declaration;it will take precedence over the original one.(There is no equivalent to the redefine clause.) The original version of Simula 67 did not have explicit information hiding constructs.In more recent versions,a feature declared as protected will be unavailable to clients;a protected feature which is further declared as hidden will also be unavailable to proper descendants.A non-protected feature may be protected by a proper descendant,but a protected feature may not be re-exported by proper descendants
§35.1 SIMULA 1115 All Simula implementations support automatic garbage collection. There is a small standard library, including in particular two-way linked lists used by the SIMULATION class studied later in this chapter. As in the notation of this book, the most common entities of non-basic types denote references to class instances, rather than the instances themselves. Instead of being implicit, however, this property is emphasized by the notation. You will declare the type of such an entity as ref (C), rather than just C, for some class C; and the corresponding operations will use special symbols: :– for an assignment where integer or real operands would use :=; == rather than = for equality; =/= rather than /= for inequality. An earlier chapter presented the rationale for and against this convention. To create an instance, you will use, rather than a creation instruction, a new expression: ref (C) a; …; a :– new C Evaluation of the new expression creates an instance of C and returns a reference to it. A class may have arguments (playing the role of the arguments to creation procedures in our notation), as in class C (x, y); integer x, y begin … end; In this case, the new expression must provide corresponding actual arguments: a :– new C (3, 98) The arguments may then be used in routines of the class; but unlike with creation instructions this gives only one initialization mechanism. Besides routines and attributes, a class may contain a sequence of instructions, the body of the class; if so, the new call will execute these instructions. We will see how to use this possibility to make classes represents process-like computational elements rather than just passive objects as in most other O-O languages. No assertion mechanism is provided. Simula supports single inheritance; to declare B as an heir of A, use A class B; begin … end To redefine a feature of a class in a descendant class, simply provide a new declaration; it will take precedence over the original one. (There is no equivalent to the redefine clause.) The original version of Simula 67 did not have explicit information hiding constructs. In more recent versions, a feature declared as protected will be unavailable to clients; a protected feature which is further declared as hidden will also be unavailable to proper descendants. A non-protected feature may be protected by a proper descendant, but a protected feature may not be re-exported by proper descendants. See “References and simple values”, page 272
1116 SIMULA TO JAVA AND BEYOND:MAJOR O-O LANGUAGES AND ENVIRONMENTS $35.1 Deferred features are offered in the form of"virtual routines",appearing in a virtual paragraph at the beginning of the class.It is not necessary to declare the arguments of a virtual routine;this means that different effective definitions ofa virtual routine may have different numbers and types of arguments.For example,a class POLYGON might begin class POLYGON; virtual:procedure set_vertices begin 4+ end allowing descendants to provide a variable number of arguments of type POINT for set vertices:three for TR/ANGLE,four for OUADRANGLE etc.This flexibility implies that some of the type checking must be done at run time. C++users should beware of a possible confusion:although inspired by Simula,C++uses “TheC++ a different meaning for the word virtual.A C++function is virtual if it is meant to be approach to bind- dynamically bound (it is,as we have seen,one of the most controversial aspects of C++ ing",page 514. that you must specify this requirement explicitly).The C++approximation to Simula's virtual procedures is called a"pure virtual function" Simula supports polymorphism:if B is a descendant of,the assignmental-b/is correct for al of type A and b/of type B.(Interestingly enough,assignment attempt is almost there:if the type of b/is an ancestor of the type of al,the assignment will work if the run-time objects have the proper conformance relationship-source descendant of target,if not,however,the result will be a run-time error,rather than a special value which, as with assignment attempt,the software could detect and handle.)By default,binding is static rather than dynamic,except for virtual routines.So if/is a non-virtual feature declared at the 4 level,al.f will denote the 4 version of/even if there is a different version in B.You can force dynamic binding by using the qua construct,as in (al qua B).f This,of course,loses the automatic adaptation of every operation to its target.You may however obtain the desired dynamic binding behavior (which may largely be considered a Simula invention)by declaring polymorphic routines as virtual.In many of the examples that we have studied,a polymorphic routine was not deferred but had a default implementation right from the start.To achieve the same effect,the Simula developer will add an intermediate class where the routine is virtual. As an alternative to using qua,the inspeet instruction makes it possible to perform a different operation on an entity a/,depending on the actual type of the corresponding object,which must be a descendant of the type 4 declared for al: inspect al when 4 do ... when B do...; This achieves the same effect but assumes that the set of descendants of a class is frozen,and runs into conflict with the Open-Closed principle
1116 SIMULA TO JAVA AND BEYOND: MAJOR O-O LANGUAGES AND ENVIRONMENTS §35.1 Deferred features are offered in the form of “virtual routines”, appearing in a virtual paragraph at the beginning of the class. It is not necessary to declare the arguments of a virtual routine; this means that different effective definitions of a virtual routine may have different numbers and types of arguments. For example, a class POLYGON might begin class POLYGON; virtual: procedure set_vertices begin … end allowing descendants to provide a variable number of arguments of type POINT for set_vertices: three for TRIANGLE, four for QUADRANGLE etc. This flexibility implies that some of the type checking must be done at run time. C++ users should beware of a possible confusion: although inspired by Simula, C++ uses a different meaning for the word virtual. A C++ function is virtual if it is meant to be dynamically bound (it is, as we have seen, one of the most controversial aspects of C++ that you must specify this requirement explicitly). The C++ approximation to Simula’s virtual procedures is called a “pure virtual function”. Simula supports polymorphism: if B is a descendant of A, the assignment a1 :– b1 is correct for a1 of type A and b1 of type B. (Interestingly enough, assignment attempt is almost there: if the type of b1 is an ancestor of the type of a1, the assignment will work if the run-time objects have the proper conformance relationship — source descendant of target; if not, however, the result will be a run-time error, rather than a special value which, as with assignment attempt, the software could detect and handle.) By default, binding is static rather than dynamic, except for virtual routines. So if f is a non-virtual feature declared at the A level, a1 ● f will denote the A version of f even if there is a different version in B. You can force dynamic binding by using the qua construct, as in (a1 qua B) ● f This, of course, loses the automatic adaptation of every operation to its target. You may however obtain the desired dynamic binding behavior (which may largely be considered a Simula invention) by declaring polymorphic routines as virtual. In many of the examples that we have studied, a polymorphic routine was not deferred but had a default implementation right from the start. To achieve the same effect, the Simula developer will add an intermediate class where the routine is virtual. As an alternative to using qua, the inspect instruction makes it possible to perform a different operation on an entity a1, depending on the actual type of the corresponding object, which must be a descendant of the type A declared for a1: inspect a1 when A do …; when B do …; … This achieves the same effect but assumes that the set of descendants of a class is frozen, and runs into conflict with the Open-Closed principle “The C++ approach to binding”, page 514
§35.1 SIMULA 1117 An example Chapter 20.Com- The following class extracts illustrate the general flavor of Simula.They are drawn from pare with the final the solution to the problem of full-screen entry systems. class texts in“AW OBJECT-ORI- class STATE: ENTED ARCHI TECTURE”20.5, virtual: page 684. procedure display; The original STATE procedure read; class appeared on page 686. boolean procedure correct; procedure message; procedure process; begin ref (ANSWER)user_answer;integer choice, procedure execute;begin boolean ok; ok :false: while not ok do begin display;read;ok :correct, if not ok then message (a) end while; process. end execute end STATE; The original APLI- class APPLICATION (n,m); CATION class integer n,m; appeared on page 690. begin ref (STATE)array transition (I:n,0:m-1); ref (STATE)array associated state (1:n). integer initial; procedure execute;begin integer st number; st number:=initial; while st number =0 do begin ref (STATE)st. st associated state (st number),st.execute; st number transition (st number,st.choice) end while end execute end APPLICATION
§35.1 SIMULA 1117 An example The following class extracts illustrate the general flavor of Simula. They are drawn from the solution to the problem of full-screen entry systems. class STATE; virtual: procedure display; procedure read; boolean procedure correct; procedure message; procedure process; begin ref (ANSWER) user_answer; integer choice; procedure execute; begin boolean ok; ok := false; while not ok do begin display; read; ok := correct; if not ok then message (a) end while; process; end execute end STATE; class APPLICATION (n, m); integer n, m; begin ref (STATE) array transition (1:n, 0:m–1); ref (STATE) array associated_state (1:n); integer initial; procedure execute; begin integer st_number; st_number := initial; while st_number /= 0 do begin ref (STATE) st; st := associated_state (st_number); st ● execute; st_number := transition (st_number, st ● choice) end while end execute … end APPLICATION Chapter 20. Compare with the final class texts in “AN OBJECT-ORIENTED ARCHITECTURE”, 20.5, page 684. The original STATE class appeared on page 686. The original APLICATION class appeared on page 690
1118 SIMULA TO JAVA AND BEYOND:MAJOR O-O LANGUAGES AND ENVIRONMENTS $35.1 Coroutine concepts Along with basic O-O mechanisms,Simula offers an interesting notion:coroutines. The notion of coroutine was presented in the discussion of concurrency.Here is a “Coroutines",page brief reminder.Coroutines are modeled after parallel processes as they exist in operating 1012. systems or real-time software.A process has more conceptual autonomy than a routine;a printer driver,for example,is entirely responsible for what happens to the printer it manages.Besides being in charge of an abstract object,it has its own lifecycle algorithm, often conceptually infinite.The rough form of the printer process could be something like from some initialization loop forever For a more complete description of a “Obtain a file to be printed",“Print it” printer process see end “Processes pro- grammed"page 960. In sequential programming,the relationship between program units is asymmetric:a program unit calls another,which will execute completely and return to the caller at the point of call.Communication between processes is more equal:each process pursues its own life,interrupting itself to provide information to,or get information from another. Coroutines are similarly designed,but for execution on a single thread of control. (This sequential emulation of parallel execution is called quasi-parallelism.)A coroutine that "resumes"another interrupts its own execution and restarts its colleague at its last point of interruption;the interrupted coroutine may itself be later resumed. Coroutine sequencing resume a resume a (This figure resume b resume b appearedoriginally on page 1012.) Coroutines are particularly useful when each of several related activities has its own logic;each may be described as a sequential process,and the master-slave relationship implied by routines is not adequate.A frequent example is an input-to-output transformation in which different constraints are placed on the structure of the input and output files.Such a case will be discussed below. Simula represents coroutines as instances of classes.This is appropriate since coroutines almost always need persistent data,and often have an associated abstract object.As we noted earlier,a Simula class has a body,made of one or more instructions. In a class representing a passive data abstraction,it will only serve as initialization of the class instances(the equivalent of our creation procedure);but in a coroutine it will be the description of a process.The body of a coroutine is usually a loop of the form
1118 SIMULA TO JAVA AND BEYOND: MAJOR O-O LANGUAGES AND ENVIRONMENTS §35.1 Coroutine concepts Along with basic O-O mechanisms, Simula offers an interesting notion: coroutines. The notion of coroutine was presented in the discussion of concurrency. Here is a brief reminder. Coroutines are modeled after parallel processes as they exist in operating systems or real-time software. A process has more conceptual autonomy than a routine; a printer driver, for example, is entirely responsible for what happens to the printer it manages. Besides being in charge of an abstract object, it has its own lifecycle algorithm, often conceptually infinite. The rough form of the printer process could be something like from some_initialization loop forever “Obtain a file to be printed”; “Print it” end In sequential programming, the relationship between program units is asymmetric: a program unit calls another, which will execute completely and return to the caller at the point of call. Communication between processes is more equal: each process pursues its own life, interrupting itself to provide information to, or get information from another. Coroutines are similarly designed, but for execution on a single thread of control. (This sequential emulation of parallel execution is called quasi-parallelism.) A coroutine that “resumes” another interrupts its own execution and restarts its colleague at its last point of interruption; the interrupted coroutine may itself be later resumed. Coroutines are particularly useful when each of several related activities has its own logic; each may be described as a sequential process, and the master-slave relationship implied by routines is not adequate. A frequent example is an input-to-output transformation in which different constraints are placed on the structure of the input and output files. Such a case will be discussed below. Simula represents coroutines as instances of classes. This is appropriate since coroutines almost always need persistent data, and often have an associated abstract object. As we noted earlier, a Simula class has a body, made of one or more instructions. In a class representing a passive data abstraction, it will only serve as initialization of the class instances (the equivalent of our creation procedure); but in a coroutine it will be the description of a process. The body of a coroutine is usually a loop of the form “Coroutines”, page 1012. For a more complete description of a printer process see “Processes programmed”, page 960. Coroutine sequencing (This figure appeared originally on page 1012.) resume a resume a resume b resume b a b
$35.1 SIMULA 1119 while continuation condition do begin Actions... resume other coroutine: ...Actions... end For some of the coroutines in a system the continuation condition is often True to yield the equivalent of an infinite process (although at least one coroutine should terminate). A system based on coroutines generally has a main program that first creates a number of coroutine objects,and then resumes one of them: coroutl :-new Cl;corout2:-new C2;... resume corout On the parallel The evaluation of each new expression creates an object and starts executing its scheme see“A muli-launcher”, body.But the quasi-parallel nature of coroutines(as opposed to the true parallelism of page 988. processes)raises an initialization problem:with processes,each new would spawn off a new process and return control to the caller,but here only one coroutine may be active at any given time.If the new expression started the coroutine's main algorithm,the above main thread would never recapture control;for example it would never get a chance to create C2 after spawning off Cl. Simula addresses this problem through the detach instruction.A coroutine may execute a detach to give control back to the unit that created it through a new.Coroutine bodies almost always begin (after initialization instructions if needed)with a detach, usually followed by a loop.After executing its detach,the coroutine will become suspended until the main program or another coroutine resumes it. A coroutine example Here is an illustration of the kind of situation in which coroutines may prove useful.You are requested to print a sequence of real numbers,given as input;but every eighth number (the eighth,the sixteenth,the twenty-fourth etc.)is to be omitted from the output. Furthermore,the output must appear as a sequence of lines,with six numbers per line (except for the last line if there are not enough numbers to fill it).So if i denotes the n-th input item,the output will start as il i2 i3 i4 i5 i6 iz ig i10 i11 i12 113 114 115 117 etc. Finally,the output should only include the first 1000 numbers thus determined This problem is representative of coroutine use because it conceptually involves three processes,each with its specific logic:the input,where the constraint is to skip every eighth item;the output,where the constraint is to go to the next line after every sixth item; and the main program,which is required to process 1000 items.Traditional control structures are not good at combining such processes with widely different constraints.A coroutine solution,on the other hand,will work smoothly
§35.1 SIMULA 1119 while continuation_condition do begin … Actions…; resume other_coroutine; …Actions … end For some of the coroutines in a system the continuation_condition is often True to yield the equivalent of an infinite process (although at least one coroutine should terminate). A system based on coroutines generally has a main program that first creates a number of coroutine objects, and then resumes one of them: corout1 :– new C1; corout2 :– new C2; … resume corouti The evaluation of each new expression creates an object and starts executing its body. But the quasi-parallel nature of coroutines (as opposed to the true parallelism of processes) raises an initialization problem: with processes, each new would spawn off a new process and return control to the caller; but here only one coroutine may be active at any given time. If the new expression started the coroutine’s main algorithm, the above main thread would never recapture control; for example it would never get a chance to create C2 after spawning off C1. Simula addresses this problem through the detach instruction. A coroutine may execute a detach to give control back to the unit that created it through a new. Coroutine bodies almost always begin (after initialization instructions if needed) with a detach, usually followed by a loop. After executing its detach, the coroutine will become suspended until the main program or another coroutine resumes it. A coroutine example Here is an illustration of the kind of situation in which coroutines may prove useful. You are requested to print a sequence of real numbers, given as input; but every eighth number (the eighth, the sixteenth, the twenty-fourth etc.) is to be omitted from the output. Furthermore, the output must appear as a sequence of lines, with six numbers per line (except for the last line if there are not enough numbers to fill it). So if in denotes the n-th input item, the output will start as i1 i2 i3 i4 i5 i6 i 7 i9 i10 i 11 i12 i13 i 14 i15 i17 etc. Finally, the output should only include the first 1000 numbers thus determined. This problem is representative of coroutine use because it conceptually involves three processes, each with its specific logic: the input, where the constraint is to skip every eighth item; the output, where the constraint is to go to the next line after every sixth item; and the main program, which is required to process 1000 items. Traditional control structures are not good at combining such processes with widely different constraints. A coroutine solution, on the other hand, will work smoothly. On the parallel scheme see “A multi-launcher”, page 988
1120 SIMULA TO JAVA AND BEYOND:MAJOR O-O LANGUAGES AND ENVIRONMENTS $35.1 Following the preceding analysis,we may use three coroutines:the producer (input),the printer (output)and the controller.The general structure is: begin elass PRODUCER begin ..See next...end PRODUCER; class PRINTER begin ..See next ..end PRINTER; class CONTROLLER begin ..See next...end CONTROLLER; rel(PRODUCER)producer;ref(PRINTER)printer;ref(CONTROLLER)controller; producer-new PRODUCER:printer:-new PRINTER;controller:-new CONTROLLER: resume controller end This is a main program,in the usual sense;it creates an instance of each of the three coroutine classes and resumes one of them,the controller.Here are the classes: class CONTROLLER;begin integer detach: for i:=I step I until 1000 do resume printer end CONTROLLER: class PRINTER:begin integer i; detach: while true do for i:=step until 8 do begin resume producer; outreal (producer.last inpul), resume controller end: next line end end PRINTER: class PRODUCER:begin This scheme will not integer i,real last input,discarded, work if the program rins out of input detach; before having while true do begin printed 1000 output items.See exercise for i:=/step until 6 do begin E35.1,page1139. last input :inreal,resume printer end; discarded inreal end end PRODUCER:
1120 SIMULA TO JAVA AND BEYOND: MAJOR O-O LANGUAGES AND ENVIRONMENTS §35.1 Following the preceding analysis, we may use three coroutines: the producer (input), the printer (output) and the controller. The general structure is: begin class PRODUCER begin … See next … end PRODUCER; class PRINTER begin … See next … end PRINTER; class CONTROLLER begin … See next … end CONTROLLER; ref (PRODUCER) producer; ref (PRINTER) printer; ref (CONTROLLER) controller; producer:– new PRODUCER; printer:– new PRINTER; controller:– new CONTROLLER; resume controller end This is a main program, in the usual sense; it creates an instance of each of the three coroutine classes and resumes one of them, the controller. Here are the classes: class CONTROLLER; begin integer i; detach; for i := 1 step 1 until 1000 do resume printer end CONTROLLER; class PRINTER; begin integer i; detach; while true do for i := 1 step 1 until 8 do begin resume producer; outreal (producer ● last_input); resume controller end; next_line end end PRINTER; class PRODUCER; begin integer i; real last_input, discarded; detach; while true do begin for i := 1 step 1 until 6 do begin last_input := inreal; resume printer end; discarded := inreal end end PRODUCER; This scheme will not work if the program runs out of input before having printed 1000 output items. See exercise E35.1, page 1139
$35.1 SIMULA 1121 Each class body begins with detach to allow the main program to proceed with the initialization of other coroutines.Procedure outreal prints a real number;function inreal reads and returns the next real on input;the extract assumes a procedure next line that goes to the next line on input. Coroutines fit well with the other concepts of object-oriented software construction. Note how decentralized the above scheme is:each process minds its own business,with limited interference from the others.The producer takes care of generating candidates from the input;the printer takes care of the output;the controller takes care of when to start and finish.As usual,a good check of the quality of the solution is the ease of extension and modification;it is indeed straightforward here to add a coroutine that will check for end of input(as requested by an exercise).Coroutines take decentralization,the hallmark of O-O architectures,one step further. On the use of a con- The architecture could be made even more decentralized.In particular,the processes currencymechanism in the above structure must still activate each other by name;ideally they should not have to describe corou- tines see "Corou- to know about each other except to communicate requested information (as when the tines"page 1012. printer obtains last input from the producer).The simulation primitives studied below allow this;after that,the solution is to use a full concurrency mechanism,such as described in an earlier chapter.As you will remember,its platform-independence means that it will work for coroutines as well as true parallelism. Sequencing and inheritance “Synchronization Even if it does not use coroutine mechanisms(detach,resume),a Simula class may have for concurrent O-O computation”,pag a body (a sequence of instructions)in addition to its features,and so may take on the 980. behavior of a process in addition to its usual role as an abstract data type implementation When combined with inheritance,this property leads to a simpler version of what the discussion of concurrency called the inheritance anomaly,to which Simula,thanks to its limitation to single rather than multiple inheritance and coroutines rather than full parallelism,is able to provide a language solution. For a class C let bodyc be the sequence of instructions declared as body of C and actual_bodyc the sequence of instructions executed for every creation of an instance of C. If C has no parent,actual bodyc is just bodyc.If C has a parent A(it can have at most one) then actual bodyc is by default the sequence of instructions actual body bodyc In other words,ancestors'bodies are executed in the order of inheritance.But this default may not be what you want.To supersede it,Simula offers the inner instruction which denotes the heir's body,so that the default policy is equivalent to having an inner at the end of the parent's body.If instead you write the body of4 as instructions j;inner;instructions then (assuming 4 itself has no parent)the execution of C will execute not its bodyc as written in the class but its actual bodyc defined as instructions j,bodyc,instructions
§35.1 SIMULA 1121 Each class body begins with detach to allow the main program to proceed with the initialization of other coroutines. Procedure outreal prints a real number; function inreal reads and returns the next real on input; the extract assumes a procedure next_line that goes to the next line on input. Coroutines fit well with the other concepts of object-oriented software construction. Note how decentralized the above scheme is: each process minds its own business, with limited interference from the others. The producer takes care of generating candidates from the input; the printer takes care of the output; the controller takes care of when to start and finish. As usual, a good check of the quality of the solution is the ease of extension and modification; it is indeed straightforward here to add a coroutine that will check for end of input (as requested by an exercise). Coroutines take decentralization, the hallmark of O-O architectures, one step further. The architecture could be made even more decentralized. In particular, the processes in the above structure must still activate each other by name; ideally they should not have to know about each other except to communicate requested information (as when the printer obtains last_input from the producer). The simulation primitives studied below allow this; after that, the solution is to use a full concurrency mechanism, such as described in an earlier chapter. As you will remember, its platform-independence means that it will work for coroutines as well as true parallelism. Sequencing and inheritance Even if it does not use coroutine mechanisms (detach, resume), a Simula class may have a body (a sequence of instructions) in addition to its features, and so may take on the behavior of a process in addition to its usual role as an abstract data type implementation. When combined with inheritance, this property leads to a simpler version of what the discussion of concurrency called the inheritance anomaly, to which Simula, thanks to its limitation to single rather than multiple inheritance and coroutines rather than full parallelism, is able to provide a language solution. For a class C let bodyC be the sequence of instructions declared as body of C and actual_bodyC the sequence of instructions executed for every creation of an instance of C. If C has no parent, actual_bodyC is just bodyC. If C has a parent A (it can have at most one) then actual_bodyC is by default the sequence of instructions actual_bodyA; bodyC In other words, ancestors’ bodies are executed in the order of inheritance. But this default may not be what you want. To supersede it, Simula offers the inner instruction which denotes the heir’s body, so that the default policy is equivalent to having an inner at the end of the parent’s body. If instead you write the body of A as instructions1; inner; instructions2 then (assuming A itself has no parent) the execution of C will execute not its bodyC as written in the class but its actual_bodyC defined as instructions1; bodyC; instructions2 On the use of a concurrency mechanism to describe coroutines see “Coroutines”, page 1012. “Synchronization for concurrent O-O computation”, page 980
1122 SIMULA TO JAVA AND BEYOND:MAJOR O-O LANGUAGES AND ENVIRONMENTS $35.1 Although the reasons for this facility are clear,the convention is rather awkward: In many cases descendants would need to create their instances differently from their ancestors.(Remember POLYGON and RECTANGLE.) Bodies of descendants,such as C here,become hard to understand:just reading bodyc does not really tell you what the execution will do. In addition,of course,the convention would not transpose easily to multiple inheritance,although this is not an immediate concern in Simula. Such difficulties with inner are typical of the consequences of making objects “Active objects active,as we found out when discussing concurrency. clash with inherit- ance".page 959. Almost all object-oriented languages after Simula have departed from the inner convention and treated object initialization as a procedure. Simulation True to its origins,Simula includes a set of primitives for discrete-event simulation.It is no accident,of course,that the first O-O language was initially meant for simulation applications;more than in any other area,this is where the modeling power of the object- oriented method can illustrate itself. A simulation software system analyzes and predicts the behavior of some external system-an assembly line,a chemical reaction,a computer operating system,a ship... A discrete-event simulation software system simulates such an external system as having,at any time,a state that can change in response to events occurring at discrete instants.This differs from continuous simulation,which views the state as continuously evolving.Which of these two modeling techniques is best for a given external system depends not so much on whether the system is inherently continuous or discrete (often a meaningless question)as on what models we are able to devise for it. Another competitor to discrete-event simulation is analytical modeling,whereby you simply build a mathematical model of the external system,then solve the equations. This is a very different approach.With discrete-event simulation,you run a software system whose behavior simulates the behavior of the external system:to get more significant results,you will increase the length of the period that you simulate in the external system's life,and so you will run the simulation longer.This is why analytical models are usually more efficient.But many physical systems are too complex to admit realistic yet tractable mathematical models;then simulation is the only possibility Many external systems lend themselves naturally to discrete event simulation.An example is an assembly line,where typical events may include a new part being entered into the line,a worker or machine performing a certain operation on one or more parts,a finished product being removed from the line,a failure causing the line to stop.You may use the simulation to answer questions about the modeled physical systems:how long does it take (average,minimum,maximum,standard deviation)to produce a finished
1122 SIMULA TO JAVA AND BEYOND: MAJOR O-O LANGUAGES AND ENVIRONMENTS §35.1 Although the reasons for this facility are clear, the convention is rather awkward: • In many cases descendants would need to create their instances differently from their ancestors. (Remember POLYGON and RECTANGLE.) • Bodies of descendants, such as C here, become hard to understand: just reading bodyC does not really tell you what the execution will do. • In addition, of course, the convention would not transpose easily to multiple inheritance, although this is not an immediate concern in Simula. Such difficulties with inner are typical of the consequences of making objects active, as we found out when discussing concurrency. Almost all object-oriented languages after Simula have departed from the inner convention and treated object initialization as a procedure. Simulation True to its origins, Simula includes a set of primitives for discrete-event simulation. It is no accident, of course, that the first O-O language was initially meant for simulation applications; more than in any other area, this is where the modeling power of the objectoriented method can illustrate itself. A simulation software system analyzes and predicts the behavior of some external system — an assembly line, a chemical reaction, a computer operating system, a ship… A discrete-event simulation software system simulates such an external system as having, at any time, a state that can change in response to events occurring at discrete instants. This differs from continuous simulation, which views the state as continuously evolving. Which of these two modeling techniques is best for a given external system depends not so much on whether the system is inherently continuous or discrete (often a meaningless question) as on what models we are able to devise for it. Another competitor to discrete-event simulation is analytical modeling, whereby you simply build a mathematical model of the external system, then solve the equations. This is a very different approach. With discrete-event simulation, you run a software system whose behavior simulates the behavior of the external system: to get more significant results, you will increase the length of the period that you simulate in the external system’s life, and so you will run the simulation longer. This is why analytical models are usually more efficient. But many physical systems are too complex to admit realistic yet tractable mathematical models; then simulation is the only possibility. Many external systems lend themselves naturally to discrete event simulation. An example is an assembly line, where typical events may include a new part being entered into the line, a worker or machine performing a certain operation on one or more parts, a finished product being removed from the line, a failure causing the line to stop. You may use the simulation to answer questions about the modeled physical systems: how long does it take (average, minimum, maximum, standard deviation) to produce a finished “Active objects clash with inheritance”, page 959