From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-0.8 required=5.0 tests=BAYES_00,INVALID_DATE autolearn=no autolearn_force=no version=3.4.4 Path: utzoo!utgpu!news-server.csri.toronto.edu!rutgers!mcnc!decwrl!ucbvax!IBM.COM!NCOHEN From: NCOHEN@IBM.COM ("Norman H. Cohen") Newsgroups: comp.lang.ada Subject: constraint error question for language lawyers Message-ID: <9011091437.AA20896@ajpo.sei.cmu.edu> Date: 9 Nov 90 14:36:18 GMT Sender: usenet@ucbvax.BERKELEY.EDU Organization: The Internet List-Id: Alex Blakemore asks why, given the declarations type Short is range 0 .. 10; type Data is array (Short range <>) of Character; type Var_Text (Len : Short := 0) is record Text : Data (1 .. Len); end record; Dummy : Var_Text; -- unconstrained the statements Dummy := (Len => 0, Text => ""); Dummy := (Len => Dummy.Len + 1, Text => Dummy.Text & 'a'); raise Constraint_Error in the second assignment. The surprise results from the fact that the catenation Dummy.Text & 'a' (where Dummy.Text = "") has bounds of 0 .. 0. Since the Text component of type Var_Text has a lower bound of 1, the evaluation of the aggregate (Len => Dummy.Len + 1, Text => Dummy.Text & 'a'); raises Constraint_Error. Now to the legal citations. RM 4.5.3(4), in discussing the result of a catenation, states: The lower bound of this result is the lower bound of the left operand, unless the left operand is a null array, in which case the result of the catenation is the right operand. In this case the left operand IS a null array, so the lower bound must be that of the right operand. In this case, however, the right operand is not an array, but a character, so it has no lower bound. The next RM paragraph, 4.5.3(5), provides a rule to cover this case: If either operand is of the component type of an array type, the result of the catenation is given by the above rules, using in place of this operand an array having this operand as its only component and having the lower bound of the index subtype of the array type as its lower bound. That is, 'a' is taken to be a shorthand for (Short'First => a). Since Short'First, or 0, is lower bound of the right operand, and since the left operand is null, 0 is the lower bound of the catenation. The actual raising of Constraint_Error is governed by RM 4.3.1(3), which discusses the evaluation of record aggregates and states: 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. The only questionable rule in all of this is the rule that the value of L&R, where L is a null array, is the value of R. This seems natural at first glance, but since Ada can have null arrays with different bounds (0 .. -1, 1 .. 0, etc.) this conflicts with the usual rule (for L nonnull) that the lower bound of the result is that of its left operand. Alex Blakemore has provided an example where this nonuniform rule leads to a nasty surprise. I would modify the program as follows: Add the subtype declaration subtype Positive_Short is Short range 1 .. Short'Last; and use Positive_Short rather than Short as the index subtype of the array type Data. Since the Text component of the record type Var_Text has a lower bound of one, this is more appropriate. The Ada rules tend to work more sensibly when the lower bound of an array is the lower bound of its index subtype. (In this case, 'a' would be taken as a shorthand for (Positive_Short'First => 'a'), which has a lower bound of 1, so the catenation ""&'a' would have a lower bound of 1.)