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=-0.8 required=5.0 tests=BAYES_00,INVALID_DATE autolearn=no autolearn_force=no version=3.4.4 X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: 103376,791ecb084fdaba75 X-Google-Attributes: gid103376,public X-Google-ArrivalTime: 1994-09-29 05:34:59 PST Newsgroups: comp.lang.ada Path: bga.com!news.sprintlink.net!howland.reston.ans.net!usc!elroy.jpl.nasa.gov!lll-winken.llnl.gov!noc.near.net!inmet!dsd!stt From: stt@dsd.camb.inmet.com (Tucker Taft) Subject: Re: Types with physical dimension Message-ID: Sender: news@inmet.camb.inmet.com Organization: Intermetrics, Inc. References: Date: Wed, 28 Sep 1994 21:41:44 GMT Date: 1994-09-28T21:41:44+00:00 List-Id: In article , Paul Graham wrote: >While Ada's strong typing mechanism can catch errors like this: > > d : dollars; > f : francs; >... > d := d + f; -- error > >it does allow such nonsensical constructs as > > d := d * d; -- what does it mean to multiply dollars by dollars? > d := d ** 10; -- ?? > >VHDL provides physical types to model values with physical dimensions. A >VHDL physical type lacks certain predefined multiplication operations, lacks >exponentiation, and its division operation returns a universal_integer (or >root_integer in Ada 9x terminolgy). > ... >One can model physical types in Ada by using private types, but this >involves writing a lot of operators. What do Ada programmers do to guard >against dimensional errors? In Ada 9X, there is a new option. You can override the predefined operators of a numeric type with an abstract function. This flags any attempt to use the operation. For example, here we define 3 types and override their predefined multiplying and exponentiating operators with abstract versions: type Cm is digits 6; type Seconds is digits 6; type Cm_Per_Sec is digits 6; function "*"(Left, Right : Cm) return Cm is abstract; function "/"(Left, Right : Cm) return Cm is abstract; function "**"(Left : Cm; Right : Integer) return Cm is abstract; function "*"(Left, Right : Seconds) return Seconds is abstract; function "/"(Left, Right : Seconds) return Seconds is abstract; function "**"(Left : Seconds; Right : Integer) return Seconds is abstract; function "*"(Left, Right : Cm_Per_Sec) return Cm_Per_Sec is abstract; function "/"(Left, Right : Cm_Per_Sec) return Cm_Per_Sec is abstract; function "**"(Left : Cm_Per_Sec; Right : Integer) return Cm_Per_Sec is abstract; Then you can define the appropriate combinations: function "/"(Left : Cm; Right : Sec) return Cm_Per_Sec; function "*"(Left : Cm_Per_Sec; Right : Sec) return Cm; function "*"(Left : Sec; Right : Cm_Per_Sec) return Cm; You would probably want to put pragma Inline on these. You could actually define a generic to simplify this, so you wouldn't have to write the trivial bodies repeatedly: generic type Left_Type is digits <>; type Right_Type is digits <>; type Result_Type is digits <>; function Mul(Left : Left_Type; Right : Right_Type) return Result_Type; pragma Inline("*"); -- This means to inline calls on any instantiation function Mul(Left : Left_Type; Right : Right_Type) return Result_Type is begin return Result_Type(Left) * Result_Type(Right); -- Note that predefined operators "reemerge" in generics -- This is probably one of the few times where that is useful! end Mul; ... Ditto for a generic Div. Now you can just write: function "/" is new Div(Cm, Sec, Cm_Per_Sec); function "*" is new Mul(Cm_Per_Sec, Sec, Cm); function "*" is new Mul(Sec, Cm_Per_Sec, Cm); ... which is relatively painless. Of course it would be nice to have more direct support for units (given infinite resources, that is ;-), but at least with "abstract" and "generics" you can build your own consistency checks. >Paul >-- >Paul Graham graham@compass-da.com Compass Design Automation, Inc. >(speaking only for myself) "Cekoslovakyalilastiramadiklarimizdanmissiniz." S. Tucker Taft Ada 9X Mapping/Revision Team Intermetrics, Inc. Cambridge, MA 02138 P.S. "abstract" subprograms weren't invented for this purpose, but they seem to do the job fairly nicely. Note that any untagged type may have an "abstract" primitive subprogram. But if a tagged type has an "abstract" primitive, then it must itself be "abstract." -T