Object-Oriented and Concurrent Program Design Issues in Ada 95
Total Page:16
File Type:pdf, Size:1020Kb
Object-Oriented and Concurrent Program Design Issues in Ada 95 Stephen H. Kaisler Michael B. Feldman Director, Systems Architecture Professor of Engineering and Applied Science Office of the Sergeant at Arms Dept. of Electrical Engineering and Computer Science United States Senate George Washington University Washington, DC 20510 Washington, DC 20052 202-224-2582 202-994-6083 [email protected] [email protected] 1. ABSTRACT Kaisler [4] identified several design issues that arose 2. INTRODUCTION from developing a process for transforming object- oriented programs written in Ada 95 or other object- Kaisler [4] described research leading to a methodology oriented programming languages to process-oriented for converting object-oriented programs to process- programs written in Ada 95. These issues limit - in the oriented programs and, thereby, making the concurrency authors' opinion - the flexibility of Ada 95 in writing implicit in object-oriented programs explicit. This concurrent programs. These problems arise from research was motivated by the fact that writing specific decisions made by the Ada 95 designers. This concurrent programs is difficult to do - no general paper addresses three of these issues: circular methodology exists - and by our recognition of the references are invalid in packages, lack of a similarity between object-oriented and process-oriented subclassing mechanism for protected types, and an programs. inability to internally invoke access statements from within a task body. Our goal is to raise the Ada 95 We believed that object-oriented programs, which exhibit community's awareness concerning these design issues a potential for concurrency, could be converted to and provide some suggestions for correcting these process-oriented programs, thereby making the problems for a future revision of the Ada concurrency explicit. Object-oriented programs exhibit programming language. the property of encapsulation, i.e., that attributes and methods of a class are defined in a single syntactic structure. Similarly, process-oriented programs also exhibit encapsulation within the process or task structure. Message passing is a basic mechanism for communication within object-oriented and process- oriented programs. Analysis of these features suggested that object-oriented programs could be converted to process-oriented programs with no loss of functionality. Rather than writing concurrent programs anew, our work focused on reusing the source code and logic of an object- oriented program to develop the process-oriented program. We developed a methodology and transformation algorithms for converting both the structure and the procedural code of the object-oriented program to the corresponding components of a process- oriented program. However, as we applied the methodology and the const for_check_test : BOOL := true; algorithms to several programs written in Ada 95 and other object-oriented programming languages (OOPLs), -- Attributes that are specific to a PIECE we discovered several limitations of Ada 95 that arise attr alive : BOOL; from specific decisions made during the language design attr iswhite : BOOL; process. This paper describes three of these limitations attr position : POS; and proposes some possible modifications to the Ada programming language for consideration in a future -- Constants that are specific to a PIECE revision. const worth : INT := 0; 3. CIRCULAR REFERENCES IN ADA 95 const fig : CHAR := ' '; PACKAGES const ispawn : BOOL := false; const isking : BOOL := false; Perhaps the most constraining feature of Ada 95 is its const isrook : BOOL := false; inability to support circular package references among two or more packages. In C++ [9], references may be ••• <other code omitted here!> made both forward and backward to other class definitions, which can result in circular references valid_move(to:POS,board:BOARD):BOOL is ret : BOOL := false; between two files containing C++ class definitions. The loop C++ compiler notes the occurrence of such circular valid_to::=move!(board,ordinary); references and generates the appropriate code without if to=valid_to entering an infinite loop. Circular references between then ret:=true; objects seem to be a natural outcome of O-O analysis and break!; design methodologies. Circular references are allowed end; between Eiffel types [5, 6], Sather classes [7], and end; Common Lisp objects [8] among other modern object- return ret; oriented programming languages. end; An example of a circular reference from the Sather 1.0 Figure 1a. PIECE Class Declaration chess program, a demonstration program from the Sather distribution, is depicted in figures 1(a) and 1(b). class BOARD is type $PIECE is alive:BOOL; private attr whitepieces : ARRAY{$PIECE}; alive(set:BOOL); private attr blackpieces : ARRAY{$PIECE}; worth:INT; iswhite:BOOL; -- The board stores information about which color position:POS; -- is to play next. valid_move(to:POS,board:BOARD):BOOL; update_position(position:POS); ••• <other code omitted here!> update_position(position:STR); move!(b:BOARD,to_piece:BOOL):POS; private move_valid_so_far(move:MOVE):BOOL fig:CHAR; pre ~move.isquit ispawn : BOOL; is isrook : BOOL; ret : BOOL := false; isking : BOOL; end; -- of type $PIECE -- A valid move must start at a position where -- one of my pieces is.... ----------------------------------------------------------------- class PIECE < $PIECE is if has_my_piece(move.from) then -- General constants that are used throughout p::=piece(move.from); -- the descendants of $PIECE -- ... and it must be a valid move with respect const white : BOOL := true; -- to the mobility of the piece at the current const black : BOOL := ~white; -- state of the board. const ordinary : BOOL := false; -- alters behavior of move! if p.valid_move(move.to, self) then short vScale; ret := true; // Location of frame in Panorama -- LongPt position; -- since the move seems to be valid, // Save for later restoration -- the moving piece is stored LongPt savePosition; -- in the move object. That eases future -- access to the moving piece // Here is the circular reference!! -- and allows for un-doing of moves. // Scroll pane for this Panorama move.piece := p; CScrollPane *itsScrollPane; end; // Member Functions end; // Construction/Destruction return ret; end; CPanorama(); CPanorama(CView *anEnclosure, Figure 1b. BOARD Class Declaration CBureaucrat *aSupervisor, short aWidth = 0, short aHeight = 0, short aHEncl = 0, short aVEncl = 0, The corresponding references in the two classes depicted SizingOption aHSizing = sizELASTIC, in the figure above are highlighted in bold. The SizingOption aVSizing = sizELASTIC); individual chess pieces (pawn, knight, rook and so forth) each inherit attributes and methods from the class <Other declarations of methods - not relevant here> PIECE. Because PIECE references the BOARD class }; through typing of arguments to its methods, each of the objects for the chess pieces must also do so. The BOARD Figure 2(a). C++ Header for Panorama Class class references the PIECE class directly in the array declarations and objects for each chess piece class through dynamic dispatching from the statement: class CScrollPane : public CPane { // class DECLARATION if p.valid_move(move.to, self) then public: ••• // Data Members where P is an instance of a chess piece class which has // Here is the circular reference !! inherited valid_move from the PIECE class. P takes as its value a handle of one of the instances of the chess pieces. CPanorama *itsPanorama; // View which scrolls So, at run-time, the appropriate implementation of CScrollBar *itsHorizSBar; // Horizontal scroll bar valid_move is determined by the class to which P CScrollBar *itsVertSBar; // Vertical scroll bar belongs. CSizeBox *itsSizeBox; // Grow box long hExtent; Figures 2(a) and 2(b) depict the headers for C++ files for long vExtent; Panorama and Scrollpane that demonstrate a circular short hUnit; reference used in a user interface application. As before, short vUnit; short hSpan; the circular references are highlighted in bold. short vSpan; short hStep; class CPanorama : public CPane short vStep; { // Class Declaration short hOverlap; short vOverlap; public: // Member Functions // Data Members // Construction/Destruction // Bounds defining Pane coordinates CScrollPane(); LongRectbounds; CScrollPane(CView *anEnclosure, // Pixels per horizontal unit CBureaucrat *aSupervisor, short hScale; short aWidth, short aHeight, // Pixels per vertical unit short aHEncl, short aVEncl, SizingOption aHSizing, SizingOption aVSizing, Boolean hasHoriz, type UI_Scrollpane_Root is Boolean hasVert, access all UI_Scrollpane_Root_Record'Class; Boolean hasSizeBox); subtype Any_Scrollpane_Root is UI_Scrollpane_Root; <Other declarations of methods - not relevant here > }; end ui_scrollpane_root; Figure 2(b). C++ Header for Scrollpane Class Figure 3(a). Scrollpane Root Class Ada 95 does not allow circular references between packages because all packages are elaborated prior to the package ui_scrollpane is beginning of execution. Circular references would occur when one package WITHs another package and the type UI_Scrollpane_Record is second package attempts to WITH the first package. In new UI_Scrollpane_Root_Record with Ada 95, circular references are detected at compile time record myPanorama: Any_Panorama; with an error message; compilation is terminated. Using end record; the methodology and transformation algorithms in [4], we converted the above code to Ada 95. Upon type UI_ScrollPane