       Teil 2  KONTROLLSTRUKTUREN, FEATURES, OPERATOR-AUSDRCKE, ZUSICHERUNGEN
       =======================================================================

       Die Reihenfolge, in der bei Laufzeit die Instruktionen abgearbeitet
       werden, wird von den Kontrollstrukturen  
                               Sequenzierung 
                               bedingte Ausfhrung
                               Verzweigung    und 
                               Schleifen
       geregelt.
       An den Programmen  FILEDEMO  des ersten Teile und  LISTRACE , das am
       Ende dieses Teils wiedergegeben ist, knnen diese Strukturen demon-
       striert werden:
       
       
       Die Kontrollstruktur "Sequenzierung" bedeutet nur, da die verschie-
       denen Instruktionen einer Instruktionssequenz (eines COMPOUNDS) nach-
       einander ausgefhrt werden.
       Im der Kreierungsprozedur  make  des Programms  LISTRACE  findet sich
       der Compound
                                 run_qsort
                                 run_sort
                                 test_if_equal
       der bedeutet, da der Reihe nach die beiden Sortieralgorithmen aufge-
       rufen werden und dann getestet wird, ob die Ergebnisse bereinstimmen

       
       Bedingte Ausfhrung findet sich in  SORTRACE  etwa im feature  
       load_list : 
                      if not error then
                          if arg_count > 0 then
                              path := arg_item (1)
                          else
                              give_help ("sortrace.hlp")
                              get_a_string ("Name of ASCII file : ")
                              path := the_string
                          end
                          ...
                      end

       Bei der inneren if-Anweisung prft das feature  arg_count  der Klasse
       ENVIRONMENT , ob in der Befehlszeile (auf DOS-Ebene) etwas steht.
       Falls ja, so wird der erste String der Befehlszeile als Name der Datei
       interpretiert, von der eingelesen werden soll.
       Falls nein, so wird mit dem feature  give_help  der Klasse  INTERACT
       eine Hilfe-Text auf den Bildschirm gegeben und der Name der einzule-
       senden Datei explizit angefordert.

       Eine allgemeinere Form der bedingten Ausfhrung ist:
                    
                            if  x>0  then
                              i1
                              i2
                            elseif  x=0  then
                              i3
                            else
                              i4 
                              i5
                              i6
                            end

       Bei positivem  x  wird also der compound  i1 i2  augefhrt, bei  x=0
       wird  i3  ausgefhrt und ansonsten wird der compound  i4 i5 i6  aus-
       gefhrt.

       
       Eine Verzweigung findet sich in der Kreierungsprozedur des Programms  
       FILEDEMO , die das Men steuert:
                   
                   io.get_char
                   ch := io.last_char
                   inspect ch
                      when  'e'  then  get_data
                      when  'a'  then  change_data
                      when  's'  then  store_data
                      when  'z'  then  show_data
                      else if ch /= 'q' then
                           io.put_string ("Unbekanntes Zeichen %N") end
                   end

       Es wird ein Buchstabe von Tastatur angefordert und je nach Ergebnis
       werden unterschiedliche Aktionen gestartet.

       
       In  SORTRACE  findet sich diese Schleife:
                           
                           from
                               !!a1.make (1, count)  
                               i := 1
                           until
                               i > count
                           loop
                               a1.put (f.item (i), i)
                               i := i + 1
                           end
       
       Es wird ein Array kreiert, und dann wird der Inhalt des Files  f  auf
       das Array bertragen:

       
       Die allgemeine Form (Syntax) der Schleife ist:

                           from
                              compound1
                           until
                              boolean_expression
                           loop
                              compound2
                           end

       Die Bedeutung (Semantik) ist: 
       Zunchst wird  compound1  ausgefhrt und dann die Schleife.
       Beim Ausfhren der Schleife wird zunchst der Boolsche Ausdruck ge-
       prft.
       Ist der wahr, so geschieht nichts mehr.
       Sonst wird  compound2  ausgefhrt, und die Schleife wird (rekursiv) 
       im resultierenden Zustand erneut ausgefhrt.
       
       
       Es mu betont werden, da ausgedehntes Nutzen von Verzweigungen und 
       Schleifen der Denkweise objektorientierter Programmierung eher wider-
       spricht.
       Bei expliziten if- oder inspect-Verzweigungen ist es ntig, alle
       denkbaren Flle aufzulisten. Dies ist bei sich entwickelnder Software
       schwierig oder fhrt stndig zu tiefgreifenden nderungen.
       Der angemessene und fr objektorientiertes Programmieren empfohlene
       Mechanismus ist die (auf Vererbung beruhende) Dynamische Bindung (Ein-
       zelheiten in Teil 3).
       Dabei wird eine nicht vorherbedachte und neu zu programmierende Anwen-
       dung einer Klasse in einer neuen Klasse realisiert, welche von der
       existierenden Klasse erbt und nur die fr die neue Klasse ntigen n-
       derungen bei den features vornimmt.
       Bei solcher Vorgehensweise wird die generelle Softwarestruktur intakt
       gelassen. Dynamische Bindung garantiert, da bei Laufzeit die fr den
       dann vorgefundenen konkreten Fall genau richtige Variante des features
       benutzt wird.

       Die explizite Programmierung von Schleifen wird im Eiffel-System dem
       Benutzer oft erleichtert oder sogar ganz abgenommen.
       Viele Standard-Klassen (so Container-Klassen und Graph-Klassen)  ent-
       halten "Iteratoren", die der Benutzer mittels vorgefertigter features 
       steuern kann (siehe Teil 4).


       ----------------------------------------------------------------------

       
       Eine Klasse wird durch ihre  FEATURES  charakterisiert. Ein feature
       beschreibt einen Zugriff auf ein Objekt oder die Manipulation eines 
       Objekts.
       
       Es gibt vier unterschiedliche Formen von features.
       Ein feature ist entweder ein  ATTRIBUT , welches die im Objekt gespei-
       cherte Information beschreibt, oder es ist eine ROUTINE , die einen 
       Algorithmus beschreibt.
       Ein Attribut ist entweder eine  KONSTANTE  oder eine  VARIABLE .
       Eine Routine ist entweder eine  PROZEDUR  oder eine  FUNKTION . 

       Eine Prozedur fhrt eine Anzahl von Operationen aus.
       Eine Funktion gibt (mit dem Schlsselwort  Result ) einen Wert zurck
       und kann auch Operationen ausfhren.  

       
       Beispiel fr eine Konstante:      constant_attribute: REAL is 3.56
       
       Beispiele fr Variable:           a1, a2 : ARRAY [STRING] 
                                         count  : INTEGER 

       Beispiel fr eine Funktion:       norm : REAL is      
                                            local
                                               xx: REAL
                                               yy: REAL
                                            do
                                               xx := x * x
                                               yy := y * y
                                               Result := sqrt (xx + yy)
                                         end

       (Die vordefinierte Gre  Result  ist stets vom Typ des Funktionswer-
       tes, in diesem Beispiel also vom Typ  REAL . )

       Beispiel fr eine Prozedur:       set_x (arg: REAL) is
                                            do 
                                               x := arg
                                            end

       
       Funktionen und Prozeduren knnen Argumente haben. 
       Die obige Funktion  norm  hat kein Argument. Die Prozedur  set_x  hat
       das Argument  arg  vom Typ  REAL .


       Der Kundenzugriff auf features geschieht normalerweise ber Punktno-
       tation (eine andere Zugriffsweise benutzt Operatoren, siehe unten):
                           
                           io.put_real (p.norm)     
                           io.put_newline
       
       Diese Zugriffsweise kann iteriert werden:

                paragraph(2).line(3).second_word.set_font(bold)

       Dieser Zugriff setzt also das zweite Wort in der dritten Zeile von 
       Paragraph 2 fett.

       Bei Zugriff auf features der eigenen Klasse wie etwa 
                                 run_qsort
                                 run_sort
                                 test_if_equal
       in der Kreierungsprozedur von  SORTRACE  ist natrlich kein Punkt n-
       tig. Solche Zugriffe sind "unqualifiziert".
           
       
       Man beachte: Bei einem Feature-Zugriff wie      
                               io.put_real (p.norm)       
       ist nicht klar, was fr eine Art feature  norm  ist. 
       norm  knnte ein Attribut sein oder auch eine Funktion ohne Argumente.
       (In der Tat ist  norm  eine Funktion ohne Argumente, siehe Teil 1,
       Klasse  POINT2 .)
       Diese Unklarheit ist beabsichtigt.
       Der Kunde (in diesem Falle  p ) von  norm  braucht nur zu wissen, DASS
       das feature  norm  ihm die Norm zurckliefert.
       WIE das feature  norm  implementiert wurde, ob als Attribut oder als
       Funktion, braucht den Kunden nicht zu interessieren (jedenfalls nicht,
       solange das feature  norm  tut, was es behauptet). Diese Kenntnis wre
       fr den Kunden sogar eher strende berflutung an Information.
       Dieses "Verbergen" von Information hat einen weiteren Vorteil:
       Falls man im Zuge der Softwarenetwicklung etwas an der Implementation
       von  norm  ndern mchte, so ndert sich nur etwas an einer einzigen
       Stelle, nmlich in der Klasse  POINT2 , wo die Norm definiert wurde.
       Zugriff auf  norm  von auen geschieht unverndert mit  p.norm .


       ---------------------------------------------------------------------
       
       
       Es gibt features, bei denen aus Grnden mathematischer Tradition nicht 
       mittels Punktnotation, sondern in Operatorform zugegriffen wird. 
       Beim punkt-orientiertem Zugriff wre es beispielsweise fr die Diffe-
       renz konsequent, ein feature  subtract (r: REAL)  zu schreiben und zu-
       zugreifen mit             
                                x.subtract(y)
       
       Aber dies wird natrlich auch in Eiffel nicht gemacht und man schreibt 
       wie gewohnt                 x - y
                                  
       Dieser Unterschied ist jedoch ausschlielich syntaktischer Art!

       hnlich ist es bei anderen Standardoperationen.
       Das folgende feature stammt aus der Standardklasse  COMPARABLE :
       
       
       infix "<=" (other : like Current) : BOOLEAN is
                           -- Is Current less or equal than `other'?
           require
               other_not_void : other /= Void

           do
               Result := not (other < Current)
           end

       
       Das Schlsselwort  infix  besagt, da auf das feature in Operatorform 
        zuzugreifen ist, also so:
                              if  x <= y  then ...      
       
       und nicht so:         if  x."<=" (y)  then ...         (falsch!)

       
       Das feature  infix "<="  enthlt intern einen weiteren Operatorzugriff 
       und zwar auf das feature  infix "<"  aus der gleichen Klasse  COMPA-
       RABLE .
       
       Einige weitere Erluterungen zum feature  infix "<=" :
       Die Vorbedingung (Einzelheiten zu Vorbedingungen siehe unten)
                              other /= Void
       verlangt, da die Vergleichsgre  other  bei Funktionsaufruf kreiert
       sein mu und nicht nach  void , "ins Nichts" weist, dem Vorbelegungs-
       wert-Wert fr Verweisgren.
       
       Die Gre  other  ist vom Anker-Typ (Einzelheiten dazu siehe Teil 3).
       Current ist das in Teil 1 schon erwhnte aktuelle Objekt.
       Die Deklaration        
                              other : like Current  
       
       bedeutet also, da  other  vom Typ der aktuellen Klasse ist.
       Dies hat weitreichende Konsequenzen:
       Mittels  "<="  vergleichen kann man nun nicht nur Objekte des Typs
       COMPARABLE , sondern (per Vererbung) Objekte aller mglichen Typen.
       Der Ankermechanismus  like...  hat die angenehme Folge, da man im
       feature  "<="  die Variable  other  nicht jedesmal neudefinieren mu,
       je nachdem, welchen Typ die zu vergleichenden Objekte gerade haben.
       Vielmehr ist die Deklaration   other: like Current  in jedem Falle
       richtig.
       
       Das letzte Beispiel demonstriert auch die Notwendigkeit vordefinierten
       Gre  Current :
       Im Prinzip wird  "x <= y"  definiert durch  "nicht y < x"  und man 
       knnte versucht sein, statt
                           Result := not (other < Current)
       zu schreiben        Result := not (y < x) 
       
       Aber das geht natrlich nicht, weil man nicht nur  x  mit  y , sondern
       auch  a  mit  b , P  mit  Q  usw. vergleichen knnen will, d.h. man
       man braucht eine allgemeine Zugriffsmglichkeit auf das aktuelle Ob-
       jekt, und dazu dient in Eiffel die Gre  Current .
       
       
       ---------------------------------------------------------------------
       
       
       Das Zugriffsrecht auf die features einer Klasse kann teilweise oder
       ganz eingeschrnkt werden.
       Eine Exportliste der Form            
                      
                          feature  {class1,class2}
                          ...    --  nachfolgende features
       
       in der Feature-Deklaration bedeutet, da lediglich  class1,  class2  
       (oder deren Erben) Klienten der nachfolgenden features sein knnen.
       Die Exportliste    
                               feature  {NONE}
       
       bedeutet, da kein Klient auf die nachfolgenden features zugreifen
       darf. Die features sind dann effektiv geheim, also nur in der lokalen 
       Klasse selbst benutzbar. Ein Beispiel aus der Containerklasse von
       Eiffel/S :

       
       class   ARRAY2 [G]

       creation
           make 

       feature  { ANY }

           size1 : INTEGER
           size2 : INTEGER
           
           make (s1, s2 : INTEGER, init_val : G) is  ...
           
           item (i, j : INTEGER) : G is  ...
           put (x : G, i, j : INTEGER) is  ...
 
       feature { NONE }
           store : ARRAY [G]
       
       end -- class ARRAY2

       
       In dieser Klasse  ARRAY2  sind rechteckige Matrizen implementiert, und
       den Benutzer interessierende Dinge sind  size1 (Zeilenzahl), size2
       (Spaltenzahl) und Prozeduren wie  item  und  put , mit denen er Ein-
       trge in die Matrix einladen oder aus ihr herausholen kann.
       In der Tat ist die Matrix als eindimensionales Array
                                store : ARRAY [G]   
       implementiert. Dies braucht den Kunden aber nicht zu interessieren; es
       gibt keinen Grund fr ihn, auf  store  zuzugreifen.
       Konsequenterweise wird  store  nach auen hin geheimgehalten.


       --------------------------------------------------------------------


       Ein Feature-Zugriff auf eine Prozedur liefert eine  INSTRUKTION , die
       bewirkt, da Operationen ausgefhrt werden:
                     
                       meine_Bank.berweise (10000 , heute)

       Ein Feature-Zugriff auf ein Attribut oder eine Funktion produziert
       einen  AUSDRUCK , der mit einem Wert verbunden ist:

                          mein_Konto.Stand (heute)

       Diese beiden Beispiele benutzen die eiffel-typische Punkt-Notation.
       Bei Ausdrcken, wo die features, auf die zugegriffen wird, mathema-
       tische Operatoren sind, benutzt auch Eiffel durchweg die traditionelle
       Operatorsyntax, beispielsweise beim Gleichheits- oder bei Vergleichs-
       operatoren:

                   Gleichung:          count = a1.size         
                   Ungleichung:           i < count       
       

       Im folgenden werden einige der Festlegungen von Eiffel fr Operator-
       ausdrcke aufgelistet.

       Fr Gleichungen bzw. Ungleichungen werden benutzt:
                                
                            " = "   bzw.   " /= "
       
       Weiter werden benutzt
       Einstellige Operatoren:    
                              not | + | - |
       zweistellige Operatoren:   
                           + | - | * | / | ^ (Potenz)
                           < | > | <= | >= |
                           // (ganzzahlige Division) 
                           \\ (ganzzahliger Rest)
                           and | or | xor (entweder-oder)
                           and then | or else | implies

       Die Prioritten dieser Operatoren sind in Eiffel wie auch sonst blich
       definiert (vergl. Handbuch S.377).

       Was es mit dem Operator  "or else"  auf sich hat, zeigt die Schleife
       
            from
                i := 1
            until
                i > count  or else  not a1.item (i).is_equal (a2.item (i))
            loop
                i := i + 1
            end
       
       aus dem Programm  SORTRACE , mit der die Inhalte der Arrays  a1  und
       a2  auf Gleichheit geprft werden.
       Hier wird die Schleife abgebrochen, wenn mindestens eine der Bedingun-
       gen
                     "Laufindex grer als Arraylnge"       bzw.
                     "die beiden Eintrge sind verschieden"
       zutreffen.
       Und zwar wird bei  "or else"  die zweite dieser beiden Aussagen ber-
       haupt nur geprft, wenn die erste "false" liefert.
       Im Beispiel ist dies genau das, was man braucht: Wrde die zweite Aus-
       sage auch im Falle  i > count  geprft, so wre  item(i)  gar nicht
       definiert und es gbe vermutlich einen Laufzeitfehler.

       Analog wie bei  "or else"  ist es bei  "and then" :
       Die nach  "and then"  folgende Aussage wird nur geprft, wenn die vor-
       stehende Aussage  "true"  liefert.

       
       ----------------------------------------------------------------------

       
       Es folgen einige Bemerkungen zur Semantik von Gleichheit und Wertzu-
       weisung.
       Was geschieht bei einer Zuweisung  y := x  ?
       Gilt danach  x = y  , und was bedeutet  x = y  genau?
       Im vorigen Beispiel wurde eine andere Form der Gleichheit benutzt:
                      a1.item (i).is_equal (a2.item (i))
       Was bedeutet das ?
       Fragen dieser Art sind nichttrivial in Sprachen, die Verweissemantik
       benutzen.
       
       Man mu unterscheiden, ob die beteiligten Gren Verweisgren oder
       einfache Gren sind:
       Sind  x  und  y  Verweisgren, so bewirkt die Zuweisung
                                
                                   y := x
       
       da  y  an das gleiche Objekt gebunden wird wie  x . Nach der Zuwei-
       sung weisen die Gren  x  und  y  also auf das gleiche Objekt.
       
       Sind bei obiger Zuweisung beide Gren  x  und  y  einfache Gren 
       (wo die Werte also nicht Verweise auf Objekte, sondern Objekte selber 
       sind), so bewirkt die Zuweisung  y := x , da das zu  x  gehrende 
       Objekt auf das zu  y  gehrende Objekt kopiert wird.

       [ Randbemerkung:
       Bei der Zuweisung  y := x  mssen die Typen von  x  und  y  nicht not-
       wendigerweise gleich sein. Oft sind sie gleich. Zumindest mu die zu 
       x  gehrende Klasse ein Nachkomme von der zu  y  gehrenden Klasse 
       sein.
       Bei allen in diesem Abschnitt beschriebenen Zuweisungen und Verglei-
       chen mssen hnliche "Konformittsbedingungen" erfllt sein. Nheres 
       dazu in Teil 3. ]

       Die beiden folgenden Fragmente illustrieren den Unterschied von ein-
       fachen Gren und Verweisgren bei Zuweisungen:

                             x,y : INTEGER  --  x , y einfache Gren
                             ...
                             x := 2
                             y := x
                             x := 4
       
       Hier sind  x  und  y  einfache Gren. Sie haben bei Programmende ver-
       schiedene Werte: x=4 , y=2.

                             p,q : POINT  --  p,q  IR  Verweisgren
                             ...
                             !!p
                             p.set_x (2)
                             p.set_y (2)
                             q := p
                             p.set_x (4)
                             p.set_y (4)

       Hier sind  p  und  q  Verweisgren. Bei Programmende sind die Punkte 
       gleich:  p = q = (4,4) .
       
       Ersetzt man die beiden letzten Programmzeilen durch
                                q.set_x (4)
                                q.set_y (4)
       so ist das Resultat genau das gleiche:  p = q = (4,4) .

       Man erkennt:
       Die Zuweisung  y:=x  bindet VERWEIS-Gren  x  und  y  an einunddas-
       selbe Objekt. Manipuliert man dann (gleichgltig wie) das (eine) Ob-
       jekt, so hat das unweigerlich identische Folgen fr  x  wie fr  y .
       Mchte man  y  an ein Objekt binden, das mit dem von  x  identisch ist
       und dennoch  x  und  y  unabhngig weiterbehandeln knnen, so ist es
       offensichtlich ntig, zwei Kopien des gleichen Objektes zu haben,
       eines fr  x  und eines fr  y .
       
       Zu diesem Zweck existiert in Eiffel die vordefinierte Prozedur
                          
                          copy (other: like current)  

       (Man knnte auch die Funktion  clone  benutzen, siehe Teil 3.)
       
       copy  ist eine Prozedur, die  other  auf das aktuelle Objekt kopiert.
       Die Instruktion
                                 y.copy (x)

       ersetzt das mit  y  verbundene Objekt durch eine Kopie von  x .

       
       Die Zuweisung  y := x  bindet  y  an das gleiche Objekt wie  x .
       Der copy-Befehl bindet  x  und  y  an unterschiedliche Objekte glei-
       chen Inhalts. 
       Bei Sprachen mit Verweissemantik gibt es also offensichtlich keinen
       eindeutigen Begriff von Gleichheit und es ist notwendig, klar zu defi-
       nieren, was man meint.

       Die Gleichung                 x = y

       bedeutet (fr Verweisgren), da  x  und  y  auf das gleiche Objekt
       verweisen.
       
       Fr verschiedene Objekte, die aber dennoch Feld fr Feld bereinstim-
       men, gibt es in Eiffel das vordefinierte feature 
              
                    is_equal (other: like current): BOOLEAN

       (Man knnte auch  equal  benutzen, siehe Teil 3.)       
       
       Der Ausdruck  y.is_equal (x)  hat also den Wert  true , wenn die zu
       x  und  y  gehrenden Objekte Feld fr Feld bereinstimmen (auch wenn
       die Objekte physisch verschieden sind).

       
       ----------------------------------------------------------------------


       Ein vor allem fr die Testphase eines Programms wichtiges Eiffel-Ele-
       ment ist das der Zusicherung (Assertion). Zusicherungen prfen (pau-
       schal gesagt), ob Dinge, die man vom Programm erwartet, auch wirklich 
       geschehen.
       Zusicherungen gibt es in folgenden Formen:
                       Vor- und Nachbedingung einer Routine
                       Invariante einer Schleife
                       Invariante einer Klasse

       Der Benutzer hat mit dem RCL-file (Runtime Control Language) die Mg-
       lichkeit, diese Kontrollen alle oder teilweise zu aktivieren oder auch
       zu desaktivieren.
       
       Das folgende Beispiel stammt aus der Standardklasse  ARRAY :


       put (element : G, index : INTEGER) is
                           -- Put `element' at position `index'.
           require
               inside_bounds : lower <= index and then index <= upper
           do
               special.put (element, index - lower)
           ensure
               item_in_place : item (index) = element
           end
       
       
       Hier sind  lower  und  upper  Attribute der Klasse  ARRAY , die das
       Indexintervall angeben.
       Die Klausel
                                inside_bounds :  
       funktioniert syntaktisch wie ein Kommentar und drckt verbal aus, was
       die Vorbedingung 
                       lower <= index and then index <= upper
       bedeutet: der Index des neu einzufgenden Elements mu zum Indexinter-
       vall des Arrays gehren. 
       Die Nachbedingung     
                              item (index) = element
       von  put  ist genauso einleuchtend und drckt exakt aus, da  element
       sich an der Position  index  befinden soll.


       Die Funktionsweise von Vor- und Nachbedingung einer Routine wird von
       Bertrand Meyer pointiert so beschrieben:
       Die                  VORBEDINGUNG BINDET DEN KUNDEN
       der Routine; sie benennt die Voraussetzungen, unter denen der Aufruf
       der Routine erlaubt ist.
       Die                 NACHBEDINGUNG BINDET DIE ROUTINE
       selbst; die Routine garantiert die Nachbedingungen bei Beendigung der
       Routine, sofern die Vorbedingungen bei Aufruf der Routine vorgelegen
       haben.


       Schleifeninvarianten und Klasseninvarianten finden sich in den Klassen
       von Eiffel/S kaum.
       Beim Heapsort-Sortieralgorithmus findet sich immerhin eine Schleifen-
       invariante in Form eines Kommentares:
       
       spec_heapsort is
           local
              ...
           do
              ...
              from
                  i := n
              invariant
                  -- a[i .. n] is sorted
              until
                  i = 1
              loop
              ...
              end
        ensure
           -- a[1 .. n] is sorted
        end         
       
       
       Das Array wird also von hinten nach vorn sortiert und die Invariante
       verlangt, da der hintere Teil des Arrays sortiert bleibt.
       
       Die Semantik einer Schleifeninvariante ist: Gilt die Abbruchbedingung
       der Schleife nicht und gilt die Invariante bei Eintritt in die Schlei-
       fe, so mu die Invariante auch gelten bei Verlassen der Schleife.


       Das folgende ist ein Phantasiebeispiel einer Klasseninvariante:


       class RECHTWINKLIGES_DREIECK
       
       inherit  
          MATH
          end
        
       feature
          epsilon: REAL is 0.0000001

          a : Real
          b : REAL
          c : REAL is...
          
          ...
       invariant
          konsistent: abs (c^2 - (a^2+b^2)) < epsilon
       end  --  class RECHTWINKLIGES_DREIECK

       
       Ein weiteres Beispiel: Bume sind spezielle Graphen, und zwar solche,
       die azyklisch sind (keine Kreise haben) und eine Ecke mehr haben als
       Kanten.
       Implementiert man Bume durch Spezialisieren der Eiffel-Klasse GRAPH ,
       so wren mgliche Klasseninvarianten 
                                    acyclic
                               n_vert = n_edge + 1

       
       In Eiffel wird groer Wert auf Fehlerkontrolle gelegt. Ein hierfr
       wichtiges Sprachelement ist die Rescue-Klausel. Ein Beispiel einer
       Rescue-Klausel findet sich in der Kreierungsprozedur von  FILEDEMO :

       
       make is
          local ch : CHARACTER
          do 
             from
                io.put_string ("Zuerst obersten Menpunkt whlen %N%N")
             until
                ch = 'q'
             loop
                show_menu
                io.get_char
                ch := io.last_char
                inspect ch
                   when  'e'  then  get_data
                   when  'a'  then  change_data
                   when  's'  then  store_data
                   when  'z'  then  show_data
                   else if ch /= 'q' then
                        io.put_string ("Unbekanntes Zeichen %N") end
                end
             end
   
             rescue
                io.put_string ("Fehler bei der Menreihenfolge %N")
                retry
          end

       Die innere Logik dieses Programms verlangt, da man eine Matrix, die
       man sehen, ndern oder speichern mchte, vorher in der Arbeitsspeicher
       geladen hat. Hlt man sich nicht an diesen Rat, so gibt es Laufzeit-
       fehler mit je nach Kompiliermodus und RCL-Status unterschiedlichen
       Folgen.
       Bei Auftreten eines solchen Fehlers tritt die Rescue-Klausel in Aktion,
       weist auf das Problem hin, und man darf erneut versuchen.

       
       ---------------------------------------------------------------------

       
       Das folgende Programm ist eines der in  Eiffel/S 1.2  mitgelieferten
       Beispielprogramme:


       class   SORTRACE
       
       inherit
           INTERACT
           end

           ENVIRONMENT
           end

           SYSTEM_TIME
           end

       creation
           make
   
       feature

           a1, a2 : ARRAY [STRING] 
           count  : INTEGER 
           sort   : SORTER [STRING] 
           qsort  : QSORTER [STRING] 
           error  : BOOLEAN

       -----------------------------------------------------------

           make is

               do
                   if not error then
                       load_list
                   end

                   if not error then
                       io.put_string ("Sorting ")
                       io.put_int (count)
                       io.put_string (" elements%N")

                       run_qsort
                       run_sort
                       test_if_equal
                   end
                   io.put_newline
               
               rescue
                   error := true
                   retry 
               end
       -----------------------------------------------------------

           load_list is

               local
                   i    : INTEGER
                   f    : TEXTFILE
                   path : STRING

               do
                   if not error then
                       if arg_count > 0 then
                           path := arg_item (1)

                       else
                           give_help ("sortrace.hlp")
                           get_a_string ("Name of ASCII file : ")
                           path := the_string
                       end

                       if not fs.file_exists (path) then
                           io.put_string ("Sorry; file does not exist%N")
                           error := true

                       elseif not fs.has_readperm (path) then
                           io.put_string ("Sorry; do not have permission%N")
                           error := true

                       else
                           !!f.connect_to (fs.access_file (path, "r", false))
                           count := f.count 

                           from
                               !!a1.make (1, count)  
                               i := 1
                           until
                               i > count
                           loop
                               a1.put (f.item (i), i)
                               i := i + 1
                           end

                           f.abort
                           a2 := clone (a1)
                       end
                   end

               rescue
                   if f /= void then
                       f.abort
                   end

                   error := true
                   retry
               end
       -----------------------------------------------------------

           run_qsort is

               local
                   time : INTEGER

               do
                   !!qsort

                   time := sysclock
                   qsort.sort (a1, 1, count)

                   io.put_string ("quicksort : ")
                   io.put_int (sysclock - time)
                   io.put_string (" ms%N")
               end
       -----------------------------------------------------------

           run_sort is

               local
                   time :INTEGER

               do
                   !!sort

                   time := sysclock
                   sort.sort (a2, 1, count)

                   io.put_string ("heapsort  : ")
                   io.put_int (sysclock - time)
                   io.put_string (" ms%N")
               end
       -----------------------------------------------------------

           test_if_equal is
               local
                   i : INTEGER
               do
                   from
                       i := 1
                   until
                       i > count or else not a1.item (i).is_equal (a2.item (i))
                   loop
                       i := i + 1
                   end

                   if i <= count then
                       io.put_string ("The arrays didn't agree%N")
                   end
               end

       end -- class SORTRACE

       
       Zur Erluterung:
       Dieses Programm ist ein Rahmenprogramm, das die in den Klassen  SOR-
       TER  und  QSORTER  implementierten Sortieralgorithmen  Quicksort  und
       Heapsort  aufruft und gegeneinander laufenlt.
       Sortiert werden Arrays von Strings.
       Angenommen, das Programm wird laufen gelassen mit der Befehlszeile
                               sortrace dos_data
       (Die mitgelieferte ASCII-Datei  dos_data  enthlt einige hundert unsor-
       tierte Strings.)
       Zunchst wird die Prozedur  load_list  aufgerufen.
       Das feature  arg_item  der geerbten Klasse  ENVIRONMENT  greift mit
       arg_item (1)  auf den (nach dem Programmnamen  sortrace ) ersten
       String der Befehlszeile zu (hier also auf den String  dos_data ).
       Das Textfile  f  wird an das gefundene physische File mit dem Namen
       path (hier  path = dos_data ) angebunden.
       Dann wird in einer Schleife der Inhalt des Textfiles in das Array  a1  
       bertragen.
       Schlielich wird mit  a2 := clone (a1)  das Array  a2  an eine identi-
       sche Kopie von  a1  gebunden.
       In  run_qsort  wird die Zeit genommen, der Quicksortalgorithmus auf
       das Array  a1  angewandt und dann die Differenzzeit auf den Bildschirm
       ausgegeben.
       In  test_if_equal  wir geprft, ob die sortierten Arrays wirklich
       bereinstimmen, d.h. ob die beiden Algorithmen gemacht haben was sie
       hatten machen sollen.
