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,fcdd0f6139250dc5 X-Google-Attributes: gid103376,public From: eachus@spectre.mitre.org (Robert I. Eachus) Subject: Re: Tagged Types and Generics Date: 1997/04/28 Message-ID: #1/1 X-Deja-AN: 237966116 References: <3.0.32.19970421225247.007129f4@mail.4dcomm.com> Organization: The Mitre Corp., Bedford, MA. Newsgroups: comp.lang.ada Date: 1997-04-28T00:00:00+00:00 List-Id: In article <3.0.32.19970421225247.007129f4@mail.4dcomm.com> "Robert C. Leif, Ph.D." writes: > After the paper was submitted, I attempted to do my suggestion and > model money as a tagged type with the child libraries being the > different currencies. If one makes the exchange rate a decimal > type, then currency conversion requires a decimal division of the > same field from two of the child library units. Let's deal with two separate problems separately. You want to have an abstract general currency type, then derive to create different currencies. So far so good. But your abstract type will have non-currency operations. If you do it right though objects won't contain fields other than the fixed point field. I see creating a generic that takes a formal decimal type, a string or two, etc. and creates a new type derived from Currency with all these nice properties. Next problem, you want to convert between two decimal types. Once you understand that this is a non-transitive relationship, you create a generic conversion function in the Currencies package that needs to do one of three things: 1) some very clever conversion code 2) use floating point or 3) overflow under unexpected circumstances. Lets choose choice 1... package Currencies is type Currency is abstract tagged private; function Symbol(Value: in Currency) return String is abstract; function Name(Value: in Currency) return String is abstract; function "+"(L,R: Currency) return Currency is abstract; ... function To_String(Value: in Currency) return String; private type Currency is ...; function Integer_Part(Value: in Currency) return String is abstract; function Fractional_Part(Value: in Currency) return String is abstract; end Currencies; generic type Decimal is delta <> digits <>; Symbol: in String; Name: in String; package Currencies.Create is type Local is new Currencies.Currency with private; function "+" (L,R: Local) return Local;... private type Local is new Currencies.Currency with record Value: Decimal := 0.0; end record; end Currencies.Create; generic type From is new Currency; type To is new Currency; Multiplier: in String; -- i.e. "123.456789" function Conversion(Amount: in From) return To; function Conversion(Amount: in From) return To is begin return Integer'Value(Integer_Part(Amount)) * From'Value(Multiplier) + From'Value(Fractional_Part(Amount)) * From'Value(Multiplier); exception when others => TBD; end Conversion; You might want to use a rational arithmetic package instead, or some such. But the real problem is that currency conversions will change in how they are specified and computed a lot faster than your software. You really do need to accept arbitrarily long strings of zeros--which I didn't do here--when a currency devalues rapidly. -- Robert I. Eachus with Standard_Disclaimer; use Standard_Disclaimer; function Message (Text: in Clever_Ideas) return Better_Ideas is...