comp.lang.ada
 help / color / mirror / Atom feed
* array conversion - how to do?
@ 1997-06-24  0:00 Geert Bosch
  1997-06-27  0:00 ` Wes Groleau
  1997-06-28  0:00 ` Robert I. Eachus
  0 siblings, 2 replies; 11+ messages in thread
From: Geert Bosch @ 1997-06-24  0:00 UTC (permalink / raw)



Here is a simple situation illustrating a problem I encountered
in using arrays of pointers to tagged objects. I have an
application that should only use printable ASCII characters in its
string processing. So I declare the following:
   
   subtype ASCII_Character is Character 
     range Character'Val (32) .. Character'Val (127);
   type ASCII_String is array (Positive range <>) of ASCII_Character;

Now this string is clearly convertible to the String type, since
the components have the same type, the ASCII_Character is only
more constrained. Thus when my application wants to output its
ASCII_String results, it uses:

   with Ada.Text_IO; use Ada.Text_IO;
   procedure Test is
      Warning_Message : ASCII_String := "Warning: only use 7-bit ASCII";
   begin
      ... 
      Put_Line (String (Warning_Message));
   end Test;

Although this is IMHO a solution with clear semantics, this is
not legal Ada because of the rule that array conversions are only
allowed between array types that have components of the same subtype.
The workaround is both ugly and inefficient using a typical Ada 
implementation:

   procedure Put_Line (Item : in ASCII_String) is
      Standard_String : String (Item'Range);
   begin
      for I in Item'Range loop
	 Standard_String (I) := Item (I);
      end loop;
   end Put_Line;

   ...  -- And so on for all subprograms that use strings

I could imagine why it would not be possible to convert String
to ASCII_String, since that conversion might need time-consuming
checks. The conversion in the example is completely safe though,
which is statically checkable for the compiler.

Actually in my real program where I use arrays of 
access-to-classwide types it really makes sense to convert 
arrays of access B'Class to arrays of access A'Class, when
B is an extension of A. 

In some situations it is really useful to use arrays of
(access-to) tagged types, but it is quite annoying that
I cannot convert arrays to more general types but need
to copy them or use Unchecked_Conversion.

Can somebody give me a reason why this limitation is
in the language? A good work-around would also be very
welcome.

Regards,
   Geert




^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: array conversion - how to do?
  1997-06-24  0:00 array conversion - how to do? Geert Bosch
@ 1997-06-27  0:00 ` Wes Groleau
  1997-06-27  0:00   ` Robert Dewar
  1997-06-28  0:00 ` Robert I. Eachus
  1 sibling, 1 reply; 11+ messages in thread
From: Wes Groleau @ 1997-06-27  0:00 UTC (permalink / raw)



If I didn't misunderstand your intent, you could use 
Ada.Characters.Handling.To_Basic to eliminate most (not 
all) of the characters outside of the ASCII range, and
Ada.Characters.Handling.To_ISO_646 to convert the rest 
to something you specify.

To eliminate the non-printable characters--please note 
that Character'Val (127) is non-printable)--you could use
Ada.Strings.Fixed.Translate (in fact, you could use it for 
the whole thing).

Geert Bosch wrote:
> Here is a simple situation illustrating a problem I encountered
> in using arrays of pointers to tagged objects. I have an
> application that should only use printable ASCII characters in its
> string processing. So I declare the following:
> 
>    subtype ASCII_Character is Character
>      range Character'Val (32) .. Character'Val (127);
>    type ASCII_String is array (Positive range <>) of ASCII_Character;
> 
> Now this string is clearly convertible to the String type, since
> the components have the same type, the ASCII_Character is only
> more constrained. Thus when my application wants to output its
> ASCII_String results, it uses:
> 
>    with Ada.Text_IO; use Ada.Text_IO;
>    procedure Test is
>       Warning_Message : ASCII_String := "Warning: only use 7-bit ASCII";
>    begin
>       ...
>       Put_Line (String (Warning_Message));
>    end Test;
> 
> Although this is IMHO a solution with clear semantics, this is
> not legal Ada because of the rule that array conversions are only
> allowed between array types that have components of the same subtype.
> The workaround is both ugly and inefficient using a typical Ada
> implementation:
> 
>    procedure Put_Line (Item : in ASCII_String) is
>       Standard_String : String (Item'Range);
>    begin
>       for I in Item'Range loop
>          Standard_String (I) := Item (I);
>       end loop;
>    end Put_Line;
> 
>    ...  -- And so on for all subprograms that use strings
> 
> I could imagine why it would not be possible to convert String
> to ASCII_String, since that conversion might need time-consuming
> checks. The conversion in the example is completely safe though,
> which is statically checkable for the compiler.
> 
> Actually in my real program where I use arrays of
> access-to-classwide types it really makes sense to convert
> arrays of access B'Class to arrays of access A'Class, when
> B is an extension of A.
> 
> In some situations it is really useful to use arrays of
> (access-to) tagged types, but it is quite annoying that
> I cannot convert arrays to more general types but need
> to copy them or use Unchecked_Conversion.
> 
> Can somebody give me a reason why this limitation is
> in the language? A good work-around would also be very
> welcome.
> 
> Regards,
>    Geert

-- 
----------------------------------------------------------------------
    Wes Groleau, Hughes Defense Communications, Fort Wayne, IN USA
Senior Software Engineer - AFATDS                  Tool-smith Wanna-be
                    wwgrol AT pseserv3.fw.hac.com

Don't send advertisements to this domain unless asked!  All disk space
on fw.hac.com hosts belongs to either Hughes Defense Communications or 
the United States government.  Using email to store YOUR advertising 
on them is trespassing!
----------------------------------------------------------------------




^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: array conversion - how to do?
  1997-06-27  0:00 ` Wes Groleau
@ 1997-06-27  0:00   ` Robert Dewar
  1997-06-28  0:00     ` Geert Bosch
  0 siblings, 1 reply; 11+ messages in thread
From: Robert Dewar @ 1997-06-27  0:00 UTC (permalink / raw)



Geert says

<<> I could imagine why it would not be possible to convert String
> to ASCII_String, since that conversion might need time-consuming
> checks. The conversion in the example is completely safe though,
> which is statically checkable for the compiler.
>>

YOu are trying to introduce into Ada a semantic concept that is 
completely missing at the moment, namely the idea that conversions
should be subdivided into those that may raise CE and those that
are known to be CE-safe at compile time.

Such distinctions are reasonable at the implementation level, but I find
the idea of basing legality on such considerations to be a large and very
unwelcome increase in semantic complexity.

In Ada, a subtype check is needed for a subtype conversion period. If the
compiler can optimize away the check fine. The rules on conversion of
arrays seem entirely consistent with this point of vi9ew.

You worry about writing the loop, but a good compiler should be able to
generate efficient code for that loop. After all the checks will all
get eliminated, and then there is no reason to think the loop will generate
code any different on a typical machine from the conversion.





^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: array conversion - how to do?
  1997-06-27  0:00   ` Robert Dewar
@ 1997-06-28  0:00     ` Geert Bosch
  1997-07-03  0:00       ` Robert Dewar
  0 siblings, 1 reply; 11+ messages in thread
From: Geert Bosch @ 1997-06-28  0:00 UTC (permalink / raw)



Geert says
   ``I could imagine why it would not be possible to convert String
     to ASCII_String, since that conversion might need time-consuming
     checks. The conversion in the example is completely safe
     though, which is statically checkable for the compiler.  ''

Robert replies:
   ``You worry about writing the loop, but a good compiler should
     be able to generate efficient code for that loop. After all
     the checks will all get eliminated, and then there is no reason
     to think the loop will generate code any different on a typical
     machine from the conversion. ''

No, that is not the point. There is a fundamental problem why this
conversion is really expensive on all Ada implementations while it 
should be free.  

Assume the following declarations:

   subtype ASCII_Character is 
     Character range Character'Val (32) .. Character'Val (127);
   type String is array (Positive range <>) of Character;
   type ASCII_String is array (Positive range <>) of Character;

   procedure Error (Message : String);
   Storage_Msg : ASCII_String := "Out of storage";

The point is that to write the conversion in another way than using
a typecast, I need to copy the entire string:

   --  Code to do Error (String (Storage_Msg));
   declare
      Error_String  : String (Storage_Msg'Range);
   begin
      for I in Error_String'Range loop
	 Error_String (I) := Storage_Msg (I);
      end loop;
      Error (Error_String);
   end;

My objection is not only that I need to write extra code, but
that the net effect of that code is to accomplish nothing. Of
course anybody facing this problem will create a function that
does the conversion, but I really doubt if this function call
will get eliminated by the compiler.

Although this specific example might not be too good, there
are very similar situations when using access-to-class-wide
types in arrays. 

Now I think about it, it is possible to rather closely model
typecasting for arrays by implementing array conversion as
showed below. It is a pity that this generates lots of code
with GNAT although all code could be eliminated. Are there
any compilers that correctly compile this into a null function?

Regards,
   Geert

--  Array_Conversion provides a typecasting function for arrays
generic
   type Source_Element is limited private;
   type Target_Element is new Source_Element;
   type Index is (<>);
   type Source_Array is array (Index range <>) of Source_Element;
   type Target_Array is array (Index range <>) of Target_Element;
function Array_Conversion (S : Source_Array) return Target_Array;
pragma Pure (Array_Conversion);

with Unchecked_Conversion;
function Array_Conversion (S : Source_Array) return Target_Array is
   subtype Fixed_Source is Source_Array (S'Range);
   subtype Fixed_Target is Target_Array (S'Range);
   function Convert is new Unchecked_Conversion (Fixed_Source, Fixed_Target);
begin
   return Convert (Fixed_Source (S));
end Array_Conversion;




^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: array conversion - how to do?
  1997-06-28  0:00 ` Robert I. Eachus
@ 1997-06-28  0:00   ` Geert Bosch
  1997-06-30  0:00     ` Robert I. Eachus
  0 siblings, 1 reply; 11+ messages in thread
From: Geert Bosch @ 1997-06-28  0:00 UTC (permalink / raw)



Robert I. Eachus <eachus@spectre.mitre.org> wrote:
       I used to worry about the fact that doing these conversions
   efficiently meant instantiating Unchecked_Conversion, but I
   eventually came around to the understanding that that is exactly
   what is happening here.

At first I had expected that the conversion would be allowed if the
elements of the source and target array had the same base type. Then
the compiler could add the standard checks for subtype conversion and
eliminate them in cases where the checks are known to succeed, like
in my example for conversion from ASCII_String to String.

The drawback of my generic Array_Conversion is that it is too powerful
in that it can convert an array of A to an array of B as long as B is
a new A. I would like to only allow conversion when A and B are subtype
compatible. Anyway, the point was to avoid copying as happens in the
loop approach, but at least GNAT doesn't seem to do that yet.

Hopefully this will improve with time.

Regards,
   Geert




^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: array conversion - how to do?
  1997-06-24  0:00 array conversion - how to do? Geert Bosch
  1997-06-27  0:00 ` Wes Groleau
@ 1997-06-28  0:00 ` Robert I. Eachus
  1997-06-28  0:00   ` Geert Bosch
  1 sibling, 1 reply; 11+ messages in thread
From: Robert I. Eachus @ 1997-06-28  0:00 UTC (permalink / raw)



In article <5opej8$rv5$1@gonzo.sun3.iaf.nl> Geert Bosch <geert@gonzo.sun3.iaf.nl> writes:

 > Here is a simple situation illustrating a problem I encountered
 > in using arrays of pointers to tagged objects. I have an
 > application that should only use printable ASCII characters in its
 > string processing. So I declare the following:

 >    subtype ASCII_Character is Character 
 >	range Character'Val (32) .. Character'Val (127);
 >     type ASCII_String is array (Positive range <>) of ASCII_Character;
 ...

 > Although this is IMHO a solution with clear semantics, this is
 > not legal Ada because of the rule that array conversions are only
 > allowed between array types that have components of the same subtype.
 > The workaround is both ugly and inefficient using a typical Ada 
 > implementation...

 > I could imagine why it would not be possible to convert String
 > to ASCII_String, since that conversion might need time-consuming
 > checks. The conversion in the example is completely safe though,
 > which is statically checkable for the compiler.

    I used to worry about the fact that doing these conversions
efficiently meant instantiating Unchecked_Conversion, but I eventually
came around to the understanding that that is exactly what is
happening here.  It is my responsibility as the Unchecked_Conversion
user to know that the conversion is correctly checked.  Easy in this
case, but this is a special case of a much more general one--the
element subtypes are not required to be static.  I still may know that
the conversion is safe, but by calling Unchecked_Conversion I am
taking that responsibility.
--

					Robert I. Eachus

with Standard_Disclaimer;
use  Standard_Disclaimer;
function Message (Text: in Clever_Ideas) return Better_Ideas is...




^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: array conversion - how to do?
  1997-06-28  0:00   ` Geert Bosch
@ 1997-06-30  0:00     ` Robert I. Eachus
  0 siblings, 0 replies; 11+ messages in thread
From: Robert I. Eachus @ 1997-06-30  0:00 UTC (permalink / raw)



In article <5p3rad$8n8$1@gonzo.sun3.iaf.nl> Geert Bosch <geert@gonzo.sun3.iaf.nl> writes:

  > The drawback of my generic Array_Conversion is that it is too powerful
  > in that it can convert an array of A to an array of B as long as B is
  > a new A. I would like to only allow conversion when A and B are subtype
  > compatible. Anyway, the point was to avoid copying as happens in the
  > loop approach, but at least GNAT doesn't seem to do that yet.

   One of those nasty "depend upon the compiler to do the right thing"
tricks you can use is to provide your own generic Checked_Conversion
routine which either does the run-time check OR just calls
Unchecked_Conversion if the source subrange is a subset of the target
subrange.  Even if the compiler is pretty dumb, you will at least get
a relatively quick check in the case where no check is required.  But
if the subranges are static and the compiler optimizes such generics
correctly (a pragma Inline can't hurt) the if statement will get
optimized away.

   A really fancy trick, and probably not worth the effort.  If the
ranges are nesting, you probably have more knowledge on the subject
than the compiler.



--

					Robert I. Eachus

with Standard_Disclaimer;
use  Standard_Disclaimer;
function Message (Text: in Clever_Ideas) return Better_Ideas is...




^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: array conversion - how to do?
  1997-06-28  0:00     ` Geert Bosch
@ 1997-07-03  0:00       ` Robert Dewar
  1997-07-04  0:00         ` Geert Bosch
  1997-07-04  0:00         ` Geert Bosch
  0 siblings, 2 replies; 11+ messages in thread
From: Robert Dewar @ 1997-07-03  0:00 UTC (permalink / raw)



Geert says

<<Now I think about it, it is possible to rather closely model
typecasting for arrays by implementing array conversion as
showed below. It is a pity that this generates lots of code
with GNAT although all code could be eliminated. Are there
any compilers that correctly compile this into a null function?
>>

I hope not!

If the body of Error is not available, this is not a valid optimization,
and indeed is typical of the kind of invalid optimizations that optimizing
compilers are sometimes known to do.

(I leave it as an interesting excercise to propose bodies of Error that
can tell this invalid optimization is being performed -- there is more
than once answer!)

Of course this means that your complaint about the conversion still stands,
but you can't go adding major chunks of complexity to a language just so
it can handle one more case efficiently, especially when it is an artifical
case -- I find the use of that subtype of character to be excessive
baggage in the first place.





^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: array conversion - how to do?
  1997-07-03  0:00       ` Robert Dewar
  1997-07-04  0:00         ` Geert Bosch
@ 1997-07-04  0:00         ` Geert Bosch
  1997-07-04  0:00           ` Robert Dewar
  1 sibling, 1 reply; 11+ messages in thread
From: Geert Bosch @ 1997-07-04  0:00 UTC (permalink / raw)



Geert says
 ``Now I think about it, it is possible to rather closely model
   typecasting for arrays by implementing array conversion as showed
   below. It is a pity that this generates lots of code with GNAT
   although all code could be eliminated. Are there any compilers
   that correctly compile this into a null function?''

Robert Dewar <dewar@merv.cs.nyu.edu> replies:
 ``If the body of Error is not available, this is not a valid
   optimization, and indeed is typical of the kind of invalid
   optimizations that optimizing compilers are sometimes known
   to do.''

I think you placed my remark about optimization in the wrong context. 
Your reply seems to target the loop approach which makes a copy that
cannot trivially be eliminated.

The code for Array_Conversion that I showed uses Unchecked_Conversion
from one constrained array to another. All checks can be eliminated,
so Unchecked_Conversion can just provide a different view of the 
array which is the goal I want to achieve. I'll quote some references
to support my claim that the code can be optimized to null.

Regards,
   Geert

RM95 13.9           /Implementation permissions/

 (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.
        
RM95 13.9             /Implementation Advice/

 (14)   The Size of an array object should not include its bounds;
	hence, the bounds should not be part of the converted data.

 (15)   The implementation should not generate unnecessary run-time
	checks to ensure that the representation of S is a
	representation of the target type. It should take advantage
	of the permission to return by reference when possible.
	Restrictions on unchecked conversions should be avoided
	unless required by the target environment.





^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: array conversion - how to do?
  1997-07-03  0:00       ` Robert Dewar
@ 1997-07-04  0:00         ` Geert Bosch
  1997-07-04  0:00         ` Geert Bosch
  1 sibling, 0 replies; 11+ messages in thread
From: Geert Bosch @ 1997-07-04  0:00 UTC (permalink / raw)



Robert Dewar <dewar@merv.cs.nyu.edu> wrote:
   Of course this means that your complaint about the conversion
   still stands, but you can't go adding major chunks of complexity
   to a language just so it can handle one more case efficiently,
   especially when it is an artifical case -- I find the use of
   that subtype of character to be excessive baggage in the first
   place.

The actual code uses arrays of access-to-classwide pointers.
When creating an array with access-to-object values of
objects that are in B'Class, I need to take advantage of
some features of objects in that class. Later on, when I want
to pass the array to more general functions, I need to 
convert the array to an array of access to A'class, where
B is new A with private. I thought posting the actual code
would be less helpful than constructing a much simpler example
with exactly the same problem.

Regards,
   Geert




^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: array conversion - how to do?
  1997-07-04  0:00         ` Geert Bosch
@ 1997-07-04  0:00           ` Robert Dewar
  0 siblings, 0 replies; 11+ messages in thread
From: Robert Dewar @ 1997-07-04  0:00 UTC (permalink / raw)



Geert said

<<The code for Array_Conversion that I showed uses Unchecked_Conversion
from one constrained array to another. All checks can be eliminated,
so Unchecked_Conversion can just provide a different view of the
array which is the goal I want to achieve. I'll quote some references
to support my claim that the code can be optimized to null.
>>

Yes, indeed, if you use unchecked conversion, the optimization is
legitimate and expected.





^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~1997-07-04  0:00 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
1997-06-24  0:00 array conversion - how to do? Geert Bosch
1997-06-27  0:00 ` Wes Groleau
1997-06-27  0:00   ` Robert Dewar
1997-06-28  0:00     ` Geert Bosch
1997-07-03  0:00       ` Robert Dewar
1997-07-04  0:00         ` Geert Bosch
1997-07-04  0:00         ` Geert Bosch
1997-07-04  0:00           ` Robert Dewar
1997-06-28  0:00 ` Robert I. Eachus
1997-06-28  0:00   ` Geert Bosch
1997-06-30  0:00     ` Robert I. Eachus

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