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.9 required=5.0 tests=BAYES_00 autolearn=ham autolearn_force=no version=3.4.4 X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: fac41,c52c30d32b866eae X-Google-Attributes: gidfac41,public X-Google-Thread: 1108a1,c52c30d32b866eae X-Google-Attributes: gid1108a1,public X-Google-Thread: 103376,2ea02452876a15e1 X-Google-Attributes: gid103376,public From: jsa@organon.com (Jon S Anthony) Subject: Re: Real OO Date: 1996/05/09 Message-ID: X-Deja-AN: 153924138 sender: news@organon.com (news) references: organization: Organon Motives, Inc. newsgroups: comp.lang.eiffel,comp.lang.ada,comp.object Date: 1996-05-09T00:00:00+00:00 List-Id: Due to some shenanigans by certain nefarious net denizens, I have been informed that this post did not get out properly. Some places may have received it, and I apologies for any duplicates... /Jon In article donh@syd.csa.com.au (Don Harrison) writes: > Jon, > > Stepping back to your original example, I'd like to clarify a few > things before commenting on it (again). > > :The example in Ada: > : > :package Drivers is > : type Driver is tagged private; > :.... > :end Drivers; > : > :package Drivers.Cars is > : type Car_Driver is new Driver with private; > :.... > :end Drivers.Cars; > : > :package Drivers.Trucks is > : type Truck_Driver is new Driver with private; > :.... > :end Drivers.Trucks; > : > : > : > :with Drivers; use Drivers; > :package Vehicles is > : type Vehicle is tagged private; > : > : procedure Register_Driver (V: Vehicle; D: Driver); > > I assume this syntax is correct. That is, you don't have to say > Driver'Class? The status of D would be clearer, IMO, if you had to > write Driver'Class. Yes, it is "correct", you don't need (and here you pretty clearly do not _want_) to say Driver'Class. As the example was proposed, there is no need to use Driver'Class. Instead of being "clearer", its use would be confusing and probably just plain wrong. > : procedure Renew_Rego_By_Mail (V: Vehicle); > :.... > :end Vehicles; > : > :with Drivers.Cars; use Drivers.Cars; > :package Vehicles.Cars is > : type Car is new Vehicle with private; > : > : procedure Register_Driver (V: Vehicle; D: Car_Driver); > :.... > :end Vehicles.Cars; > : > :with Drivers.Trucks; use Drivers.Trucks; > :package Vehicles.Trucks is > : type Truck is new Vehicle with private; > : > : procedure Register_Driver (T: Truck; D: Truck_Driver); > : procedure Renew_Rego_By_Inspection(T: Truck); > > Presumably, Register_Driver does not override the implementation for Vehicle > because of RM 6.3.1(15) and 8.3(8,9)? Visibility doesn't really enter into it (8.3 stuff) but 6.3.1(15) pretty much hits it. Truck_Driver and Driver are two _different_ types. The fact that they both belong in Driver'Class is not relevant to the declarations or implementation of operations of these two _specific_ types. It _is_ relevant to an _invocation_ of such operations where classwide operand(s) happen to be specified. > :.... > :end Vehicles.Trucks; > : > : > :-- In a client somewhere > :-- > : D: Driver; > : Cd: Car_Driver; > : V: Vehicle; > : T: Truck; > :.... > : -- Option 1. > : -- > : D := Cd; -- Illegal, compile time error > : V := T; -- Illegal, compile time error > : > : -- Option 2. > : -- > : D := Driver(Cd); -- OK, convert toward root > : V := Vehicle(T); -- OK, convert toward root > > I understand these are view conversions, but am wondering how this can be > implemented without reference semantics? Actually these are about the only example of such conversions which are not view conversions. All of the types involved are specific types and so the conversion "does the right thing" and merely changes the corresponding components of D and V to the values present in Cd and T. In no case are the tags (dynamic type) changed. In particular, no truncation occurs. View conversions (the most typical case...) when used in an invocation (the most typical case again...) _do_ use reference semantics. For example, the "better" way to have written the above Option 2 would have been to skip the D and V decls and the assignments and simply have written: Register_Driver(Vehicle(T), Driver(Cd)); -- Reference semantics... > : Register_Driver(V, D); -- just fine and no dispatch needed > > Is this this call statically bound to the implementation for Vehicle? Absolutely. That's the point of this option. > : -- Option 3. > : -- > : Register_Driver(Vehicle'Class(T),Cd); -- Compile error, no primitive ops > > ... for type Truck with formal parameter Car_Driver? Not quite - Vehicle has no primitive operations with _car_ drivers - only "generic" _drivers_. > : -- Option 4. > : -- > : Register_Driver(Truck'Class(T), Cd); -- Compile error, no primitive ops > > ... for type Truck with formal parameter Car_Driver? Yes, exactly. There are only operations for and pairs. > : -- Option 6. > : -- > : Register_Driver(Vehicle'Class(V), D); -- Fine > : Register_Driver(Vehicle'Class(T), D); -- Fine (calls inherited op!!) > > Shouldn't the first one be: > > Register_Driver(Truck'Class(T), D); -- Fine Depends on what you mean. As written the first one is just fine. All vehicles are in Vehicle'Class and D is delcared as a driver and there is a primitive Register_Driver op for the pair which is inherited (and possibly overridden) for every vehicle (note the non capitalized spelling of vehicle here). And as written your version is just fine for completely similar reasons (just substitute "truck" for "vehicle" and Truck for Vehicle.) From a legality point of view - neither have any legality issues, they are perfectly valid and "do the right thing." > :As you can see, you can't get the invalid system stuff in the Ada model. > :In particular, you should note that the Truck type has _two_ primitive > :operations Register_Driver: > : > : procedure Register_Driver(V: Truck; D: Driver); -- Inherited from Vehicle > : procedure Register_Driver(V: Truck; D: Truck_Driver); -- *New* primitive op > > And, shouldn't these be: > >:procedure Register_Driver(V: Vehicle; D: Driver); -- Inherited from Vehicle >:procedure Register_Driver(T: Truck; D: Truck_Driver); -- *New* primitive op The V in the second of mine should be a T as you have in your second as that is how it is declared in Vehicles.Trucks (though it _could_ have been given as a "V"). So, for this one, I made a typo... This is _really_ unfortunate as it probably just served to confuse you. Sorry. This really was a bad typo because the first one is quite correct as given and is the more important (and less obvious) bit. Vehicle and Truck are different _specific_ types and a specific type only covers itself. In a derivation an inherited operation is obtained from the parent version by "systematic replacement" of the corresponding types in the signature. Admittedly this is not particularly obvious to the casual observer. See 3.4(18-23) for the precise definition. From a "pragmatic" point of view, the important thing is to realize that there is indeed a new operation for the derived type with a signature specifying the new _specific_ type that is the derived type. /Jon -- Jon Anthony Organon Motives, Inc. 1 Williston Road, Suite 4 Belmont, MA 02178 617.484.3383 jsa@organon.com -- Jon Anthony Organon Motives, Inc. 1 Williston Road, Suite 4 Belmont, MA 02178 617.484.3383 jsa@organon.com