comp.lang.ada
 help / color / mirror / Atom feed
From: "Samuel T. Harris" <u61783@gsde.hou.us.ray.com>
Subject: Re: User define attributes
Date: Wed, 18 Apr 2001 15:50:44 -0500
Date: 2001-04-18T15:50:44-05:00	[thread overview]
Message-ID: <3ADDFE24.9B3E1038@gsde.hou.us.ray.com> (raw)
In-Reply-To: mailman.987589038.7796.comp.lang.ada@ada.eu.org

Marius Amado Alves wrote:
> 
> On Mon, 16 Apr 2001, Samuel T. Harris wrote:
> > It is somewhat harder to build a generic for records
> > since the "index" are the field names and the composite
> > function depend upon which field is in use. But it
> > can be done.
> 
> It can?  You mean without passing the names of the components explicitly,
> parallelely?  Please let us know how!
> 
> I am really curious because some months ago this was briefly discussed
> here on CLA and the conclusion was negative.  Not even a compiler
> dependent means was detected.
> 

Lets go back to the array. It needs generic formal parameters
for the width, image, and value of its index type and its
component type. An instantiation provides a width, image, and
value function for the composite type (i.e. the array).
This is easy because an array is a homogenous collection.
No matter the value of the index, the handling of components
are the same.

Now, compare this to records. Records are a heterogenous
collection. The handling of components depends upon
which component one is dealing. So, the image, value,
and width functions for the components must case
off of the field name and defer to the appropriate
field type. This case you have to write in preparation
for you instantiation. Some code examples follow ...

Here is the spec for a generic which supports arrays.

    generic
	type Index_Type is (<>);
	type Component_Type is private;
	type Array_Type is array (Index_Type range <>) of Component_Type;
	with function Width (Item : Index_Type) return Natural is <>;
	with function Image (Item : Index_Type) return String is <>;
	with function Value (Item : String) return Index_Type is <>;
	with function Width (Item : Component_Type) return Natural is <>;
	with function Image (Item : Component_Type) return String is <>;
	with function Value (Item : String) return Component_Type is <>;
    package Array_Attribute_Functions is
	-- The base type of the generic index_type must have a predecessor to
	-- index_type'first to support returning the value of an empty image "()".
	function Width (Item : Array_Type) return Natural;
	function Image (Item : Array_Type) return String;
	function Value (Item : String) return Array_Type;
    end Array_Attribute_Functions;

And here is an instantiation ...

  type Test_Record_Array is array (Positive range <>) of Test_Record_Type;

  function Width (Item : Positive) return Natural;

  function Image (Item : Positive) return String;

  function Value (Item : String) return Positive;

  function Width (Item : Test_Record_Type) return Natural 
    renames Test_Record_Type_Attributes.Width;

  function Image (Item : Test_Record_Type) return String 
    renames Test_Record_Type_Attributes.Image;

  function Value (Item : String) return Test_Record_Type 
    renames Test_Record_Type_Attributes.Value;

  package Test_Record_Array_Attributes is 
    new Array_Attribute_Functions 
     (Index_Type => Positive,
      Component_Type => Test_Record_Type,
      Array_Type => Test_Record_Array);

... where I could have used positive'image and positive'value
for the index functions, but I cannot use positive'width
since it is a parameterless function. I have to define a width
function which is a simple one-liner. So, for consistency I
also define an image and value function. Ignore, for the moment,
the fact that with width, image, and value functions for the
record type have not been defined yet, that will come later.

I believe the implementation of the generic body is obvious
to most everyone. Image simply iterates over the index of
the parameter and calls the image of the index and the
image of the component, puts a "=>" finger in between,
adds a separating "," after each iteration, except the last.
Finally it decorates the whole thing with enclosing "()".

The necessary code to satisfy the generic instantiation
is trivial for arrays. Now lets look at records ...

   generic
	type Field_Type is (<>);
	type Record_Type is private;
	-- Record fields should all have default values.
	with function Width (Item : Field_Type) return Natural is <>;
	with function Image (Item : Field_Type) return String is <>;
	with function Value (Item : String) return Field_Type is <>;
	-- Width of a field of the record with default value
	-- must represent the largest width possible.
	with function Width (Field : Field_Type; Item : Record_Type)
			    return Natural is <>;
	with function Image (Field : Field_Type; Item : Record_Type)
			    return String is <>;
	with procedure Value (Item : String;
			      Field : Field_Type;
			      Into : in out Record_Type) is <>;
    package Record_Attribute_Functions is
	function Width (Item : Record_Type) return Natural;
	function Image (Item : Record_Type) return String;
	function Value (Item : String) return Record_Type;
    end Record_Attribute_Functions;

... which look much like the one for arrays with the following
differences.

1. Instead of an index type, we have a field type.
2. Width, Image, and Value functions dealing with the component
   have a field_type parameter. The corresponding array function
   did not since the array generic know how to index the array
   but the record generic cannot "index" the record by field.
3. Instead of a component value function, we have a
   value procedure which works on the composite type.

The need for a value procedure is obvious when one considers
that various fields may have various types and their is no
way for a single value function to support those various
types. So, instead of providing a value function, the coder
must prepare a value procedure which incrementally fills
in a working record kept by generic body.

Here is an instantiation which provided the width, image,
and value function for the array generic ...

  type Test_Record_Type is
    record
      I, J : Largest_Integer;
      X, Y, Z : Largest_Float;
    end record;

  type Test_Record_Field is (I, J, X, Y, Z);

  function Width (Item : Test_Record_Field) return Natural;
  function Image (Item : Test_Record_Field) return String;
  function Value (Item : String) return Test_Record_Field;
  function Width (Field : Test_Record_Field; Item : Test_Record_Type) return Natural;
  function Image (Field : Test_Record_Field; Item : Test_Record_Type) return String;
  procedure Value (Item : String; Field : Test_Record_Field; Into : in out Test_Record_Type);

  package Test_Record_Type_Attributes is
    new Record_Attribute_Functions
     (Test_Record_Field, Test_Record_Type);

... The body of width, image, and value which involve
components must handle the "indexing" of field names
to actual record components. This is most easily done
with case statements where each field alternative
calls the appropriate width, image, or value function
according to the field types. Each field for image
and value will have its own alternative. Normally
the width will also have one alternative per field.

As a side note for discriminent and variant records,
the discriminants should come first. The value
function cannot determine the actual type of the
return value until it has all discriminants. This
means all discriminant need to have default values
to allow record variables to polymorph. The value
function simply resets the in out parameter when
it know it has all the other discriminants.

All three subprograms; width, image, and value;
may employ sophisticated logic to handle variant
records in order to avoid access invalid fields
as they interate over the "index" field_type.
Or they can just simply make the attempt and
handle constraint_error with a very localized
null exception handler.

I hope that answers your questions.
Since this code was written for a particular
project, I am not free to release the contents.
However, if there is some demand, I shall
rewrite it from scratch at home and submit
it to www.adapower.com.

-- 
Samuel T. Harris, Principal Engineer
Raytheon, Aerospace Engineering Services
"If you can make it, We can fake it!"



  reply	other threads:[~2001-04-18 20:50 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2001-04-14 13:33 User define attributes Ayende Rahien
2001-04-16  7:27 ` Martin Dowie
2001-04-16 11:23   ` Ayende Rahien
2001-04-16 11:37     ` Martin Dowie
2001-04-16 14:35       ` Samuel T. Harris
2001-04-16 15:20         ` Martin Dowie
2001-04-16 15:37           ` Brian Rogoff
2001-04-16 16:19           ` Samuel T. Harris
2001-04-16 17:08             ` Marin David Condic
2001-04-16 22:00               ` Samuel T. Harris
2001-04-17 12:34                 ` Georg Bauhaus
2001-04-17 20:35                   ` Samuel T. Harris
2001-04-24 21:00                   ` Samuel T. Harris
2001-04-16 17:37             ` Martin Dowie
     [not found]           ` <0tEC6.7646$FY5.638172@www.newsranger.com>
2001-04-16 17:34             ` Martin Dowie
2001-04-18 12:14         ` Marius Amado Alves
2001-04-18 20:50           ` Samuel T. Harris [this message]
2001-04-19  1:35             ` Jeffrey Carter
2001-04-19 12:50               ` Samuel T. Harris
2001-04-20 19:08             ` Marius Amado Alves
replies disabled

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