With Ada through Thick And Thin

Christoph Karl Walter Grein

The other day, I overheard a conversation between Lady Ada and a desperate customer.

Adam: Madam, I'm Adam.
Ada: Adam, I'm Ada. Nice to meet you. What can I do for you?
Adam: Madam, I've got a problem that drives me crazy. Could you please have a look at the following declarations?
  type D is array (Integer range <>) of Boolean;
  type A is access all D;

  X : aliased D (1..3);
  AX: A           := X'Access;
  BX: A (X'Range) := X'Access;
I just can't understand why this silly compiler won't accept this.
Dam', I'mad!
Ada: Chill out, my friend, ... cool down... Take my hand and I'll lead you through thick and thin of the RM.
See, you've defined an unconstrained array type and a pointer to objects of this type. Since the type is unconstrained, its objects of course have to store their bounds together with the components. And so has the pointer. This means the pointer has to be a so-called fat pointer, in contrast to normal thin pointers, which grant access to only the array itself, its bounds being known because of some other reasons.
Now your object X is constrained by explicit bounds. The 'Access attribute therefore delivers a thin pointer. AX on the other hand is a fat pointer. BX is a fat pointer as well...
Can you still follow me? Hello? Are you still there?
Adam: Am I, ma? I'm not so sure...
Ada: Now, I do state very clearly in RM 3.10(10) that the designated subtype of A and A(X'Range) is D, don't I.
Adam: ...mim... [unintelligible]
Ada: My dear Adam, let's further analyse the problem. From RM 3.3.1(8,9) follows that the nominal and the actual subtype of X is D(1..3). So the actual subtype is constrained.
X is a constrained object because its nominal subtyp is constrained.
RM 3.10.2(27/1) requires that A's designated subtype shall statically match the nominal subtype.
RM 4.9.1(2) states that statically matching subtypes have statically matching constraints.
Adam: I...
Ada: No, don't interrupt me. We're nearly there.
For AX, the expected type of X'Access is A. A's designated subtype D does not statically match X's nominal subtype D(1..3).
For BX, the expected type of X'Access is again A. A(X'Range)'s designated subtype D does not statically match X's nominal subtype D(1..3).
Adam: ...
Ada: Now you're speechless, aren't you.
And now to the final blow.
Just consider the following:
  Y : aliased D   := X;
  AY: A           := Y'Access;
  BY: A (Y'Range) := Y'Access;
If I'm telling you that the nominal subtype of Y is D, its actual one is D(1..3), so that Y is an object constrained by its initial value, you should be able to find out all by yourself why this is now correct.
So, my dear friend, certainly you're asking yourself now what purpose a constraint on an access type (like in your example on A via (X'Range)) should serve. Well, virtually none - you'll normally find such a beast only in ACVC tests. Its only effect is to enforce an additional range check; the designated subtype is not affected.
... er ... Hello? Where are you...?
Adam: [enlightened, has entered nirvana and evaporated]

Contents        © Copyright 2005 C.K.W. Grein