Search code examples
roundingadafixed-point

Ada 2012 - replace Fixed_Decimal_Type'Round() with customised version?


Recently I have had joyous success when providing my own replacement 'Write () procedure for a custom record type, such as...

   type Pixel_Format is
      record
         --  blah blah
      end record;

   procedure Pixel_Format_Write (
     Stream : not null access Root_Stream_Type'Class;
     Item : in Pixel_Format);

   for Pixel_Format'Write use Pixel_Format_Write;

I was using this to convert certain record members from little-endian to big-endian when writing to a network stream. Worked beautifully.

By the same thinking I wondered if it is possible to replace the 'Round () function of decimal fixed point types, so I attempted a quick and dirty test...

   --  This is a "Decimal Fixed Point" type
   type Money_Dec_Type is delta 0.001 digits 14;

   --  ...

   function Money_CustomRound(X : in Money_Dec_Type)
     return Money_Dec_Type'Base;

   for Money_Dec_Type'Round use Money_CustomRound; -- COMPILER COMPLAINS HERE

   --  ...

   function Money_CustomRound(X : in Money_Dec_Type)
     return Money_Dec_Type'Base is

     begin
        return 0.001;
   end Money_CustomRound;

Alas, GNAT finds this offensive:

attribute "Round" cannot be set with definition clause

Question:

Am I attempting the impossible? Or is there a way to change the default 'Round attribute, in the same way that changing 'Write is possible?

Context to the question:

I have a set of about 15 different ways of rounding currency values that change from one project to the next (sometimes within the same project!). Examples include:

  • Round halves away from zero (Ada's default it seems)
  • Round halves towards zero
  • Statistical (a re-entrant type that requires global housekeeping)
  • Round towards evens OR odds
  • Rounds towards +INF / -INF
  • ...

It would be a powerful tool to be able to have this kind of functionality become transparent to the programmer by using certain rounding methods defined at the generic package level.

The angel on my other shoulder suggests I'm asking for something completely insane.

I wonder this because the documentation (ALRM and "Barnes 2012") both give a function specification for the default procedure. Why would they do that if one couldn't replace it with another of one's own design?


Solution

  • No, you cannot redefine the Round attribute. Attributes can only be queried (see RM K.2). Only aspects can be (re)defined using an aspect specification (see RM K.1; some exceptions apply). The RM gives specifications of the functions behind the attributes to clarify the signatures to the reader.