!standard 13.09(06) 03-12-05 AC95-00087/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 !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? ;-) ****************************************************************