This is an old revision of the document!


Introduction

While messing around with Ada.Calendar, a need to output the return value of Ada.Calendar.Clock as a String, took me on an adventure in the land of pragma Assert, the Address attribute, the 'Size attribute and the fact that not all Ada compilers are created equal.

Caveat

The following is an example of how to do something. It's not meant to be used in any real capacity. If you need a portable String representation of Ada.Calendar.Clock, then you're better off using the many nice features of Ada.Calendar.Formatting.

The Problem

The problem of outputting the return value from Ada.Calendar.Clock as a string is one of privacy. The returned type, Time, is declared private. Also it's implementation defined:

<blockquote> The time base associated with the type Time of package Calendar is implementation defined. The function Clock of package Calendar returns a value representing the current time for this time base. The implementation-defined value of the named number System.Tick (see 13.7) is an approximation of the length of the real-time interval during which the value of Calendar.Clock remains constant. </blockquote>

So we can't see it, and we don't know how it's implemented. But there are ways around these issues.

One Solution

For my experiment I've used the GNAT GPL 2010 compiler, and in this compiler the Time type is declared as:

type Time_Rep is range -2 ** 63 .. +2 ** 63 - 1;
type Time is new Time_Rep;

A big number indeed. A 64 bit signed integer. Knowing this, we can create a function that converts a 64 bit Time type to a String. Or rather we can fake a conversion. This is how it's done:

function Time_Image 
  (Item : in Ada.Calendar.Time)
   return String
is
   type Time is mod 2 ** 64;
   pragma Assert (Time'Size = Item'Size);
 
   Time_Stamp : Time;
   for Time_Stamp'Address use Item'Address;
begin
   return Trim (Source => Time'Image (Time_Stamp),
                Side   => Ada.Strings.Left);
end Time_Image;

Amazingly simple, yes?

Lets take a closer look at the inner workings of the Time_Image function:

type Time is mod 2 ** 64;

We declare a new Time type with the same size as the Ada.Calendar.Time type (as defined by the GNAT GPL 2010 compiler). I've used mod 2 ** 64 instead of range -2 63 .. +2 63 -1, but that's mostly because I don't care about the sign. You can just as well go with range -2 63 .. +2 63 -1. The important thing to bear in mind, is that the two types should have the same size. Which brings us to this:

pragma Assert (Time'Size = Item'Size);

Here we assert that the two types are of equal size. If for some reason they don't match, an Assertion_Error exception is raised. It bears mentioning that the behavior of pragma Assert depends on the pragma Assertion_Policy setting.

So while the Time declaration destroys any hope of portability between compilers and systems, the pragma Assert at least makes sure we can catch any problems and act accordingly.

Next we have:

Time_Stamp : Time;
for Time_Stamp'Address use Item'Address;

This is where the “magic” happens. We declare the Time_Stamp variable and then immediately thereafter we tell the program to use the machine address of the Item object for the Time_Stamp object. What this basically means, is that when we read the Time_Stamp variable, we're actually reading the contents of the Item object.

Outputting the String representation of Time_Stamp is now a simple matter of using the 'Image attribute and the Trim function (to pretty it up):

return Trim (Source => Time'Image (Time_Stamp),
             Side   => Ada.Strings.Left);

And voila! We have a neat String representation of the Ada.Calendar.Clock return value. Whether or not this is useful for anything, well, I'll leave that decision to the reader.

Thanks

I'd like to extend my thanks to Jacob Sparre for gently pushing me in the right direction. As usual the freenode #ada IRC channel proved an invaluable help in learning something new.


Navigation