How come that Lady Ada spoiled the previously so delicious meal with the two marked declarations. (In presence of the beverages, the compiler rejects the programm because of the ambiguity of the catenation operators "&", in absense it is legal).

Before attacking the problem, we first want to keep a close eye on our lady. The menu contains a certain number of dishes. We can choose from it a meal with a maximum of 10 courses. When we choose exactly 10, the aggregate

is empty; else it fills the sequence of dishes to exactly 10 courses by adding the necessary amount of empty courses. And for what serves the type conversion in the call of Enjoy? Well, we must not assume that the menu starts with entry number 1 - it's therefore that we use the attribute 'Length instead of 'Last. Thus the expression

gets the limits Menu'First and Menu'First + 9, RM_83 4.5.3 (4). Requested however is the range 1..10, and that's exactly what the subtype conversion Meal(X) is doing under the precondition that X has the correct length: The expression X keeps its value, only its limits slide.

Now I'm seeing Lady Ada sitting in her new house, laughing up her sleeve: In Ada 95, this would not have happened, because in such a case the subtype conversion (sliding) is done automatically, RM_95 4.6 (60), so that we can write directly

without raising Constraint_Error, and - magically - the ambiguity is gone.

Why? We are dealing here with a quite general problem, which appears in many disguises. Normally it appears when different string types are used:

but the cause is not the component type (here Character). Anybody bumping into a problem like this is driven to dispair, especially so because compiler messages normally are not very helpful and the declaration to blame (of the kind of Beverages) may be well hidden in some other package appearing in a use-clause. Here I would have bet my head that I was dealing with a compiler bug. What only made me suspicious, however, was three compilers being fed this program all responding with some more or less intelligible message complaining about the ambiguity of the catenation operator "&".

A funny abridged version of the problem goes like this:

Are the expressions "Lady" & " Ada" and "Lady Ada" the same?

In the following I quote Lars Prins's solution of Rational, adapted to our Table.

It seems that the declaration of Beverages is irrelevant here, but in fact it is not! According to RM_83 3.6 (10), the declaration of Beverages is equivalent to

The procedure can be simplified a bit without losing the ambiguity:

According to RM 4.6 (3), the type of the operand of a type conversion must be determinable independently of the context (in particular, independently of the target type). This means that for the resolution of the "&" operator, the fact that the result will be converted to the type Meal may not be used. Using a different type for the conversion, for instance, results in the same error. The fact that a type conversion to Meal was used is irrelevant indeed.

To show in which ways the expression can be interpreted, two unambiguous declarations are added. The ambiguity is resolved in these cases by taking away the type conversion, which puts an extra requirement on the resolution of the "&" operator:

Quote end.

Everything understood? OK, this takes some time to digests. Basically it is about the compiler's inability to decide whether the concatenation of the two operands shall result in a Meal or in a Wine_Cellar. (In both cases, the conversion to Boolean is of course absolute nonsense - but that does not matter, as little as the wrong lengths of the strings!)

The problem may be cured in Ada 83 for example in the following way:

With the function Adulterate, this nearly looks the same as before, but there is a fundamental syntactic and semantic difference: A type conversion only looks like a function call, but is none, no Ada function specification can be given for it (whence it does not appear as a function call in the syntax)! The specification ought to have the form

Now the requirement becomes obvious why a compiler must establish the operand type without consideration of the context (RM 4.6 (3)).

Something similar is true for some attributes. Given two overloaded functions

we again get ambiguity:

Neither for the 'Val attribute a specification can be given.

Still another solution is possible:

And with this, we have finally arrived at the Ada solution proper for such cases.


Contents        © Copyright 1998 C.K.W. Grein