Wie brachte Lady Ada es fertig, mit den beiden markierten Deklarationen das schmackhafte Menü ungenießbar zu machen. (In Anwesenheit der Getränke weist der Compiler das Programm wegen Zweideutigkeit des Katenierungsoperators "&" zurück, bei Abwesenheit ist es legal). Noch dazu werden die Getränke nicht einmal angerührt.

Dies ist ein Rätsel, das in Ada aktuell Band 2 Heft 1 (April 1994) in etwas anderer Form schon einmal erschienen ist, dessen Lösung jedoch wegen des Hinscheidens der Zeitschrift nie veröffentlicht wurde. Das wird hiermit nachgeholt.

Bevor wir jedoch die Lösung angehen, wollen wir unserer Lady erst einmal genau auf die Finger sehen. Unsere Speisekarte enthält eine beliebige Anzahl von Speisen. Wir können uns daraus ein Menü mit maximal 10 Gängen zusammenstellen. Wählen wir genau 10 aus, so ist das Aggregat

leer; ansonsten füllt es die Speisefolge auf genau 10 Gänge auf, indem es die erforderliche Anzahl leerer Gänge anhängt. Wozu dient jedoch die Typumwandlung im Aufruf von Genieße? Nun, wir dürfen nicht davon ausgehen, dass die Speisekarte mit dem Eintrag Nummer 1 beginnt - deshalb verwenden wir auch das Attribut 'Length anstelle von 'Last. Damit erhält der Ausdruck

die Grenzen Speisekarte'First und Speisekarte'First + 9, RM_83 4.5.3 (4). Verlangt ist jedoch der Bereich 1..10, und die Untertypumwandlung Menü(X) erreicht genau das unter der Voraussetzung, dass X die richtige Länge besitzt: Der Ausdruck X behält seinen Wert, nur seine Grenzen werden verschoben.

Ich sehe jetzt Lady Ada in ihrem neuen Haus sitzen und sich ins Fäustchen lachen: In Ada 95 wäre das nicht passiert, denn dort wird in einem solchen Fall die Untertypumwandlung (sliding) automatisch durchgeführt, RM_95 4.6 (60), wir können also direkt

schreiben, ohne Constraint_Error auszulösen, und damit ist dann auch plötzlich die Zweideutigkeit verschwunden.

Warum? Wir haben es hier mit einem recht generellen Problem zu tun, das in vielen Verkleidungen erscheint. Gewöhnlich tritt es auf, wenn verschiedene String-Typen verwendet werden:

doch liegt die Ursache nicht im Komponententyp (hier Character). Jedem, der auf ein derartiges Problem stößt, ist schier zum Verzweifeln zu Mute, besonders da die Compilermeldungen gewöhnlich nicht sehr hilfreich sind und die schuldige Deklaration (der Art von Getränke) bei Verwendung von use-Klauseln in einem ganz anderen Paket verborgen sein kann. Hier hätte ich meinen Kopf wetten mögen, dass es sich um einen Compilerfehler handelt. Was mich nur stutzig machte, war, dass drei Compiler, denen ich das vorwarf, alle eine mehr oder weniger verständliche Meldung ausgaben des Inhalts, dass der Konkatenierungsoperator "&" zweideutig sei.

Eine lustige Kurzfassung des Problems lautet:

Sind die Ausdrücke "Lady" & " Ada" und "Lady Ada" dasselbe?

Ich zitiere im Folgenden die Lösung von Herrn Lars Prins von der Firma Rational, angepasst an unseren Tisch.

Es scheint, dass die Deklaration der Getränke irrelevant ist, aber tatsächlich ist sie es nicht! Nach RM_83 3.6 (10) ist die Deklaration der Getränke äquivalent zu

Die Prozedur kann vereinfacht werden, ohne dass die Zweideutigkeit verloren geht:

Gemäß RM 4.6 (3) muss sich der Operand einer Typumwandlung unabhängig vom Kontext bestimmen lassen (insbesondere unabhängig vom Zieltyp). Das heißt, dass für die Auflösung des "&"-Operators die Tatsache nicht verwendet werden darf, dass das Ergebnis zum Typ Menü umgewandelt werden wird.

Um zu zeigen, wie der Ausdruck interpretiert werden kann, fügen wir zwei unzweideutige Deklarationen hinzu. Die Zweideutigkeit wird in diesen Fällen durch Entfernen der Typumwandlung aufgelöst, die eine zusätzliche Anforderung an die Auflösung des "&"-Operators stellt.

Zitat Ende.

Alles klar? Na ja, man braucht Zeit, das zu verdauen. Im Grunde geht es darum, dass der Compiler nicht entscheiden kann, ob bei der Konkatenierung der beiden Operanden nun ein Menü oder ein Weinkeller herauskommen soll. (In beiden Fällen ist die Umwandlung in Boolean natürlich absolut unsinnig - aber das spielt keine Rolle, genauso wenig wie die falsche Länge der Strings!)

Beheben lässt sich das Problem in Ada 83 zum Beispiel folgendermaßen:

Mit der Funktion Pansche sieht das zwar fast genauso aus wie zuvor, es gibt jedoch einen gewichtigen syntaktischen und semantischen Unterschied: Eine Typumwandlung sieht nur aus wie ein Funktionsaufruf, ist aber keiner, es lässt sich keine Ada-Spezifikation einer Funktion für sie angeben (weswegen sie in der Syntax auch nicht als Funktionsaufruf vorkommt)! Die Spezifikation müsste nämlich die Form haben:

Jetzt wird auch die Forderung klar, warum ein Compiler ohne Beachtung des Kontextes den Typ des Operanden bestimmen muss (RM 4.6 (3)).

Ähnliches gilt für einige Attribute. Gegeben seien zwei überladene Funktionen

Wieder erhalten wir Zweideutiges:

Auch für das 'Val-Attribut lässt sich keine Spezifikation angeben.

Noch eine weitere Lösung ist möglich:

Und dies ist auch die eigentliche Ada-Lösung für solche Fälle.


Ada Magica
Inhaltsverzeichnis