-------------------------------------------------------------------------- Object-Oriented Systems Fall 1994 COM3360 Karl Lieberherr --------------------------------------------------------------------------- Midterm Question 1: 15 UNKNOWNS, 3 points each 45 Question 2: 11 UNKNOWNS, 3 points each 33 Question 3: 30 UNKNOWNS, 2 points each 60 Question 4: 17 UNKNOWNS, 4 points each 68 206 total --------------------------------------------------------------------------- Open book and open notes. To make the grading easier, please put your values for the unknowns on the enclosed answer sheet. THE GAME OF REDUNDANCY AND UNKNOWNS ----------------------------------- Most of the questions in this exam ask you to determine unknowns of the form UNKNOWN1, UNKNOWN2, ... This makes it easier for you to answer the questions, since you get extra context information. Yet you need to master the behavioral objectives of the course to answer the questions. Guessing an answer is not a successful strategy and therefore a "game of redundancy" test is more interesting than a multiple choice test. The questions have the following pattern: I show you several artifacts which are related by the theory of object-oriented design and programming. Because of the dependencies between the artifacts, some of the information is redundant and can be recovered from the context by applying the objectives covered in the course. The information which you should discover is marked UNKNOWNx. If an unknown is not uniquely determined, mark the answer with *CHOICE*. An unknown may be anything, e.g., a number, an identifier, a character, two identifiers with a blank between them, a string etc. If an unknown is the empty string, give NOTHING as answer, e.g., UNKNOWN = NOTHING. Example: 5 + UNKNOWN1 = 8 UNKNOWN1 = 3 --------------- UNKNOWN2 * UNKNOWN3 = 20 UNKNOWN2 = 4 *CHOICE* UNKNOWN3 = 5 *CHOICE* At the beginning of a question we give the number of points per unknown. Question 1: =================================================================== 15 UNKNOWNS, 3 points each (directory c-oopsla94) The program below separates the phones into phones which are either on-hook or off-hook. You are given the propagation patterns, object graph (in textual form) and you are asked to determine the propagation graph and a C++ member function. The propagation patterns are: (concatenate has the following definition obtained with the command man Repetition void concatenate( repetition* lst ); Destructively appends lst to the end of the receiver list. The original list is contained in the result.) *operation* Phone_List* find_phones_on_hook() *init* (@ new Phone_List(); @) *traverse* *from* Building *to* Phone *wrapper* Phone *prefix* (@ return_val -> concatenate( this -> find_phones_on_hook(this)); @) *operation* Phone_List* find_phones_on_hook(Phone* p) *init* (@ new Phone_List(); @) *traverse* *from* Phone *to* OnHook *wrapper* OnHook *prefix* (@ return_val -> append(p); @) *operation* Phone_List* find_phones_off_hook() *init* (@ new Phone_List(); @) *traverse* *from* Building *to* Phone *wrapper* Phone *prefix* (@ return_val -> concatenate( this -> find_phones_off_hook(this)); @) *operation* Phone_List* find_phones_off_hook(Phone* p) *init* (@ new Phone_List(); @) *traverse* *from* Phone *to* OffHook *wrapper* OffHook *prefix* (@ return_val -> append(p); @) The input object graph is: : Building ( < phones > : Phone_List { : HomePhone ( < status > : Hardware ( < status > : Status ( < ringingStatus > : Ringing ( ) < hookStatus > : OnHook ( ) < talkingStatus > : NonTalking ( ) ) ) ) , : BusinessPhone ( < status > : Hardware ( < status > : Status ( < ringingStatus > : NonRinging ( ) < hookStatus > : OffHook ( ) < talkingStatus > : Talking ( ) ) ) ) , : HomePhone ( < status > : Hardware ( < status > : Status ( < ringingStatus > : NonRinging ( ) < hookStatus > : OnHook ( ) < talkingStatus > : NonTalking ( ) ) ) ) } ) Traversal directive: *from* { Building } *to* { Phone } Propagation graph for traversal: *source* { Building } *target* { Phone } *paths* UNKNOWN1 = UNKNOWN2. UNKNOWN3 : . UNKNOWN4 Traversal directive: *from* { Phone } *to* { OffHook } Propagation graph for traversal: *source* { Phone } *target* { OffHook } *paths* Phone : UNKNOWN5. UNKNOWN6 = < status > Status . UNKNOWN7 = < UNKNOWN8 > HookStatus . UNKNOWN9 UNKNOWN10 = . BusinessPhone = < status > Hardware . HomePhone = < status > Hardware. Find the UNKNOWNs in the following C++ member function which is generated: void UNKNOWN11::find_phones_on_hook_( Phone_List* & return_val ) { // outgoing calls UNKNOWN12 UNKNOWN13(*this); Phone* UNKNOWN14; while ( each_Phone = next_Phone() ) { UNKNOWN15->find_phones_on_hook_( return_val ); } } Question 2: ================================================================== 11 UNKNOWNS, 3 points each (directory c-oopsla94) Parsing from several files. The main program fragment below is a test program for testing whether the result object is equal to the expected output. Such a program is useful as part of a regression test. The result object is computed by method find_phones_off_hook. The expected output is stored in file expected as a sentence. If the result object is equal to the expected object, the message SUCCESS is printed and else the message FAILURE. We want to call the main program with: run demeter-input expected or run demeter-input In either case, file expected is used as input file. Find the UNKNOWNS below. //---------------------------------------- // Your own code follows after this //---------------------------------------- Phone_List* result = iBuilding -> find_phones_off_hook(); cout << "\n*** PHONES OFF HOOK ***\n" << result << endl; UNKNOWN1* expected = new UNKNOWN2(); if( UNKNOWN3 >= 3 ) expected = (UNKNOWN4*)UNKNOWN5->g_parse( UNKNOWN6[2] ); else expected = (UNKNOWN7*)UNKNOWN8->g_parse( "UNKNOWN9" ); if ( expected == NULL ) { cerr << "Parser error." << endl; exit(1); } cout << endl; if( UNKNOWN10->UNKNOWN11( expected ) ) cout << "SUCCESS"; else cout << "FAILURE"; cout << endl; Question 3: =================================================================== 30 UNKNOWNS, 2 points each (directory c-oopsla94) Adaptiveness through parsing. When you print the following object graph with g_print: : Building ( < phones > : Phone_List { : HomePhone ( < status > : Hardware ( < status > : Status ( < ringingStatus > : Ringing ( ) < hookStatus > : OnHook ( ) < talkingStatus > : NonTalking ( ) ) ) ) , : BusinessPhone ( < status > : Hardware ( < status > : Status ( < ringingStatus > : NonRinging ( ) < hookStatus > : OffHook ( ) < talkingStatus > : Talking ( ) ) ) ) , : HomePhone ( < status > : Hardware ( < status > : Status ( < ringingStatus > : NonRinging ( ) < hookStatus > : OnHook ( ) < talkingStatus > : NonTalking ( ) ) ) ) } ) the following sentence is printed: ( home phone ringing on-hook non-talking phone quiet off-hook talking home phone quiet on-hook non-talking ) which corresponds to the object built in variable iBuilding20 produced by the C++ program below. UNKNOWN1* UNKNOWN2 = new UNKNOWN3(); HomePhone* iHomePhone2 = new HomePhone( ); Ringing* iRinging3 = new Ringing( ); OnHook* iOnHook4 = new OnHook( ); NonTalking* iNonTalking5 = new NonTalking( ); Status* iStatus6 = new Status( UNKNOWN4,UNKNOWN5,UNKNOWN6 ); Hardware* iHardware7 = new Hardware( UNKNOWN7 ); iHomePhone2->UNKNOWN8(iHardware7 ); iPhone_List1->append( UNKNOWN9 ); BusinessPhone* iBusinessPhone8 = new BusinessPhone( ); NonRinging* iNonRinging9 = new NonRinging( ); OffHook* iOffHook10 = new OffHook( ); Talking* iTalking11 = new Talking( ); Status* iStatus12 = new Status( UNKNOWN10,UNKNOWN11,UNKNOWN12 ); Hardware* iHardware13 = new Hardware( iStatus12 ); iBusinessPhone8->set_status(iHardware13 ); iPhone_List1->append( iBusinessPhone8 ); HomePhone* iHomePhone14 = new HomePhone( ); NonRinging* iNonRinging15 = new NonRinging( ); OnHook* iOnHook16 = new OnHook( ); NonTalking* iNonTalking17 = new NonTalking( ); Status* iStatus18 = new Status( iNonRinging15,iOnHook16,iNonTalking17 ); Hardware* iHardware19 = new Hardware( iStatus18 ); iHomePhone14->UNKNOWN13(iHardware19 ); iPhone_List1->append( iHomePhone14 ); Building* iBuilding20 = new Building( iPhone_List1 ); The corresponding class dictionary is: Building = List(UNKNOWN15). Phone : BusinessPhone | HomePhone *common* UNKNOWN16 Hardware. Hardware = Status. Status = RingingStatus HookStatus TalkingStatus. RingingStatus : UNKNOWN17 | NonRinging. Ringing = UNKNOWN18. NonRinging = UNKNOWN19. HookStatus : UNKNOWN20 | OffHook. OnHook = UNKNOWN21. OffHook = UNKNOWN22. TalkingStatus : UNKNOWN23 | NonTalking. Talking = UNKNOWN24. NonTalking = UNKNOWN25. BusinessPhone = UNKNOWN26. HomePhone = UNKNOWN27. List(S) ~ UNKNOWN28 {UNKNOWN29} UNKNOWN30. Find the UNKNOWNS. Question 4: =================================================================== 17 UNKNOWNS, 4 points each (directory c-oopsla94-2) Program evolution Instead of dealing with the objects in question 1, we want now to work with the following kinds of objects: Drawing the object: Building HAS 1 PART( Phone_List HAS 3 ELEMENTS{ HomePhone HAS 1 PART( Hardware HAS 1 PART( Status HAS 3 PARTS( Ringing HAS 0 PART() HookStatus HAS 0 PART() NonTalking HAS 0 PART()))) BusinessPhone HAS 1 PART( Hardware HAS 1 PART( Status HAS 3 PARTS( NonRinging HAS 0 PART() Missing optional part! Talking HAS 0 PART()))) HomePhone HAS 1 PART( Hardware HAS 1 PART( Status HAS 3 PARTS( NonRinging HAS 0 PART() HookStatus HAS 0 PART() NonTalking HAS 0 PART())))}) End of drawing. Displaying the object as a tree: : Building ( < phones > : Phone_List { : HomePhone ( < status > : Hardware ( < status > : Status ( < ringingStatus > : Ringing ( ) < hookStatus > : HookStatus ( ) < talkingStatus > : NonTalking ( ) ) ) ) , : BusinessPhone ( < status > : Hardware ( < status > : Status ( < ringingStatus > : NonRinging ( ) < talkingStatus > : Talking ( ) ) ) ) , : HomePhone ( < status > : Hardware ( < status > : Status ( < ringingStatus > : NonRinging ( ) < hookStatus > : HookStatus ( ) < talkingStatus > : NonTalking ( ) ) ) ) } ) End of display. (In other words: we have changed the class dictionary. Instead of an alternation class we use now an optional part.) How do you have to change the propagation patterns so that they still properly compute the phones which are on-hook and off-hook as in question 1 On input (as sentence) ( home phone ringing on-hook non-talking phone quiet talking home phone quiet on-hook non-talking ) The operation on-hook should produce the following phone list: *** PHONES ON HOOK *** ( home phone ringing on-hook non-talking home phone quiet on-hook non-talking ) The operation off-hook should produce the following phone list: *** PHONES OFF HOOK *** ( phone quiet talking ) Find the UNKNOWNs below. *operation* Phone_List* find_phones_on_hook() *init* (@ new Phone_List(); @) *traverse* *from* UNKNOWN1 *to* UNKNOWN2 *wrapper* UNKNOWN3 *prefix* (@ return_val -> concatenate(this -> find_phones_on_hook(UNKNOWN4)); @) *operation* Phone_List* find_phones_on_hook(UNKNOWN5* p) *init* (@ new Phone_List(); @) *traverse* *from* UNKNOWN6 *to* UNKNOWN7 *wrapper* UNKNOWN8 *prefix* (@ return_val -> append(p); @) *operation* Phone_List* find_phones_off_hook() *init* (@ new Phone_List(); @) *traverse* *from* UNKNOWN9 *to* UNKNOWN10 *wrapper* UNKNOWN11 *prefix* (@ return_val -> concatenate(this -> find_phones_off_hook(UNKNOWN12)); @) *operation* Phone_List* find_phones_off_hook(UNKNOWN13* p) *init* (@ new Phone_List(); @) *traverse* *from* UNKNOWN14 *to* UNKNOWN15 *wrapper* UNKNOWN16 *prefix* (@ UNKNOWN17 @)