From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-1.3 required=5.0 tests=BAYES_00,INVALID_MSGID autolearn=no autolearn_force=no version=3.4.4 X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: 103376,4a1a5f232d1bd597,start X-Google-Attributes: gid103376,public From: Richard Irvine Subject: Interface using abstract types Date: 1996/07/04 Message-ID: <31DBC61D.1B44@eurocontrol.fr>#1/1 X-Deja-AN: 163668801 cc: irv@eurocontrol.fr content-type: text/plain; charset=us-ascii organization: Eurocontrol Experimental Centre, Bretigny-Sur-Orge, France mime-version: 1.0 newsgroups: comp.lang.ada x-mailer: Mozilla 2.0 (X11; I; HP-UX A.09.05 9000/755) Date: 1996-07-04T00:00:00+00:00 List-Id: Apologies in advance for the length of this posting. We are designing a subsystem which might be bound into a number of client applications. We wish to define the subprograms which the client application must provide for our purposes. e.g. We define type Abstract1 is abstract tagged null record; procedure anOperation(on : in out Abstract1) is abstract; type Abstract2 is abstract tagged null record; procedure doSomethingWith ( aThing : in out Abstract2; andSomethingElse : in Abstract1'Class ) is abstract; and the client application provides type ClientXConcrete1 is new Abstract1 with ...; procedure anOperation(on : in out ClientXConcrete1); type ClientXConcrete2 is new Abstract2 with ...; procedure doSomethingWith ( aThing : in out ClientXConcrete2; andSomethingElse : in Abstract1'Class); The type of the parameter andSomethingElse in the concrete version of doSomethingWith must be Abstract1'Class in order to conform with the abstract version. However, we really only want the client application to have to provide operations which are valid for its set of types, rather than for the entire class. Furthermore, the operations on Abstract1 are those needed by our subsystem for its purposes. To provide an implementation of doSomethingWith the client may need to use additional operations on its descendant of Abstract1. However, it cannot do this and still conform to the abstract doSomethingWith. So it seems that when defining the abstract doSomethingWith we should not have had a parameter of type Abstract1'Class. A possible solution to this problem is as follows: package abstract1package is -- an abstract type to which the client application must conform type Abstract1 is abstract tagged null record; end; with abstract1package; use abstract1package; package clientx.concrete1package is -- a particular client application's implementation of the abstract type type Concrete1 is new Abstract1 with ...; end; -- hide the name of the client whose concrete types we are using with clientx.concrete1package; package customisation.concrete1package renames clientx.concrete1package; with customisation.concrete1package; use customisation.concrete1package; package abstract2package is type Abstract2 is abstract tagged null record; -- specify the operation on Abstract2 using a parameter of a -- concrete type without knowing which client is providing it procedure doSomethingWith ( aThing : in out Abstract2; andSomethingElse : in Concrete1'Class ); end; -- a client's implementation of Abstract2 with abstract2package; use abstract2package; with customisation.concrete1package; use customisation.concrete1package; package clientx.concrete2package is type Concrete2 is new Abstract2 with ...; procedure doSomethingWith ( aThing : in out Concrete2; andSomethingElse : in Concrete1'Class ); end; -- once again hide the name of the client providing the implementation with clientx.concrete2package; package customisation.concrete2package renames clientx.concrete2package; -- finally an example of part of a subsystem with customisation.concrete1package; use customisation.concrete1package; with customisation.concrete2package; use customisation.concrete2package; procedure framework ( aConcrete1 : in Concrete1; aConcrete2 : in out Concrete2 ) is begin doSomethingWith (aThing => aConcrete2, andSomethingElse => aConcrete1); end; The advantage of this scheme is that we specify using abstract types what the client must provide, while the client is free to write operations which are valid for its set of types. Which client's types are being used can be switched in the rename clauses. While not altogether ugly this does seem like a rather roundabout scheme. Have we missed the point, is there a better way of doing things?