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: 103376,6b6619eb9cada212 X-Google-Attributes: gid103376,public From: "Matthew Heaney" Subject: Re: Help me to chose between ADA 95 and C++ Date: 1999/12/18 Message-ID: <385bab78_3@news1.prserv.net> X-Deja-AN: 562340023 Content-transfer-encoding: 7bit References: <83b8il$i5k$1@nntp4.atl.mindspring.net> <3859abde_3@news1.prserv.net> <83dsno$5v2$1@nntp2.atl.mindspring.net> Content-Type: text/plain; charset="US-ASCII" X-Complaints-To: abuse@prserv.net X-Trace: 18 Dec 1999 15:42:48 GMT, 32.101.8.235 Organization: Global Network Services - Remote Access Mail & News Services Mime-version: 1.0 Newsgroups: comp.lang.ada Date: 1999-12-18T00:00:00+00:00 List-Id: In article <83dsno$5v2$1@nntp2.atl.mindspring.net> , Richard D Riehle wrote: > In general this is true. From time to time it might be useful to > expand or contract the exported behavior for a particular numeric > type. For example, I saw a design not long ago with this declaration, > > type Counter is private; > function Initialize return Counter; > function Increment return Counter; > function Decrement return Counter; > > where the full defintion was a integer type. The designer intended to > prevent any operations on Counter except increment and decrement. For > this application, that was a reasonable approach and eliminated any of > the complications associated with a client doing more arithmetic than > necessary. But you can add and even subtract operations from a scalar type: type Counter is new Integer; function "+" (L, R : Counter) return Counter is abstract; function "-" (L, R : Counter) return Counter is abstract; You can then use Counter'Succ and Counter'Pred. > I can think of other circumstances where it would be > useful to hide the actual type definition and export a restricted set > of operations, or a special set of operations. Moreover, it might be > useful to expand the set of exceptions for that type and add pre- and > post- conditions in the implementation of some operator/operation. You can also replace operations: type Heading_Type_Base delta 1.0/2**(-16) range -720.0 .. 720.0; subtype Heading_Type is Heading_Type_Base range 0.0 .. Heading_Type_Base'Pred (360.0); function Predefined_Add (L, R : Heading_Type_Base) return Heading_Type_Base renames "+"; function "+" (L, R : Heading_Type) return Heading_Type; function Predefined_Subtract (L, R : Heading_Type_Base) return Heading_Type_Base renames "-"; function "-" (L, R : Heading_Type) return Heading_Type; Now you can implement "+" and "-" to have wrap-around behaviour: H := 359.0; H := H + 2.0; -- H = 1.0 H := 5.0; H := H - 10.0; -- H = 355.0 > Suppose, however, that we want to do a little more than that. > Suppose the Divide operation is modified as (contrived example): > > function "/"(L , R : T) return T is > Result : T; > begin > if R = Zero then ... -- raise some exception? > elsif some-other-condition -- raise some other exception > elsif even-another-condition -- raise even-another-exception > else > Result := Division-operation > end if; > if Result is-in-some condition -- raise post-condition-exception > -- potentially more tests > else > return Result; > end if; > end "/"; > > I fully understand the problems with this example, but I also recognize > that, in the absence of exportable pre- and post-conditions in Ada, we > have few options but to check for these within the code itself. But pre- and post-condition checking is a separate issue from overriding predefined operators of a scalar type. We could declare your divide op for a non-private type: type T is new Float; function Predefined_Divide (L, R : T) return T renames "/"; function "/" (R, L : T) return T; You may prefer to not use an infix operator at all: type T is new Float; function Div (Dividend, Divisor : T) return T; In any case you're free to raise whatever exceptions are appropriate. As far as pre- and post-condition checking goes, I prefer to check using pragma Assert. No, this is not an official standard, but it is a de facto standard. (There's even an AI to add this pragma to the language.) The benefit using a pragma is that the assertion check can be turned on or off using switches, analogous to suppressing constraint checks. > Under these circumstances, I might want to write my own operators to ensure > conformity with rules that cannot be described through simple range > constraints. Agreed, but this doesn't mean you have to declare the type as private. > I agree that this is an additional problem. Deferred constants seem > to violate many of the principles of object-oriented programming. They have their place. If I write an ADT for exclusive use within a subsystem -- where I know no type derivation will occur -- then I'd probably use a deferred constant. However, if you write an ADT for general consumption, and you don't really know who your clients are, then I'd use a function. (Again, because they might do some derivations, and we want the function to be inherited. Constants aren't inherited.) This issue rears its ugly head for another reason. If you use a deferred constant, and elaboration of the constant requires nonstatic initialization, then you won't be able to use pragma Preelaborate: package Lists is pragma Preelaborate; --illegal... type List_Type is private; Null_List : List_Type; ... private type List_Type is new Controlled with record Head : Node_Access; end record; Null_List : constant List_Type := (Controlled with Head => null); -- ... because this is nonstatic end Lists; We'd like to use the strongest form of categorization pragma possible. Above, we'd have to change down to pragma Elaborate_Body. The solution is to declare Null_List as a primitive operation of the type: package Lists pragma Preelaborate; -- legal ... type List_Type is private; function Null_List return List_Type; -- ... because this returns its value at run-time private type List_Type is end Lists; > I think we are once again in agreement on most points. Yes. -- Creationists attempt to draw a line between evolutionary biology and the rest of science by remarking that large-scale evolution cannot be observed. This tactic fails. Large-scale evolution is no more inaccessible to observation than nuclear reactions or the molecular composition of water. Abusing Science: The Case Against Creationism Philip Kitcher