 Herzlich willkommen zurück zu Programmierparadigmen. Wir sind hier in Teil 3 des Moduls Kontrollfluss und in diesem dritten Teil soll es um Auswahlmöglichkeiten geben, also Verzweigungen im Programm, wo der Programmierer bestimmen kann, in welche Richtung der Kontrollfluss weitergeht. Wir arbeiten uns sozusagen so ein bisschen hoch in den Abstraktionsleveln, also werden wir angefangen im ersten Teil dieses Moduls mit den Ausdrücken und in welche Reihenfolge diese Ausdrücke evaluiert werden, haben dann im zweiten Teil angeschaut, was es denn für nicht so richtig strukturierte Kontrollflussmechanismen gibt, insbesondere Go-Tools und Continuations und sind jetzt an der Stelle, wo bestimmte Sprachkonstrukte, die uns helfen, im Programm zu entscheiden, wo es genau weitergehen soll zu nutzen und wir werden uns insbesondere auch ein bisschen anschauen, wie die denn kompiliert werden, also nicht nur die Sicht des Programmierers, sondern auch mal kurz die Sicht von denen, die die Sprache schlussendlich implementieren nehmen. Fangen wir mal vielleicht an mit der einfachen Frage, was ist denn überhaupt dieses Selection oder dieser Auswahl, von der ich hier spreche? Also die Grundidee ist eigentlich ganz simpel und ich vermute, dass die meisten das auch schon mal beim Programmieren gesehen haben, nämlich wir haben irgendwo eine Verzweigung im Programm und wo der Kontrollfluss dann weitergeht, also ob jetzt diesen Zweig oder jeden Zweig nehmen, hängt von einer Bedingung ab, die zur Laufzeit evaluiert wird. Diese Bedingung kann zum Beispiel ein Boolean sein, also ein Wert, der entweder True oder False ist und je nachdem, wo wir dann, je nachdem ob es True oder False ist, gehen wir dann den einen Weg oder den anderen oder es gibt auch Varianten, wo es mehr als zwei mögliche Ausgänge gibt und das Programm dann entsprechend einen dieser Wege wählt, je nachdem wie diese Bedingung auswählt. Es gibt ja verschiedene syntaktische Varianten, also wie das schlussendlich in Sprachen syntaktisch umgesetzt ist. Die zwei häufigsten sind auch die, die wir uns hier ein bisschen genauer anschauen wollen, nämlich zum einen die if else Statements, also wo wir einfach eine Bedingung haben und dann gehen wir entweder in den if Branch oder in den else Branch oder case switch Statements, wo es mehr als zwei Möglichkeiten geben kann und je nachdem wie eine Bedingung dann ausgeht, eine dieser Möglichkeiten der Weg ist, wo das Programm anschließend weiter ausführt. Schauen wir uns zunächst das mal die if statement oder if else Statements ein bisschen genauer an. Obwohl es ja eigentlich ein sehr einfaches und doch universelles Konstrukt ist, gibt es da relativ große syntaktische Unterschiede zwischen den verschiedenen Programmiersprachen. Je nachdem, wo die Sprache herkommt, also wie die so entstanden ist und von welchen anderen Sprachen, die irgendwann mal abgeleitet wurde, sieht die Sündungsdann manchmal sehr anders aus, als man es vielleicht kennt. Also in Sprachen, die von algo 60 abstammen oder in irgendeine Form davon stark beeinflusst wurden, sieht das in der Regel so aus, wie man es hier sieht. Das ist zum Beispiel dann auch so ähnlich, wie man es vielleicht aus C oder Java kennt. Also das if und else sind einfach die entsprechenden Keywords und dann gibt es noch irgendeine Form, den Block, der beginnt, wenn diese eine Bedingung war oder eben die andere Bedingung war es, dann abzugrenzen. Ein bisschen anders sieht es zum Beispiel in Bash aus. Bash ist ja auch eine Programmiersprache. Auch da haben wir ein Keyword für if und die die Umgrenzung der entsprechenden Blöcke hat dann lustigerweise dieses Fee. Also das Block Ende vom if Block endet mit Fee, also sozusagen das if anders herum. Auch die Bedingung sieht ein bisschen anders aus. Es gibt da zum einen diese eckigen Klammern rings herum und dann ist zum Beispiel auch der Gleichheitsoperator in dem Fall eben nur das einfache ist gleich und nicht das doppelte wie in den Algo 60 Familien. Eine dritte Variante sieht man hier. Also das ist aus Blisp, einer funktionalen Programmiersprache, die wir uns ganz im Ende der Veranstaltung auch noch ein bisschen genauer anschauen wollen. Und was hier passiert ist, dass wir das if dadurch ausdrücken, dass wir sagen, es gibt da diese Funktion namens KONT. Was das genau bedeutet, schauen wir uns dann am Ende der Veranstaltung noch genauer an. Aber schlussendlich bedeutet das auch das Gleiche, was hier drüben schon zweimal in anderen Sprachen steht. Nämlich, dass ich verschiedene Bedingungen abfrage, zum Beispiel das A gleich B ist oder das A gleich C ist oder wenn das nicht der Fall ist einfach true. Also sozusagen, wenn die anderen Sachen nicht true sind, dann ist das auf jeden Fall immer true. Und dann habe ich genau wieder meine Fälle, die hier abgearbeitet werden und die dann ja je nachdem, wie die Bedingungen ausgeht ausgeführt werden. Neben der Sündtags wollen wir uns für die verschiedenen Auswahlkonstrukte, die es in Programmiersprachen gibt, auch mal anschauen, wie die denn eigentlich kompiliert werden. Das heißt, wir schauen uns auch mal ein bisschen an, wie das ganze so von der Seite der Sprachimplementierung ausschaut. Fangen wir mal wieder mit den if-Statements an und schauen uns einfach an, wie genau die kompiliert werden. Als Beispiel schreibe ich erstmal eine kleine, kleines if-Statement auf und zwar hat es mehrere Teilausdrücke in der Bedingung drin. Ups, noch nicht, sondern ich sage if und dann wenn A größer B ist und C größer D ist. Oder, es gibt noch eine andere Variante, nämlich, dass E und gleich F ist. Dann gehen wir den Einweg, also dann kommt hier, was ich jetzt einfach mal als when clause abkürze. Oder, falls wir den Weg nicht gegangen sind, gibt es dann noch den anderen und das ist einfach die else clause. Wenn so ein Compiler das jetzt übersetzt, dann würde der das in irgendein Assembler Sprache oder irgendeine Maschinsprache übersetzen. Ich zeige es jetzt einfach mal mit so einer kleinen Spiel-Essampler ähnlichen Sprache, in der wir Werte in Register schreiben. Und in dem Fall wäre das erste, was passiert, ist, dass wir in ein Register, nämlich mal Register 1, den Wert von A schreiben und anschließend in ein anderes Register, nennen wir es mal Register 2, den Wert von B. Jetzt kommt die erste Überprüfung, nämlich ob der Wert, der in A ist, kleiner gleich dem Wert, der in B ist. Und das sieht dann so aus, dass ich hier diese Überprüfung habe. Und was ich in dem Fall nämlich mache, ist, dass ich schon mal weiß, dass der das End im ersten Teil unseres Bedehungsausdrucks nicht wahr werden kann. Das heißt, wir gehen dann an eine bestimmte Stelle, die wir gleich aufschreiben, die heißt dann L4. Wenn das nicht der Fall ist, das heißt, wenn also A größer als B ist, sprich der erste Teil unseres End-Ausdrucks könnte oder der erste Teil ist wahr. Das heißt, der gesamte End-Ausdruck könnte nach wahr werden. Also springen wir nicht weg, sondern gehen mal weiter und schauen uns dann C und D an, indem wir die Werte jeweils wieder in diese Register schreiben. Da können wir dieselben Register nehmen, weil wir A und B an der Stelle gar nicht mehr brauchen. Und hier schauen wir jetzt, ob C größer als D ist, indem wir schauen, ob das, was in Register 1 ist, größer als das, was in Register 2 ist. Und wenn das der Fall ist, müssen wir also dann auch nicht mehr überprüfen, ob E und gleich F ist. Und wir wissen, dass wir dann zu unserer Venklaus direkt springen können. Und das ist eine Location L1, die ich dann auch gleich zeig. Jetzt kommt zunächst einmal der Fall, den wir vorhin ausgelassen haben. Nämlich, als wir gesagt haben, wir springen zu L4, wenn A nicht größer als B ist. Denn in dem Fall würden wir dann überprüfen, ob E und gleich F ist, also ob der zweite Teil unseres Ohr-Ausdrucks wahr werden könnte. Auch dafür laden wir wieder die Werte, um die es geht, nämlich E und F, in diese Register R1 und R2. Und schauen dann, in dem Fall, ob die gleich sind. Also die Negierung von dem Ausdruck, der sonst eigentlich so im Kot steht. Und falls das der Fall sein sollte, springen wir direkt zur L-Claus. Denn dann wissen wir, dass beide Teile dieses Ohrs eben nicht wahr sind. Das heißt, die Bedingung, um in das F reinzugehen, ist garantiert nicht wahr, sondern wir müssen zum L-Claus. Und das ist in dem Fall dann an einer Location L2. So, jetzt hat mal die Location L1 vorhin schon erwähnt. Das ist nämlich die, wo die Venklaus steht. Und da steht dann natürlich praktisch mehr als nur dieses eine Venklaus, diese Zeile, sondern da stehen dann natürlich mehr Instruktionen. Und wenn alles, was da drin steht, dann ausgeführt wurde, dann geht es ganz zum Ende, also sozusagen hinter dieses komplette F-L-Statement. Und die Stelle nenne ich einfach mal L3. Vorher gibt es aber noch den anderen Fall, nämlich, dass wir in den L-Sbranche reingehen. Und das war diese Location L2, die wir vorhin ja gerade schon gesehen haben. Und hinter der, das besteht natürlich dann potenziell auch wieder aus mehreren Instruktionen, kommt dann irgendwo die Location L3, zu der wir springen oder nachdem wir die L-Claus ausgeführt haben, dann automatisch kommen. Was man in diesem einfachen Beispiel schon recht gut sehen kann, ist wieder compiler bestimmte Aspekte der Implementierung von Kontrollfluss, die wir vorhin schon mal kurz besprochen haben, hier umsetzt. Also das eine, was in dem vorherigen Teil in diesem Modulier schon vorkam, ist diese sogenannte Short-Circuited Evaluation. Also nochmal zur Erinnerung, das war die Idee, dass wir bei einem logischen Ausdruck oft den zweiten Teil gar nicht evaluieren müssen, weil wir schon vorher wissen, was dieser logische Ausdruck insgesamt ergibt. Und für unseren End-Ausdruck, den wir hier in dem Beispiel haben, zeigt sich das hier ganz gut, weil wir an der Stelle, wenn wir wissen, dass A kleiner gleich B ist, also A nicht größer als B ist, dann wissen wir, dass unser End hier oben, das tatsächlich auch nicht zu true evaluieren kann. Das heißt, wir müssen gar nicht mehr C und D vergleichen, sondern können direkt zu der Stelle dahinter springen. Ein anderer interessanter Aspekt ist, wie der Compiler diesen Kontrollfluss, der ja eigentlich nicht linear ist, doch in diese lineare Sequenz von Instruktionen reinzwängt. Und zwar dadurch, dass er ganz einfach an bestimmten Stellen einfach immer durchfällt. Also dadurch, dass man nicht irgendwo anders hinspringt, fällt man schlussendlich auf einen bestimmten Fall oder geht einen bestimmten Weg in den möglichen Kontrollflüssen, die es hier gibt. Also ein Beispiel ist zum Beispiel diese Send-Clause, die man unter anderem ja erreichen kann, indem man einfach all die Instruktionen, die oben drüber steht, ausführt und nie eines der Go-Tools nimmt. Und schlussendlich dadurch, dass man einfach nie woanders hingeht, kommt man dann schlussendlich automatisch bei der Send-Clause raus. Das zweite Ausfallkonstrukt, was wir uns hier ein bisschen genauer anschauen wollen, sind die Case-Switch-Statements. Die Grundidee dabei ist, dass man mehrere Auswahlmöglichkeiten hat, wo der Kontrollfluss als nächstes hingehen kann. Und diese Auswahl wird zur Laufzeit getroffen, in dem eine bestimmte Expression verglichen wird mit einer Reihe von Compile-Zeit-Konstanten. Hier auf der Folie sehen wir mal ein Beispiel zur Abwechslung mal in Ada-Syntax. Also was wir hier haben ist dieses Case-Keyword, wo dann hier statt dem Punkt-Punkt-Punkt irgendeine Expression steht, die potenziell auch sehr komplex sein kann. Und der Wert, zu der diese Expression dann schlussendlich evaluiert, wird anschließend verglichen zu diesen verschiedenen Fällen, die wir hier unten haben. Also wir sehen da zum Beispiel, wenn diese Expression zu 1 evaluiert, dann wollen wir hier Clause A ausführen. Falls die Expression zu 2 oder 7 evaluiert, wollen wir Clause B ausführen. Falls der Wert zwischen 3 und 5 liegt, dann wird's Clause C. Falls der Wert 10 ist, dann wollen wir Clause D. Und falls irgendwas anderes rauskommt, dann wollen wir Clause E ausführen. Von der Terminologie her, man nennt diese möglichen Werte oft auch Labels. Und das, was dann entsprechend ausgeführt wird, wenn eben eines dieser Labels den gleichen Wert hat, wie das, was beim Evaluieren der Expression rauskommt, das nennt man auch die Arms. Also sozusagen die Arme oder Wege, die man aus diesem Case-Switch-Statement herauswählen kann. So schauen wir uns mal wieder an, wie das Ganze kompiliert wird. Also wie würde der Compiler das dann schlussendlich auf Assembler oder auf eine Maschinensprache übersetzen? Ich lass den Code mal so ein bisschen im Hintergrund und dann schreibt man mal daneben, was beim Kompilieren dieses Case-Switch-Statements dann rauskommt. Also es geht zunächst, dass man damit los, dass wir die Expression evaluieren, da die im Code ja auch nur Punkt, Punkt, Punkt ist, schreibe ich da auch nicht viel mehr zuhin, außer dass das eben ganz einfach die Evolution von dieser Expression ist, die kontrolliert, wo wir dann schlussendlich langlaufen. So und dann werden im Prinzip die einzelnen Bedingungen oder die einzelnen Fälle nacheinander abgefragt und je nachdem, was dann wahr oder falsch ist, werden dann die verschiedenen Arme dieses Case-Switch-Statements ausgeführt. Also zunächst schauen wir erstmal, ob unser Wert, der jetzt in Register 1 liegt, gleich oder ungleich zu 1 ist. Hier ist wieder dieser Trick, dass wir im Prinzip das überprüfen, was wir im Source Code eigentlich nicht sehen, sondern genau das Gegenteil davon. Und in dem Fall würden wir dann zu L1 gehen. Falls wir diesen Sprung nicht machen, fallen wir sozusagen durch auf den Fall, wo wir Clause A tatsächlich ausführen. Also das wären dann sozusagen die Instruktionen, die hier danach kommen. Wenn wir das gemacht haben, dann müssen wir in diesem Fall, weil es unten ja diesen When Others-File gibt, aus diesem ganzen Statement wieder raus, aus dem ganzen Case-Switch Statement. Und das tun wir, indem wir dann zu einer Location namens L6 springen würden, die ich ganz am Ende dann unten dran hängen. Also L6 ist sozusagen der Punkt, wo wir hinspringen, wenn wir ein Fall als den richtigen erkannt haben und dann die entsprechenden Instruktion in dem Fall ausgeführt haben. So, wenn wir jetzt nicht Clause A ausführen, dann überspringen wir sozusagen diesen Teil und gehen dann hierher. Und das ist genau diese Location L1, die ich hier oben schon kurz erwähnt habe. Die nächsten Fälle im Code sind, dass der Wert gleich 2 oder gleich 7 ist. Also was wir dann hier machen werden, ist, dass wir das Ganze überprüfen. Schauen also, ob in R1 der Wert 2 drin ist, wenn das der Fall ist, springen wir an eine bestimmte Stelle. Und falls wir da nicht hingesprungen sind, schauen wir noch, ob wir hier den Wert 7 haben. Hier machen wir wieder diesen Trick mit dem Niggieren, sodass wir, falls der Wert 7 ist, eben einfach nicht zur L3 springen, sondern hier weiterlaufen. Und hier haben wir dann die Clause B, so der wir also kommen können, indem wir entweder dieses Go to L2 ausführen oder eben in der Instruktion unten drunter dann nicht zur L3 springen. In jedem Fall, falls wir das gemacht haben, müssen wir danach das Case Switch Statement wieder beenden und tun das, indem wir wieder zur Location L6 springen. So, ähnlich geht es dann weiter für die anderen Fälle. Für den Fall, dass unser Registerwert nicht 7 war, wollten wir jetzt zu einer Location L3 springen. Und das ist nämlich genau die, wo wir dann den nächsten Fall anschauen. Der nächste Fall soll schauen, ob der Wert zwischen 3 und 5 liegt. Das machen wir hier in dem kompilierten Code so, dass wir schauen, ob R1 kleiner als 3 ist, also eben nicht in diesem Range drin liegen kann. Und falls das so ist, gehen wir zur Location L4. Und anschließend, falls wir da nicht hingegangen sind, schauen wir, ob unser Wert R1 größer als 5 ist, also sozusagen auch außerhalb des Bereichs ist. Und wenn das der Fall sein sollte, gehen wir auch zur L4. Wenn wir keinen dieser Sprünge genommen haben, wissen wir, dass der Wert also zwischen 3 und 5 liegt. Das heißt, wir können dann diese Clause C ausführen und dann auch entsprechend wieder aus dem gesamten Statement rausgehen, indem wir zur L6 springen. So, jetzt haben wir nur noch einen regulären Fall oder einen speziellen Fall übrig. Nämlich der, dass es, dass der Wert 10 ist. Wohin diese 2 go to zur L4? L4 kommt jetzt nämlich genau hier, wo wir schauen, ob der Wert in R1 ungleich 10 ist, also wieder dieser Durchfall-Trick. Wenn das der Fall ist, gehen wir zur L5. Wenn wir da nicht hingesprungen sind, haben wir dann hier Clause D, also den Fall dafür, dass der Ausdruck zu 10 evaluiert hat. Und wenn das getan wurde, müssen wir wieder zur L6 gehen. Und jetzt schreibe ich mal hier oben weiter. Und da ist nämlich nur noch diese eine Location L5, wo wir diesen Standardfall, also das, was hier mit 1 others ausgedrückt wurde, behandeln. Da haben wir dann Clause I. Und schlussendlich, ganz am Ende des ganzen, haben wir L6, wo dann der Code kommt, der nach diesem Case-Switch-Statement ausgeführt wird, also was auch immer in die Programm anschließend kommt, das finden wir dann hinter dieser, hinter diesem Label L6. So, dieser Code ist jetzt schön und gut. Der hat aber einen großen Nachteil. Und der ist nämlich, dass wir im Prinzip linear durch die verschiedenen Fälle durchwandern. Das heißt, wenn wir den when others Fall am Ende erreichen wollen, müssen wir vorher erst alle anderen Bedingungen überprüfen. Das heißt, also der große Nachteil von der Art dieses Case-Switch-Statement zu kompilieren ist, dass wir im Prinzip so einen linearen Pass durch die verschiedenen, ja, durch die verschiedenen Bedingungen machen. Jetzt in dem kleinen Beispiel macht es vielleicht keinen so großen Unterschied, aber man kann sich vorstellen, dass natürlich auch Case-Switch-Statements mit deutlich mehr Fällen gibt. Und dann macht es natürlich schon einen Unterschied, ob ich da jetzt durch alle Fälle immer erst mal durchlaufen muss, um dann festzustellen, dass es vielleicht doch der Letzte war oder ob man das vielleicht noch ein bisschen cleverer machen kann. Ein Weg dieses Case-Switch-Statement cleverer zu kompilieren, nämlich in Maschinencode, der nicht durch alle Bedingungen linear durchlaufen muss, ist mithilfe einer so landen Jump-Table. Was das ist, schauen wir uns jetzt mal ein bisschen genauer an. Also die Grundidee dieser Jump-Table-Based-Compilation ist, dass ich eine Tabelle habe, die mir im Prinzip sagt, wo ich alles hinspringen kann. Also in der Tabelle werden die verschiedenen Label aufgelistet, wo dann die verschiedenen Arme dieses Statements zu finden sind. Also an einem Label ist dann Clause A, am nächsten Label ist Clause B und so weiter. Und die Label sind in der Tabelle cleverer Weise so aufgeführt, dass wir einfach an die richtige Stelle in diese Tabelle springen können, ohne wirklich die verschiedenen Fälle alle durcharbeiten zu müssen. Schauen wir uns das mal an. Also in dem Fall wird die Tabelle hier losgehen. Wir haben da irgendwo ein Label, wo das losgeht. Und in der Tabelle haben wir dann Referenzen durch dieses und dargestellt auf andere Stellen im Code, also auf andere Label. Also sprich an diesen Stellen stehen sozusagen die Adressen dieser Label drin. Ich schreibe jetzt erst mal kurz hin und dann sage ich ein bisschen mehr dazu. Wer jetzt ganz scharf hinschaut, sieht da vielleicht auch schon so ein gewisses Muster dabei. Ohne letztens erst mal viel zu sagen, schreibe ich erst mal weiter und erkläre jetzt dabei, was ich mache. Also was wir hier jetzt machen, ist erst mal wieder unseren Ausdruck evaluieren, so ähnlich wie wir das vorher ja auch schon gemacht haben. Im Gegensatz zu dem Code, den wir vorher aufgeschrieben hatten, überprüfen wir jetzt nicht jede Bedingung nach der anderen, sondern schauen im Prinzip nur nach zwei Fällen, nämlich dass unser Wert, der hier rauskommt, außerhalb dieses 1 bis 10 Intervals liegt. Denn alles, was zwischen 1 und 10 liegt, wird, wie man gleich sehen, oben von der Tabelle abgedeckt. Aber falls unser Wert in R1 kleiner 1 sein sollte, dann gehen wir sozusagen zu Clause I und die ist in dem Fall an L5 gespeichert. Oder falls der Wert hier größer als 10 sein sollte, dann passiert dasselbe. Auch dann springen wir zu L5. Also L5 ist sozusagen da, wo der, wo der, wo der, der Other Branch, also dieser, diese Clause I, dann steht. So, falls das nicht der Fall ist, also wenn wir jetzt also wissen, dass der Wert zwischen 1 und 10 irgendwo liegt, dann nutzen wir jetzt unsere Tabelle, um nachzuschauen, an welchem Label wir weitermachen müssen. Und zwar mit dem ganz cleveren Trick. Wir haben die Tabelle nämlich so aufgeschrieben, dass dieses erste Label hier oben dem Fall entspricht, dass unsere Expression zu 1 evaluiert wird und dann das nächste 2, 3, 4, 5, 6 und so weiter, bis wir hier unten den Fall haben, wo unsere Expression zu 10 evaluiert. Also wir dann zu Clause D springen müssten. Und um jetzt einfach an die richtige Stelle in der Tabelle, an der richtigen Stelle zu landen, müssen wir einfach den Wert der in R1 drin ist, als Adresse in diese, als Index in diese Tabelle betrachten. Und vorher müssen wir noch kurz anpassen, weil die Tabelle nämlich 0 indiziert ist. Das heißt wir ziehen nochmal 1 von R1 ab und schauen aber dann nach, was ist denn an der Stelle, an der, was ist denn im R1 Element unserer Tabelle T? Das gibt uns dann schlussendlich ein Label. Zum Beispiel, wenn die Expression gleich 3 wäre, kämen wir bei Label L3 raus und an der Stelle würde dann zum Beispiel der Code von Clause C stehen. Und je nachdem welches Label daraus kommt, da springen wir dann hin, indem wir das, was wir jetzt in R1 haben, nämlich der Wert, der an der R1 Stelle der Tabelle stand, nehmen und dann da anschließend hinspringen. Der große Vorteil an dieser Art, das zu kompilieren mithilfe dieser Jump Tables, ist jetzt also, dass wir nicht durch diese ganzen Bedingungen einzeln durchlaufen müssen, sondern dass wir einen konstanten, oder von der, vom Zeitaufwand her konstanten Sprung haben und zwar ein Sprung direkt zu dem richtigen Arm, also zu dem richtigen Fahrt, den wir dann schlussendlich auch ausführen wollen. Ja, nach diesem kleinen Ausflug in die Kompilierung und wie diese Selection Statements oder Konstrukte in Programmiersprachen denn überhaupt übersetzt werden, schauen wir uns jetzt noch ein bisschen an, was für Variation dieser Case-Switch-Statements denn in verschiedenen Programmiersprachen gibt. Also diese Grundidee von dem Case-Switch-Statement gibt es tatsächlich in vielen Sprachen, aber wie so oft variieren dann die Details. Eine Frage ist zum Beispiel, welche Werte überhaupt in den Labels erlaubt sind. Sind da nur Konstanten erlaubt, kann die solche Ranges angeben oder kann ich dieses oder verwenden, wie wir das in dem Ader Beispiel gesehen haben, das hängt alles von der Sprache ab. Auch die Frage zum Beispiel, ob ich am Ende vom Case-Switch-Statement immer ein Default-Arm haben muss, also irgendwas wie dieses, was wir gerade auch gesehen haben, wo sozusagen der Fall bearbeitet wird, der sagt, das tritt ein, wenn all die anderen Fälle nicht eintreten muss ich das haben oder nicht, auch das hängt wieder von der Sprache ab. Und was passiert, falls ich solch einen Default-Arm eben nicht habe und keiner der Werte matcht, auch das ist eine Frage, die die Sprache beantworten muss und wo verschiedene Sprachen verschiedene Antworten geben. Als ein Beispiel für Antworten auf diese Fragen schauen wir uns einfach mal eine populäre Familie von Sprachen an, nämlich C, C++ und Java, die ja in zumindest einen Hinsicht, hinsichtlich dieser Case-Switch-Statements doch sehr ähnlich sind und im Prinzip da sehr ähnliche Antworten oder die gleichen Antworten auf diese Fragen geben. Hier rechts sehen wir mal so ein Switch-Statement, wie das in den Sprachen aussehen würde. Also wir haben das Switch-Keyword gefolgt von dieser Expression und dann so eine Reihe von Cases, die die jeweiligen Fälle abdecken. Eine Besonderheit dieser Sprachen ist, dass wir für jeden Wert, mit denen wir die Expression vergleichen wollen, einen einzelnen Case brauchen. Das heißt wir können keine Ranges oder diese Oder-Ausdrücke in der Form angehen, wie wir das gerade in A da gesehen haben. Die andere Besonderheit ist, dass es, dass der Kontrollfluss sozusagen durchfällt, außer wir haben explizit ein Break-Statement, was den Kontrollfluss davon abhält. Das heißt, wenn wir jetzt zum Beispiel den Fall zwei hätten, also wenn unsere Expression den Wert zwei hat, dann landen wir erst mal hier und würden, weil da kein Break dahinter steht, dann automatisch gleich zu diesem nächsten Fall hier durchrutschen und obwohl der Wert natürlich nicht zwei und sieben sein kann, sondern in dem Fall dann vielleicht nur zwei wäre, würden wir Clause B ausführen. Anschließend ist hier das Break, was wichtig ist, denn wenn wir das nicht hätten, würde das dann noch weiter nach unten durchfallen und wir kämen schlussendlich irgendwann hier bei dem Default Statement unten wieder raus. Das heißt, alle Fälle, die man tatsächlich behandeln will und dann nicht noch andere Fälle gleichzeitig auch noch behandeln will oder nicht noch anderen Code auch noch ausführen will, müssen immer mit diesem Break beendet werden, was hier auch richtig gemacht wurde, um eben schlussendlich direkt hinter dieses Statement zu kommen, also das, was das Break schlussendlich macht. Zum Abschluss noch ein kleines Quiz, um zu testen, dass wir das auch schön verstanden haben und zwar ist hier ein Stück C++ Code zu sehen, also Code in der Familie von Sprachen, die wir uns da gerade ja angeschaut haben und die Frage ist, was gibt dieser Code schlussendlich aus? Das Einzige, was ich vielleicht kurz dazu sage, für die, die jetzt nicht C++ Experten sind, ist, dass das hier schlussendlich den Wert, der in X drin steht, ausgibt. Und mehr möchte ich dazu an der Stelle auch erst mal nicht sagen, sondern wird sie dann an der Stelle das Video wieder anzuhalten, darüber nachzudenken, was der Code schlussendlich ausgeben würde, in die Ilias abzustimmen und erst dann weiter zu machen. Gut, dann verrate ich mal die Lösung, also was dieser Code schlussendlich ausgibt, ist der Wert 17 und der Grund ist folgender. Wir haben hier nämlich nirgends Break Statements drin, das heißt, dieser Code überprüft, was in dem Wert X steht, das ist 3. Schaut, ob das gleich 1 ist, das ist nicht der Fall, also dieses erste Statement hier wird nicht ausgeführt, aber der Case, wo wir schauen, ob der Wert 3 ist, das ist dann wahr. Das heißt, wir rechnen X ist gleich X plus X, sind wir bei 6 und weil jetzt eben kein Break Statement drin steht, addieren wir dann, oder fühlen wir dann die anderen Fälle auch aus, also sprich auch dieses Statement hier wird ausgeführt, 6 plus 6 ist dann 12 und dann haben wir nochmal diesen Default Case hier unten, wo wir nochmal 5 darauf addieren und dann kommen wir schlussendlich hier unten mit X gleich 17 raus und deswegen ist das, was dann auch an der Stelle ausgegeben wird. Ja und das was dann auch schon wieder aus diesem dritten Teil im Modul Kontrollfluss. Ich hoffe, Sie haben jetzt ein bisschen Gefühl dafür, was es denn für Selection Statements oder Auswahlmöglichkeiten in so einem Programm gibt, also wo das Programm zur Laufzeit entscheiden kann, in welche Richtung der Kontrollfluss jetzt weitergeht und auch wie diese Konstrukte nicht nur hingeschrieben werden, sondern dann auch kompiliert werden. Und damit vielen Dank fürs Zuhören und bis zum nächsten Mal.