Kategorie: Uncategorized

  • object oriented pl/i

     

    OBJECT-ORIENTED PL/I

    Discussion paper by Peter Elderon.

    From comp.lang.pl1 Sat Nov 23 14:13:20 1996
    From: Dave Jones <djones@starbase.neosoft.com>
    Newsgroups: comp.lang.pl1
    Subject: Ptere Elderon's OO-PL/I presentation.
    Date: Mon, 18 Nov 1996 13:51:04 -0600
    Organization: NeoSoft, Inc.

    INTRODUCTION

    A class consist of objects and the operations (also known as methods) that may be performed on such objects. Classes of- fer the following features:

    • data encapsulation

      Classes „hide“ the data that represent an object (also commonly known as an „instance“) of a class and expose only the methods that can be applied to it.

    • inheritance

      Classes also allow new, more specialized, classes to be developed from existing classes.

    • polymorphism

      When you define a subclass, you may also override the methods defined in your parent classes. Then when ap- plying a method to an object of a class (or one of its subclasses), which actual method is invoked will depend on the actual class to which the object belongs and whether that class overrode the parent class’s method.

    In some object-oriented languages, the cost of method invo- cation is kept to a minimum but at the expense of what is sometimes called „fragile superclasses“: changes to a class require all users and subclasses of that class to be recom- piled.

    In PL/I, class users and subclasses need not be recompiled if

    1. 1. new methods are added to a class
    2. 2. new instance variables are added to a class

    This is what you would expect from a math library, for in- stance.

    PL/I also clearly separates the client’s view of a class from the implementer’s by defining a class via:

    1. 1. a statement that defines the client’s view:
      • o the class’s parentage
      • o the operations that may be performed on its objects (these operations are also known as „instance methods“)
    2. 2. a package that defines the implementation:
      • o what parent class methods have been overridden
      • o the implementation of its instance methods
      • o the implementation of the overridden methods
      • o its „private“ instance data

    THE CLIENT’S VIEW OF A CLASS

    The statement that defines the client’s view of a class is the DEFINE CLASS statement, which would typically be in an include file. It has the syntax:

     
          DEFINE
            CLASS
    
              INHERITS (  )
              METHODS (  ) ;

    The INHERITS clause names this class’s parent. Every PL/I class is a subclass of the PL/I-provided Object class (ex- cept, of course, the Object class itself). Note also that a class may have only one parent; like Smalltalk and Java, object-oriented PL/I supports only single inheritance.

    The METHODS clause names the operations permitted on objects of this class. These methods are the only way a client can manipulate objects of this class. There is no public or pro- tected data: all data is encapsulated by methods.

    For example, the following statement defines a „student“ class

     
          define
            class
              student
              inherits( object )
              methods
                (
                  setUp entry( char(64) varying,
                                char(6) )
    
                 ,get_Id entry() returns( char(6) )
    
                 ,get_Name entry() returns( char(64) varying )
    
                 ,print entry()
                );

    CLASS INSTANCES

    The DEFINE CLASS statement shares some important similari- ties with the DEFINE STRUCTURE statement.

    The name appearing in the specification of a HANDLE attri- bute may be the name specified in a DEFINE STRUCTURE state- ment or in a DEFINE CLASS statement. A variable declared as a HANDLE for a class is also known as an instance of that class.

    Just as the only access to the elements in a defined struc- ture is via the => operator applied to a handle to that structure, the only access to the methods in a defined class is is via the => operator applied to a handle to that class.

    For instance, given the student class in the example above, the following statements declare an instance of that class and invoke the setup method for that class.

    dcl  s  handle student;
    
           call s=>setUp( 'Z. Dobson', '030507' );

    The example above is incomplete since before you apply a method to an object, the object must be instantiated. The primary way to instantiate an object is via the NEW type function applied to the name of that class. So the example above could be completed to look like:

     
           dcl  s  handle student;
    
           s = new(: student :);
           call s=>setUp( 'Z. Dobson', '030507' );
    So just as for defined structures, storage for defined classes is obtained via the new type function.

    If an instance of a class is obtained via the new function, it should be destroyed by applying to it the delete method from the PL/I object class. So the student instance ob- tained above could be destroyed via

     
           call s=>delete();

    THE IMPLEMENTER’S VIEW OF A CLASS

    A PL/I package implements a class by specifying the name of the class in the OWNS clause of the PACKAGE statement. For instance, the following statement indicates that this pack- age implements the student class:

    student: package owns( student );

    A package that owns a class must contain a DEFINE CLASS statement for that class.

    A package that owns a class must also define any private data for a class via the DEFINE INSTANCE statement:

     
          DEFINE
            INSTANCE
    
              (  ) ;
    The DEFINE INSTANCE statement is valid only inside a package that owns the class whose data that it defines.

    The declaration commalist in the define instance statement must specify must specify either a scalar or a structure or an array thereof.

     

    QUESTION: should a list of scalars and/or structures be allowed??

    A package that owns a class must implement all the methods in that class by containing a level-one procedure for each method defined by the class. Note that these procedures are not exported from the package; they cannot be invoked from outside or inside the package except via a handle.

    As indicated earlier, PL/I allows new methods and variables to be added to a parent class without „damaging“ any of is subclasses or clients. This implies that classes must be created at run-time. The compiler generates all the code to do this. The actual creation of the class occurs in the PL/I package that owns the class.

    The code generated by the compiler produces several external names built using the name of the class:

    • o NewClass
    • o ClassData
    • oCClassDataThis name is generated only if the PL/I object class is the SOM object class
    Each method implemented by a class receives one undeclared byvalue parameter, which can be referenced by the built-in function SELF. SELF is a handle for the class being imple- mented and can be used to access instance data as well as to invoke methods. For instance, the following code implements the student class:
     
          student:
            package
            owns( student );
    
            %include class;
            %include student;
    
            dcl self builtin;
    
            define
              instance
                student
                 ( 1 student_data
                    ,2 student_id      char(6)
                    ,2 student_name    char(64) varying
                 )
              ;
    
            setUp: proc( name, id );
    
              dcl name char(64) varying;
              dcl id   char(6);
    
              self=>student_id = id;
              self=>student_name = name;
            end;
    
            get_Id: proc returns( char(6) );
    
              return( self=>student_id );
            end;
    
            get_Name: proc returns( char(64) varying );
    
              return( self=>student_name );
            end;
    
            print: proc;
    
              put skip edit( ' id', ': ',
                             self=>student_id ) (a(12),a,a );
              put skip edit( ' name', ': ',
                             self=>student_name ) (a(12),a,a );
            end;
    
          end student;
    A package that owns a class may also override methods in its parents' classes. The DEFINE OVERRIDES statement indicates which parent methods a class will override:
     
          DEFINE
            OVERRIDES
    
              (  ) ;
    The DEFINE OVERRIDES statement is valid only inside a pack- age that owns the class named in it. This package must also contain a level-one procedure for each method overridden by the class.

    A method may often want to override a parent method in order to perform some special processing before or after the normal processing performed by the parent method. In order to be able to do this, it must be possible to specify that the method that should be applied to self is that defined by its parent. The PARENT built-in function provides this ability.

    For instance, if a subclass of the student class overrode the student print method because it wanted to print addi- tional data belonging to the subclass, the first thing the subclass print method might want to do is invoke the student print method as in the following example:

     
           print: proc;
             call parent=>print();
             /* use self to print additional data */
           end;

    THE PL/I OBJECT CLASS

    Every class has the object class as its root class. The ob- ject class defines a set of common methods that can be ap- plied to all class instances.

    The object class define statement is

     
              define
                class
                  object
                  methods
                    (
                       delete entry()
                       /* used to destroy an instance of a class   */
                       /* it will invoke the uninit method         */
    
                    ,  init entry()
                       /* invoked when an instance is created      */
                       /* the class object version does nothing    */
                       /* but exist in order to be overridden      */
    
                    ,  uninit entry()
                       /* invoked when an instance is destroyed    */
                       /* the class object version does nothing    */
                       /* but exist in order to be overridden      */
    
                    );

    CONFORMANCE

    Only a handle may be assigned only to another handle But the source in such an assignment should be a handle of the target handle's class or one of its subclasses

    For example, given the student class with two derived classes, undergrad and graduate, consider

     
               dcl s handle student;
               dcl u handle undergrad;
               dcl g handle graduate;
    
               ...
               s = u;  /* valid */
               u = s;  /* valid */
    
               ...
               s = g;  /* valid */
               u = s;  /* invalid */
    A new condition CONFORMANCE, which can be disabled or enabled like SUBSCRIPTRANGE, will be raised when enabled if such an invalid assignment is attempted.

    CONSTRUCTORS

    QUESTION: Should constructors be supported??

    In examples used above, the student class has a method, setUp, that can be used to initialize its instance data. However, the student class could be defined with a constructor that would be invoked to perform this initialization.

    If a method list for a class contains a method with the same name as the class name, that method is called a constructor. The constructor will be invoked when the new function is invoked, and if the constructor requires parameters, the new function must be invoked with the necessary additional arguments. For instance, the student class above could be defined via

     
          define
            class
              student
              inherits( object )
              methods
                (
                  student entry( char(64) varying,
                                 char(6) )
    
                 ,get_Id entry() returns( char(6) )
    
                 ,get_Name entry() returns( char(64) varying )
    
                 ,print entry()
                );
    The student class would then be instantiated via
     
          dcl s handle student;
          s = new(: student, 'Z. Dobson', '030507' :);
    Constructor methods cannot be invoked directly except a constructor method itself may invoke via the parent builtin the constructor for its parent class.

    AN EXAMPLE WITH INHERITANCE AND POLYMORPHISM

    Using the student class above, two different subclasses could be defined for it via the statements:
     
          define
            class
              undergrad
              inherits( student )
              methods
                (
                  setUp_Undergrad entry( char(64) varying,
                                         char(6),
                                         char(8) )
                );
    
          define
            class
              graduate
              inherits( student )
              methods
                (
                  setUp_Grad entry( char(64) varying,
                                    char(6),
                                    char(8) )
                );
    The implementation of the undergrad class could be
     
    
          undergrad: package owns( undergrad );
    
            %include class;
            %include student;
            %include undergrad;
    
            dcl self builtin;
            dcl parent builtin;
    
            define
              instance
                undergrad
                 (
                    underGradDate char(8)
                 )
              ;
    
            define
              overrides
                undergrad
                 (
                    print
                 )
              ;
    
            setUp_Undergrad: proc( name, id, graddate );
    
              dcl name char(64) varying;
              dcl id   char(6);
              dcl gradDate char(8);
    
              call self=>setup( name, id );
              self=>UnderGradDate = graddate;
            end;
    
            print: proc;
    
              call parent=>print;
              put skip edit( ' grad date', ': ', self=>undergradDate )
                           ( a(12), a, a );
            end;
    
          end undergrad;
    While the implementation of the graduate class could be
     
          graduate: package owns(graduate);
    
            %include class;
            %include student;
            %include graduate;
    
            dcl self builtin;
            dcl parent builtin;
    
            define
              instance
                graduate
                 (
                    gradDegree char(8)
                 )
              ;
    
            define
              overrides
                graduate
                 (
                    print
                 )
              ;
    
            setup_Grad: proc( name, id, degree );
    
              dcl name char(64) varying;
              dcl id   char(6);
              dcl degree char(8);
    
              call self=>setup( name, id );
              self=>GradDegree = degree;
            end;
    
            print: proc;
    
              call parent=>print;
              put skip edit( ' degree', ': ', self=>gradDegree )
                           ( a(12), a, a );
            end;
    
          end graduate;

    The following code is client code using these classes. It obtains an instance of the undergrad class, initializes it and saves the handle for that instance in an array of stu- dent handles. It then obtains an instance of the graduate class, initializes it and saves the handle for that instance in the same array of student handles. Finally it loops through that array and prints the data for each student. The print function is polymorphic since the two subclasses have

    each overridden it: when applied to a student handle it will call the print method for the undergrad or graduate class in accordance with the class to which the handle actually points.

    So the output of the following program would be, thanks to polymorphism:

     

     
    
             id          : 030507
             name        : Z. Dobson
             grad data   : 19550611
    
             id          : 111317
             name        : L. Jim
             degree      : Ph. D.
     
          registrar: proc;
    
            %include class;
            %include student;
            %include undergrad;
            %include graduate;
    
            dcl s(20) handle student;
            dcl u     handle undergrad;
            dcl g     handle graduate;
            dcl c     fixed bin(31) init(0);
            dcl jx    fixed bin(31);
    
            /* add a sample undergrad student */
            c = c + 1;
            u = new(: undergrad :);
            call u=>setUp_Undergrad( 'Z. Dobson', '030507', '19550611' );
            s(c) = u;
    
            /* add a sample graduate student */
            c = c + 1;
            g = new(: graduate :);
            call g=>setUp_Graduate( 'L. Jim', '111317', 'Ph. D.' );
            s(c) = g;
    
            /* print out all the students */
            do jx = 1 to c;
              call s(jx)=>print();
              put skip;
            end;
          end;

  • schwertberg

    Sehr geehrte Damen und Herren!

    Mit einigem Erstaunen habe ich gelesen, dass sich praktisch alle Fraktionen im Gemeinderat von Schwertberg