[comp.lang.ada] implicit array type conversion

news@planck.uucp (Usenet News) (07/26/90)

Why is it that implicit array type conversion does not apply to the
following situation?  I can't find anything in the RM that disallows
this situation for implicit conversion.

The compiler (Verdix Sun 4 Self, version 6.0.2(g)) gives the following
warning for the assignment to B:

warning: RM 3.6.1: bounds check will raise CONSTRAINT_ERROR at runtime

It does raise the exception on execution.

I sorta wanted to get some other views before I flag this to Verdix as a
bug.  Minor flame: Its real easy to miss some statement buried in the RM
which clarifies these kinds of language lawyer issues.

------------------------ cut here ----------------------------------
procedure Strings is

   type STRING (Len : NATURAL) is
      record
         S : Standard.STRING(1..Len);
      end record;

   A : Standard.STRING(7..7);
   B : STRING(1);

begin -- Strings

   A := "X";
   B := (A'length, A);

end Strings;

Terry J. Westley
Arvin/Calspan Advanced Technology Center
P.O. Box 400, Buffalo, NY 14225
acsu.buffalo.edu!planck!hercules!westley

collard@software.org (David Collard) (07/27/90)

In article <1990Jul26.132742.3828@planck.uucp> acsu.buffalo.edu!planck!hercules!westley () writes:
> Why is it that implicit array type conversion does not apply to the
> following situation?  I can't find anything in the RM that disallows
> this situation for implicit conversion.
> 
> procedure Strings is
> 
>    type STRING (Len : NATURAL) is
>       record
>          S : Standard.STRING(1..Len);
>       end record;
> 
>    A : Standard.STRING(7..7);
>    B : STRING(1);
     ^^^^^^^^^^^^^^ At this point B is constrained to Len = 1.  
                    Which is why a constraint error is raised later.
> 
> begin -- Strings
> 
>    A := "X";
>    B := (A'length, A);
> 
> end Strings;
> 

An aggregate assignment which overrides the discriminant of a record is 
only allowed if the discriminant has a default and the object is not 
constrained when it is declared, i.e

  type STRING(Len : Natural := 0) is
    record
      S : Standard.STRING(1..Len);
    end record;

  B : String;

If you change your declaration to this, then the assignment will not
raise a constraint error.
HOWEVER it still will not work because when the discriminant does have
a default and an object is declared using the default , then the compiler 
will try to allocate enough space for the maximum value for the discriminant
(probably over 2 billion if Natural is 32 bits) which is 

  1) Too much memory

  2) Is beyond the maximum length for a string on some machines.

What will work is:

  type String_Index is range 0..100;

  type String(Len : String_Index := 0) is
    record 
      S : Standard.String(1..Natural(Len));
    end record;

  B : String;


But note that if the range of String_Index is large, you may be using
a lot more memory than is apparent.

The discriminated record is not intended to support dynamic allocation
of different sized objects.  If you really want dynamic allocation then
use an access type.

Good Luck
--

-----------------------------------------------------------------------
D. Thor Collard                      Internet: collard@software.org
Software Productivity Consortium     UUNET:    ...!uunet!software!collard
2214 Rock Hill Rd, Herndon VA 22070  

NCOHEN@IBM.COM ("Norman H. Cohen") (07/27/90)

Given the declarations

   type My_String (Len : Natural) is
      record
         S : String (1..Len);
      end record;

   A : String(7..7);
   B : My_String(1);

Terry Westley questions the raising of Constraint_Error by the
following statement:

   B := (A'Length, A);

(I have changed the name of Westley's record type to avoid confusion.)

The exception is raised not by the assignment-statement check that the
value of the righthand side belongs to the subtype of the lefthand side,
but by the evaluation of the aggregate.  (The same thing would happen
if the assignment to B were replaced by

   C := (A'Length, A) = My_String'(1, "X");

where C is of type Boolean.)

RM 4.3.1(3) states:

   For the evaluation of a record aggregate, the expressions given in the
   component associations are evaluated in some order that is not
   defined by the language....  A check is made that the value of each
   subcomponent of the aggregate belongs to the subtype of this
   subcomponent.  The exception CONSTRAINT_ERROR is raised if this check
   fails.

In this case, the value of A belongs to subtype String(7 .. 7) (because
that's how A is declared) but the subtype of the second component of
the aggregate (deduced from the type declaration for My_String and the
discriminant value given by the first component in the aggregate) is
String(1 .. 1).

There's nothing in the RM to suggest that an implicit subtype conversion
takes place here.  Such conversions are mentioned only in 5.2(3) and
5.2.1(1), and only for assignment statements in which the lefthand side
is a variable of an array type.

The only problem with the compiler is that its warning message ought to
have cited 4.3.1(3) rather than 3.6.1.

Norman H. Cohen

stt@inmet.inmet.com (07/27/90)

Re: Implicit array subtype conversion

It turns out that in Ada 83, implicit array subtype conversion
(aka "sliding") only takes place on array assignment,
and array object initialization at declaration (see RM 5.2.1 and 3.2.1:16).
It is easy to argue that sliding should be applicable in
more circumstances (or less, if it makes no sense for the array type),
but alas, the presence of sliding has been linked to the
use of named-with-others array aggregates (see RM 4.3.1:6).
Generally, where sliding is legal, named-with-others is illegal.

Actually, it is quite possible to imagine a rule that would allow
both to be legal in the same context, by simply stating that
an array aggregate with an OTHERS choice always takes the
bounds implied by the "applicable index constraint" even though
sliding might have allowed for different bounds in the same context.

Ada 9X will likely address this issue.

S. Tucker Taft
Intermetrics, Inc.
Cambridge, MA  02138

mfeldman@seas.gwu.edu (Michael Feldman) (07/28/90)

In article <1469@software.software.org> collard@software.org (David Collard) writes:
 >In article <1990Jul26.132742.3828@planck.uucp> acsu.buffalo.edu!planck!hercules!westley () writes:
 >
 >  type STRING(Len : Natural := 0) is
 >    record
 >      S : Standard.STRING(1..Len);
 >    end record;
 >
 >  B : String;
 >
 >If you change your declaration to this, then the assignment will not
 >raise a constraint error.
 >HOWEVER it still will not work because when the discriminant does have
 >a default and an object is declared using the default , then the compiler 
 >will try to allocate enough space for the maximum value for the discriminant
 >(probably over 2 billion if Natural is 32 bits) which is 
 >  1) Too much memory
 >  2) Is beyond the maximum length for a string on some machines.
Well, maybe. Actually it is implementation-dependent. TeleSoft indeed allocates
for the maximum, so the space never needs to be reallocated. Meridian allocates
only a header block, then allocates dynamically as much space as is needed.
What can other readers report about their compilers?

The above example shows VERY POOR use of the type system, since a string is
not likely to grow to integer'last characters. The correction below is
just the right approach.

This is also a good example of how Ada, for better or worse, leaves most
storage-management issues to the implementer. I think this is appropriate,
by the way, but one has to realize that it is so. Often the implementation
dependent surprises can be minimized by intelligent use of types, as in this
case.
 >What will work is:
 >
 >  type String_Index is range 0..100;
 >
 >  type String(Len : String_Index := 0) is
 >    record 
 >      S : Standard.String(1..Natural(Len));
 >    end record;
 >
 >  B : String;
 >
 >
 >But note that if the range of String_Index is large, you may be using
 >a lot more memory than is apparent.
 >
 >The discriminated record is not intended to support dynamic allocation
 >of different sized objects.  If you really want dynamic allocation then
 >use an access type.
I'm not sure I agree with this. I think people should try to minimize their
use of access types, though this is clearly a matter of taste which we
shouldn't get religious about. Discriminated records and unconstrained 
arrays - and a number of other features - aid in reducing the amount of
recourse to access types. Given the risks and storage management problems
associated - in all languages - with pointers, I encourage the use of these
language-provided pointer-avoidance schemes. There is no free lunch, as the
time/space tradeoffs inherent in this example make quite clear,
and of course there is still no substitute for common sense.
---------------------------------------------------------------------------
Prof. Michael Feldman
Department of Electrical Engineering and Computer Science
The George Washington University
Washington, DC 20052
+1-202-994-5253
mfeldman@seas.gwu.edu
---------------------------------------------------------------------------