2

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?

  • 1
    You’d have to write the code anyway, so what benefit would you get redefining the attribute rather than just having a function `Round`? ... which would in fact end up with shorter code – Simon Wright Oct 16 '19 at 20:29
  • @SimonWright, existing functions that use the old default behaviour would not have to be modified for the new requirements. –  Oct 17 '19 at 07:26
  • I encounter a lot this « fear » of find-replace code when doing port/refacto. I often consider it as a symbol of lack of confidence of the management level into developers and software evolutions. Even I you could redefine le ‘Round, you would have to assess (test) it’s impact on all its users. Impact analysis and tests will occur anyways. Why then making « open + edit » n files a feared event ? A software changes over time, no matter how hard people wish it not to. – LoneWanderer Oct 18 '19 at 09:36
  • @LoneWanderer, yes you're right. I wish it wasn't such a sticking point too. I also wish I had any power to do anything about it :) –  Oct 18 '19 at 13:21
  • @LoneWanderer it's not always fear, there's also a simple convenience factor. If it "just happens" then you aren't doing extra work. – Patrick Kelly Oct 20 '19 at 14:03

1 Answers1

3

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.

DeeDee
  • 5,654
  • 7
  • 14