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,c3a7c1845ec5caf9 X-Google-Attributes: gid103376,public From: mheaney@ni.net (Matthew Heaney) Subject: Re: Equality operator overloading in ADA 83 Date: 1997/04/22 Message-ID: X-Deja-AN: 236522909 References: <01bc4e9b$ac0e7fa0$72041dc2@lightning> Organization: Estormza Software Newsgroups: comp.lang.ada Date: 1997-04-22T00:00:00+00:00 List-Id: In article <01bc4e9b$ac0e7fa0$72041dc2@lightning>, "Manuel Wenger" wrote: >I've tried to overload the "=" operator for fractions in a package. It >obviously doesn't work if the type isn't defined as "limited private", and >I don't want that. As an alternative, I found out that I might as well do a >renaming declaration, just by defining the type as "private" - so I've >tried doing that as well, and then using the following to rename the equal >sign: In Ada 83, you aren't allowed to override the predefined equality operator for nonlimited private types. A bit of a bummer, and that's why they changed it for Ada 95. Either you can make the type limited, and define the equality operator (and a Copy operation, too, while you're at it), or, add an Is_Equal operation and hope that clients remember to call that operation instead of "=". Or, if your type doesn't contain any access objects, you can leave the type as nonlimited private, and use the technique below to make sure predefined equality always works correctly. In Ada 95, you can replace the equality operator for nonlimited types. However, there is a caveat, necessited by backwards compatibility issues. The issue is that, if the type is not a tagged type, and if an object of the type is an component of a record or array, then the *predefined* operator - not the overridden one - is called. This is a real bummer. Note that if the type is tagged - even privately tagged - then the overidden version is always called. You can mitigate this issue 2 ways: 1. Always make sure equality works, irrespecitive of whether the predefined or overridden version is called. 2. Make the type privately tagged. Note that this is a server problem, not a client problem. You the implementor of an abstraction are responsible for satisfying the contract you advertised in the spec. A client should never have to worry that if he declares a record or array containing an object of your type, that equality won't work correctly. You the server must guarantee that equality always works. For types with value semantics, that is, containing no components that are access objects, then you can always make equality work, even predefined equality. You can do this with a bit of extra coding, or, just privately tagging the type. For types that have access object components, then you need to (privately) inherit from Controlled to prevent structure sharing, so you're tagged anyway, and the correct equality operator will get called. Consider a type such as Bounded_String: type Bounded_String is private; ... private type Bounded_String is record Buffer : String (1 .. Max_Length); Last : Natural := 0; end record; end; The simplest technique is to just privately tag the type: type Bounded_String is tagged record Buffer : String (1 .. Max_Length); Last : Natural := 0; end record; If you don't want to do that, then you have to make sure that every Buffer element has a known, default value. When you shorten the logical length of the Bounded_String, then you must assign the default value to the newly unused Buffer elements: Default_Character : constant Character := Ada.Latin_1.Nul; type Bounded_String is record Buffer : String (1 .. Max_Length) := (others => Default_Character); Last : Natural := 0; end record; For example, when you update a Bounded_String: procedure Set (Bounded : in out Bounded_String; To : String) is Last : Natural renames Bounded.Last; begin if To'Length >= Last then Bounded.Buffer (1 .. To'Length) := To; else declare Pad_Length : constant Positive := Last - To'Length; Pad : constant String (1 .. Pad_Length) := (others => Default_Character); begin Bounded.Buffer (1 .. Last) := To & Pad; end; end if; Last := To'Length; end Set; It took me a while to realize that, yes, even for types (without access objects) that have a physical length greater than the logical length, you can make the predefined equality work. This is true even for Ada 83, so you may be able to apply this technique to your problem. I would like to take this opportunity - while I'm on my soapbox :-) - to politely remind compiler vendors that they should make sure that equality for Ada.Strings.Bounded.Bounded_String always works. Either use some compiler magic to make sure the overridden equality operator gets called, privately tag Bounded_String, or implement the type using the technique I've shown above. You the purchaser of a compiler should test to make sure Bounded_String works. If the predefined equality is ever getting called, let your vendor know his product is broken. Perhaps this should be an ACVC test, too (maybe it is already). Matt -------------------------------------------------------------------- Matthew Heaney Software Development Consultant (818) 985-1271