Version 1.2 of acs/ac-00088.txt

Unformatted version of acs/ac-00088.txt version 1.2
Other versions for file acs/ac-00088.txt

!standard 13.09(06)          03-12-05 AC95-00088/01
!standard 13.09(08)
!class amendment 03-12-05
!status received no action 03-12-05
!status received 03-11-07
!subject Unchecked type conversion
!summary
!appendix

From: Christoph Grein
Sent: Friday, November 7, 2003  3:24 AM

Is the following code legal, i.e. is the resulting string not abnormal?

        type Byte is mod 2**8;
        for Byte'Size use 8;
        type Byte_Array is array (Natural range <>) of Byte;
        pragma Pack (Byte_Array);

        function To_String is new Unchecked_Conversion (Byte_Array, String);

        B: Byte_Array := (Character'Pos ('A'),
                          Character'Pos ('d'),
                          Character'Pos ('a'));
        C: String := To_String (B);
        D: String (10 .. 12) := To_String (B);

Is C equal to "Ada"?
Is C equal to D?

Note the different index type ranges Natural vs. Positive (but could also be
any enumeration type).

Both, Source and Target types in Unchecked_Conversion may be indefinite types.
There are some condition on the legality:

13.9(6): S'Size = Target'Size

But Target may be indefinite (and is here), so does not have a size. So what
does the above condition mean?

13.9(8) talks about the "target subtype" (sic). What is the target subtype?
Is it the subtype of C? But this would only be known after evaluation of
To_String.
Or is only the assignment to D correct? D's subtype is known and has the
correct size; it is a constrained composite subtype.

So what do 13.9(6,8) mean exactly, given the famous Robert Dewar's rule that
the RM never says silly things?

****************************************************************

From: Tucker Taft
Sent: Friday, November 7, 2003  7:27 AM

> Is the following code legal, i.e. is the resulting string not abnormal?

It is definitely legal.  And in a typical/reasonable implementation,
the result is not abnormal.

>         type Byte is mod 2**8;
>         for Byte'Size use 8;
>         type Byte_Array is array (Natural range <>) of Byte;
>         pragma Pack (Byte_Array);
>
>         function To_String is new Unchecked_Conversion (Byte_Array, String);
>
>         B: Byte_Array := (Character'Pos ('A'),
>                           Character'Pos ('d'),
>                           Character'Pos ('a'));
>         C: String := To_String (B);
>         D: String (10 .. 12) := To_String (B);
>
> Is C equal to "Ada"?

In typical implementations, yes.

> Is C equal to D?

In typical implementations, yes.

> Note the different index type ranges Natural vs. Positive (but could also be
> any enumeration type).
>
> Both, Source and Target types in Unchecked_Conversion may be indefinite types.
> There are some condition on the legality:

These are not conditions on legality.  These are conditions on
whether the effect is language-defined or implementation-defined.

> 13.9(6): S'Size = Target'Size
>
> But Target may be indefinite (and is here), so does not have a size. So what
> does the above condition mean?

It means that you have not satisfied all the rules for making
the effect language-defined, so you are entering the arena
of implementation-defined behavior.   However, implementations
try to do the "right thing," and I would be surprised if yours
didn't produce the effect you expected.

To be honest, this section is written this way because trying
to formally define the effect of unchecked conversion is very
difficult, so we decided to provide a language-defined effect
only in very limited circumstances, and rely on implementations
to use that as a model for what to do in other circumstances.

> 13.9(8) talks about the "target subtype" (sic). What is the target subtype?

It is "Target".  Named type-ish things in Ada are always subtypes,
in that they imply both a type and a constraint.  The underlying
type is not directly namable.  See RM 3.2(8-9) and 3.2.1(6).
In this particular case, the target subtype, "String," is unconstrained.

> Is it the subtype of C? But this would only be known after evaluation of
> To_String.

No, the target subtype is the type passed into the instantiation,
i.e. String.

> Or is only the assignment to D correct? D's subtype is known and has the
> correct size; it is a constrained composite subtype.

Both are legal, but neither has officially language-defined
semantics.  Both depend on implementation-defined semantics,
but do so in a way that is very likely to be portable.

> So what do 13.9(6,8) mean exactly, given the famous Robert Dewar's rule that the
> RM never says silly things?

I hope the above answers your questions.  The key thing to understand
is that 6-10 are not legality requirements, but rather setting up
the conditions under which 13.9(5) specifies the semantics.  Under
other circumstances, you will need to rely on your implementor
to specify the semantics.  There should be something like Annex M
in the user manual for your particular compiler which talks about
the implementation-defined semantics for Unchecked_Conversion.
See paragraph 52 in annex M.

****************************************************************

From: Christoph Grein
Sent: Monday, November 10, 2003  4:34 AM

> In typical implementations, yes.

You talk here about 'typical implementations', but neither Gnat nor Apex treat
it this way.

Gnat rejects this taking advantage of 13.9(13).
Apex raises an exception.

So there seem to be different opinions about what is 'typical'.

The problem seems to be where to put the array bounds. But if both, source and
target, are indefinite types, source has stored the bounds, and there should
also be a place to store the target bounds. Perhaps there are problems if the
index sizes are different? I'm no compiler builder, so I do not know what is
hidden behind such an Unchecked_Conversion.

My conclusion is: The RM is very obscure on this topic. (I've learned in long
experience with Ada (83 and 95) to understand RM speak, but here I have to
resign :-(

****************************************************************

From: Tucker Taft
Sent: Monday, November 10, 2003  10:39 AM

> You talk here about 'typical implementations', but neither Gnat nor Apex treat
> it this way.

Oh well.  At least my favorite front end has no problem with this.
It does produce a warning that such conversions are nonportable.

> Gnat rejects this taking advantage of 13.9(13).
> Apex raises an exception.
>
> So there seem to be different opinions about what is 'typical'.
>
> The problem seems to be where to put the array bounds. But if both, source and
> target, are indefinite types, source has stored the bounds, and there should
> also be a place to store the target bounds. Perhaps there are problems if the
> index sizes are different? I'm no compiler builder, so I do not know what is
> hidden behind such an Unchecked_Conversion.

We don't have any problem implementing this, so I can't guess what is
the problem other vendors face.  In any case, you can probably make them
happy by declaring local constrained subtypes of String and Byte_Array that are exactly the
right length, and then instantiate Unchecked_Conversion with those.
You could declare your own To_String function which did this internally,
so the users of To_String could have the same external interface.  E.g.:

    function To_String(BA : Byte_Array) return String is
        subtype SBA is Byte_Array(BA'Range);
        subtype Str is String(1..BA'Length);
        function To_Str is new Unchecked_Conversion(SBA, Str);
    begin
        return To_Str(BA);
    end To_String;

This compiles on our compiler without any warnings about non-portability,
and produces the same result as your original.

>
> My conclusion is: The RM is very obscure on this topic. (I've learned in long
> experience with Ada (83 and 95) to understand RM speak, but here I have to
> resign :-(

Oh well...  Now and then I find the RM rather inscrutible as well.
I wonder who wrote it? ;-)

****************************************************************


Questions? Ask the ACAA Technical Agent