comp.lang.ada
 help / color / mirror / Atom feed
From: Craig Carey <research@ijs.co.nz>
Subject: Re: Representing data differently
Date: Sun, 09 Feb 2003 17:39:21 +1300
Date: 2003-02-09T17:39:21+13:00	[thread overview]
Message-ID: <c5cb4v03pves595pdtq3euo1glgf5ne71q@4ax.com> (raw)
In-Reply-To: GBS0a.26741$HN5.82176@rwcrnsc51.ops.asp.att.net


On Fri, 07 Feb 2003 18:07:34 GMT, tmoran@acm.org wrote:

>>In C I can represent the same data multiple ways using structs and
>>unions.  How and can I do this in Ada?
>
>  In Ada it's called Unchecked_Conversion.  It's "unchecked" because
>there's not much the compiler can do to help check that you coded
>what you meant to code.  Look it up in any Ada text.


This message provides a more details and it has an example showing how
to make two records be of the same size.


Suppose that there is a generic package that has to be instantiated
only once (otherwise, with GNAT, the executables get larger), but the
instantiated generic package has receive two completely different
types.

The generic package has this header:

   generic
      type Data_Type is private;	  --  Constrained only
      ...

The package passes these 3 checks:

  * The 'union' type is not a pointer to both records. In this option
    and unchecked conversion would be done on the pointers. It is
    simple to specify but leads to harder to write code and probably
    a larger executable.

  * The 'union' type is not a variant, and it is not a tagged type.
    Those two types are unconstrained.


--------------------------------------------------------------------

with Ada.Unchecked_Conversion;

package Bt is

   type Kind_Enum is (Kind_R1, Kind_R2, Kind_Zero);

      --  Help catch unitialized value bugs in Linux:
   for Kind_Enum use (Kind_R1 => 7, Kind_R2 => 8, Kind_Zero => 9);

   pragma Volatile (Kind_Enum);  --  Inlined code uses field's value

   type Hoof_Rec is null record;

   type R1_Rec is
      record
         X1       : Integer;
      end record;

   type R2_Rec is
      record
         Y1       : String (1 .. 7);
         Y2       : Boolean;
      end record;

   for Hoof_Rec'Alignment use 4;
   for R1_Rec'Alignment   use 4;
   for R2_Rec'Alignment   use 4;

   Size   : constant := 64;    --  Adjust by hand

   for Hoof_Rec'Size use Size;
   for R1_Rec'Size   use Size;
   for R2_Rec'Size   use Size;

   type Variant is
      record
         Kind     : Kind_Enum := Kind_Zero;
         K        : Hoof_Rec;
      end record;

   function From_R1 (X : R1_Rec) return Variant;

   function To_R1 is new Ada.Unchecked_Conversion (
               Source => Hoof_Rec, Target => R1_Rec);

private
   function From_R1 is new Ada.Unchecked_Conversion (
               Source => R1_Rec, Target => Hoof_Rec);
end Bt;

--------------------------------------------------------------------

with Text_IO;

package body Bt is

   function From_R1 (X : R1_Rec) return Variant is
   begin
      return (Kind => Kind_R1, K => From_R1 (X));
   end From_R1;

begin
   declare
      Z0    : Hoof_Rec;
      Z1    : R1_Rec;
      Z2    : R2_Rec;

      function Nim (Omicron : Natural) return String
            renames Natural'Image;

      function From_R1_To_R2 is new Ada.Unchecked_Conversion (
                  Source => R1_Rec, Target => R2_Rec);
   begin
         --  Prints "64 64 64 TRUE":

      Text_IO.Put_Line (Nim (Z0'Size) & Nim (Z1'Size) &
               Nim (Z2'Size) & ' ' &
               Boolean'Image (From_R1_To_R2 (Z1).Y2));

         --  In GNAT,T'Object_Size to get the size of the variables
         --   without defining variables.

      if Z0'Size /= Z1'Size or Z0'Size /= Z2'Size then
         raise Program_Error;
      end if;
   end;
end Bt;

--------------------------------------------------------------------

pragma Style_Checks ("3abcefhiklmnoprst");

with Bt;

procedure Bt_Main is
begin
   null;
end Bt_Main;

--------------------------------------------------------------------


The text

   "From_R1_To_R2 (Z1).Y2"

shows a way to use Unchecked_Conversion that permits the compiler to
not copy the entire record. That is permitted by AARM 13.9
(Unchecked Type Conversions), which says:

  12 An implementation may return the result of an unchecked
   conversion by reference, if the Source type is not a by-copy type.
   [In this case, the result of the unchecked conversion represents
   simply a different (read-only) view of the operand of the
   conversion.]

  12.a Ramification: In other words, the result object of a call on an
   instance of Unchecked_Conversion can occupy the same storage as the
   formal parameter S. 


For GNAT, adding a ".all" and having the conversion be applying to
a pointer to a record easily could reduce the chance of copying.

--

For completeness, the Unchecked_Conversion feature and its copying, can
be avoided, by using this technique:

   for X'Address use Y'Address;
   pragma Import (Y);
         --  :Stops default initialising of pointers (not in GNAT 3.14)


If X or Y is an "in out" mode record parameter then it could be copied
in or out. Making it tagged guarantees that that doesn't happen.

AARM 3.10 (Access Types) says:
 (9.g) A formal parameter of a tagged type is defined to be aliased so
   that a (tagged) parameter X may be passed to an access parameter P by
   using P => X'Access. Access parameters are most important for tagged
   types because of dispatching-on-access-parameters (see 3.9.2). By
   restricting this to formal parameters, we minimize problems
   associated with allowing components that are not declared aliased to
   be pointed-to from within the same record.

http://www.adaic.org/standards/95aarm/html/AA-3-10.html


--------------

A bug that ACT got rid of has been replaced with another bug in the same
place.

In 15 July 2001 I reported this error as a bug (in GNAT 3.13p, the native
FreeBSD version of FreeBSD):

| 5. function Nim (Omicron : Natural) return String renames Natural'Image;
|                  |
| >>> warning: "Omicron" is not referenced
         

With version 3.15p, there is still a warning (a minor problem):

| 17.       function Nim (Omicron : Natural) return String
| 18.             renames Natural'Image;
|                 |
|     >>> (style): subprogram body has no previous spec



G. A. Craig Carey

Speedy Ada Strings.
(The licence of the package changed: this software now can't be mixed with
software under a licence having the acronym "GMPL", with 2 exceptions: (1)
Ada Core Tech software is OK, it's exempted; (2) the "GMPL" text per
file, of the 3rd party, is cryptographically signed by Ada Core, etc.
R. R. Software seems to have its own GMPL -- I didn't see the acronym
expanded, and while undefined it is different enough under law):
http://www.ijs.co.nz/code/ada95_strings_pkg.zip

http://www.ijs.co.nz/ada_95.htm




  reply	other threads:[~2003-02-09  4:39 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2003-02-07 14:15 Representing data differently Daniel Allex
2003-02-07 18:07 ` tmoran
2003-02-09  4:39   ` Craig Carey [this message]
2003-02-10 12:47     ` Colin Paul Gloster
2003-02-13 17:21       ` Craig Carey
2003-02-08  0:24 ` Wojtek Narczynski
2003-02-12 18:52 ` Martin Krischik
2003-02-22 19:09   ` Robert A Duff
2003-02-23 13:06     ` Martin Krischik
2003-02-23 21:09 ` Craig Carey
2003-02-23 21:59   ` tmoran
replies disabled

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox