 Ja, hallo und willkommen zurück zu Programmierparadien, also diesem dritten Teil des Moduls, zunehmend Scopes and Bidings. Was Sie hier genau machen wollen, ist, dass wir uns Scopes ein bisschen genauer anschauen. Also diese Dinge, die definieren, waren genau die Assoziation von einem Namen und dem, worauf der Name zeigt in so einem Programm, den überhaupt gültig ist. Und insbesondere werden wir uns die Scoping-Regeln von verschiedenen Programmiersprachen anschauen. Die variieren noch ein ganzes Stück und jeder Sprache ist der eine oder andere Name vielleicht gültig. Und wenn man als Programmierende eine Schimpfprogrammiersprache verwendet, sollte man natürlich wissen, was genau die Scoping-Regeln denn überhaupt sind in dieser Sprache. Also legen wir gleich mal los mit diesen Scoping-Regeln. Also was machen diese Scoping-Regeln oder Scoping-Rules auf Englisch denn überhaupt? Die definieren, welche Bidings gerade aktiv sind in einem Programm. Und nochmal zur Änderung, Bidings war dann einfach nur die Assoziation von Namen mit Objekten, die einen Namen haben, also zum Beispiel variabel Namen und bestimmten Speicherobjekten. Also was diese Scoping-Regeln dann machen, ist festzulegen, welche Bedeutung eine bestimmte Name überhaupt hat oder überhaupt eine Bedeutung hat, wenn ich an einem bestimmten Punkt im Programm bin oder in der Programmausführung bin. Jede Programmiersprache hat ihre eigenen Regeln, was das Scoping betrifft. Also ein kleines Beispiel, einer der vielleicht einfachsten Programmiersprachen überhaupt, nämlich BASIC, hat genau ein Scope, das heißt die Regel ist, wie der Name der Sprache schon sagt, sehr, sehr einfach. Es gibt einfach nur diesen einen Scope und die Variapen sind einfach immer gültig, weil immer die Definition in diesem einen Scope drin sind. Die meisten anderen Programmiersprachen haben etwas komplexe Regeln und eine Sache, die man üblicherweise hat, ist, dass es für jede Subproutine oder für viele Funktionen, die ausgeführt wird, einen Scope gibt und dass diese Scopes auch ineinander verschrachtelt werden können. Schauen wir uns diese verschachtelten Scopes mal ein bisschen genauer an. Also der Grund, warum es die in vielen Programmiersprachen gibt, ist, dass wir für jede Funktion und jede Subproutine einen Scope haben möchten und man Funktion aber auch ineinander schachteln kann. Das heißt, ich kann innerhalb einer Funktion eben eine andere Funktion nochmal definieren und dadurch ergibt sich dann auch eine Schachtelung der entsprechenden Scopes. Grundsätzlich hat es mal jede Funktion oder jede Subproutine ihren eigenen Scope und wenn wir ihn in einer Schachtel, dann sind die Scopes verschachtelt. Und die Frage ist, welche Bedeutung hat ein bestimmter Name denn es eigentlich, wenn ich den innerhalb einer Funktion verwende? Und die Antwort hierauf gibt in den meisten Programmiersprachen diese Regel, die closes nested Scope Rule. Was die sagt, sind im Prinzip zwei Sachen. Die sagt zum einen, dass ein Name genau da sichtbar ist, wo der Name auch deklariert ist. Das heißt, wenn ich zum Beispiel mal ein Name innerhalb einer Funktion deklariere, dann ist dieser Name natürlich auch innerhalb dieser Funktion sichtbar. Außerdem ist der Name aber auch noch sichtbar in allen genesteten Scopes, die sich innerhalb der Scopes dieser Funktion befinden. Das heißt, in den Funktionen, die in der Funktion sind, ist der Name der äußeren Funktion ebenfalls sichtbar. Ein Spezialfall ist jetzt, was denn eigentlich passiert, wenn innerhalb eines inneren Scopes ein Name deklariert wird, der auch schon in einem äußeren Scope existiert. Und hier ist die Regel meistens so, dass die inneren Scopes die Namen der äußeren Scopes verstecken können. Das heißt, wenn ich den gleichen Namen innerhalb der einen Funktion habe und dann auch einmal innerhalb des äußeren Scopes habe und dann auch einmal innerhalb des inneren Scopes habe, dann ist innerhalb der inneren Funktion der Name der äußeren Variable eben nicht sichtbar, sondern wo wird versteckt durch den Namen, der innerhalb in der inneren Funktion definiert wird. Schauen wir uns zur Verletzung vielleicht einfach mal ein Beispiel an. Was ich in dem Beispiel mache, ist wieder eine Reihe von Funktionen zu definieren. Das war wieder in dieser ausgeklachten Spielsprache. Fangen wir mal mit der Funktion f1, die einen Argument namens a1 bekommt. Die wird hier ziemlich viel Platz brauchen, sagen wir mal bis dahunter. Innerhalb dieser Funktion deklarieren wir eine Variable namens x. Und außerdem gibt es innerhalb dieser Funktion jetzt weitere Funktionen, die in die Funktion f1 reingeschachtelt sind. Und zwar haben wir alle diese Funktion f2, die auf jeden Argument nimmt und das heißt a2. Und in f2 gibt es jetzt noch eine Funktion, nämlich die Funktion f3, die ebenfalls wieder in Argumenten nimmt, nämlich a3. Die macht irgendwas, was ist hier nicht so wichtig und außer diese Funktion f3 zu deklarieren, man kann f2 natürlich auch noch Dinge tun, was genau ist hier auch nicht so wichtig. Und jetzt sind wir wieder in der äußeren Funktion f1. Und hier gibt es nun auch noch eine weitere Funktion namens f4, die ebenfalls wieder in Argument bekommt, nämlich a4. Und auch wieder drin, wenn ihr eine verschachtelte Funktion hat, nämlich f5 von f5, bekommt auch noch mal ein Argument, was a5 heißt und macht neben vielleicht noch mal andere Sachen auch noch Folgendes, nämlich eine weitere Variate zu deklarieren, die ebenfalls x heißt und dann vielleicht auch noch irgendwie verwendet wird. So für dieses Programm können wir uns jetzt die Scopes der ganzen bindingsägigen Namen, die hier auch treten, mal genauer anschauen. Und wir fangen einfach mal an mit den Namen a1. Und was wir hier sehen ist, dass a1 eigentlich von Anfang dieser Funktion f1 bis zum Ende dieser Funktion f1 existiert und das binding sozusagen genauso lang lebt, wie diese Funktion f1 existiert. Das heißt in unserem kleinen Beispiel hier von ganz oben bis nach ganz unten. Der nächste Name, der hier auftritt, ist der Name x und der ist in diesem Sinne interessant, weil der eben einmal innerhalb von f1 deklariert wird und dabei auch nochmal innerhalb von der Funktion f5 deklariert wird für das bäuse oder x, also das x, was in f1 deklariert wird, schauen wir mal an, wo genau das gilt und das gilt ab hier oben, also wieder innerhalb der Funktion f1, aber dann nur bis hierhin erstmal, denn innerhalb von f5 wird dieser Name ja überdeckt von dem lokalen x, was es dann in f5 gibt. Und hinter der Definition von der Funktion f5 ist dann doch wieder der Name des Variables x aus f1 sichtbar, sprich, da geht das grob dann weiter. Dann haben wir hier diese Funktion f2, f2 ist innerhalb von f1 deklariert, das heißt wir können überall diesen Namen verwenden, sprich, das geht auch wieder von ganz oben, bis nach ganz unten. Dann haben wir auch noch die Argumente, die es hier gibt, also zum Beispiel dieses Argument a2, was eine f2 übergeben werden kann, dieses Argument oder der Name ist an das Argument nur gebunden innerhalb der Funktion f2, also sprich von hier nach hier und so ähnlich, dann zum Beispiel auch für das Argument a3, denn das existiert nur innerhalb dieser Funktion f3, also nur von hier bis hier. So, dann machen wir weiter mit der Funktion f4, die existiert innerhalb von f1 und weil ich die dann überall in f1 verwenden kann, ist der Name f4 sozusagen innerhalb dieses kompletten Blocks von f1 an die Funktion, an die Implementierung von f4 gebunden. Anders ist es für die, für das Argument a4, was f4 bekommt, denn das gibt es nur innerhalb der Funktion und auch innerhalb der in f4 geschachteten Funktion f5, sprich in diesem Bereich, die Funktion f5 ist im Prinzip genau, das ist auch etwas, was innerhalb dieser Funktion f4 deklariert und definiert ist und deswegen ist es auch genau innerhalb dieses Blocks von f4 sichtbar und jetzt haben wir noch zwei Namen, die interessant sind, zum einen das Argument a5, das ist genauso wie die anderen Funktionen, die wir gesehen haben, innerhalb der umgebenden Funktion sichtbar, sprich innerhalb von f5 und dann gibt es hier noch dieses 2 dx, nämlich dieses lokale x, was innerhalb von f5 deklariert ist und das, weil es eben dann auch eine lokale Variante innerhalb von f5 ist, ist innerhalb des kompletten Blocks von f5 sichtbar, aber eben nicht weiter draußen und was jetzt noch mal interessant ist, ist eben sich wieder das 2x und 2x gemeinsam anzuschauen und man sieht, dass eben dieses inner x, das äußere x versteckt genau innerhalb des Blocks von f5. So, das wissen Sie, was passiert, wenn Funktionen oder auch Scopes in den anderen verschrachtet werden und wie genau diese Namen, die hier bei den Scopes zugeordnet sind, denn dann aufgelöst werden. Eine andere interessante Frage ist, wann wir denn überhaupt genau wissen, wann, an welcher Objekte ein Name gebunden ist, nämlich wann genau das Binding dann eigentlich feststeht und da gibt es in den üblichen Programmiersprachen eigentlich genau zwei Antworten, nämlich einmal das Static Scrobing und zum anderen das Dynamic Scrobing. Static Scrobing ist das, was häufig aufhört und das, was die meisten intuitiv glaube ich auch erwarten, einfach weil es in den heutzutage modernen Programmiersprachen so die liebteste Variante ist. Was hier passiert, ist, dass wir den, das Binding eines Names aus dem Programm Text direkt ablesen können. Das heißt, wir müssen das Programm nicht ausführen, sondern sehen im Prinzip aus dem Programm Text direkt, an welchen Wert ein Name denn gebunden sein wird. Das Gegenkonzept dazu nennt sich Dynamic Scrobing und was hier passiert ist, dass das Binding eines Names eben nicht statisch aus dem Programm Text direkt gesehen werden kann, sondern das hängt vom jeweiligen Kontrollfluss ab. Das hängt davon ab, wie wir zum Beispiel ihnen eine Funktion eintreten und welche, welche andere Code vorher ausgeführt wurde und nur dann zu laufzer können wir eigentlich sagen, welche Bedeutung ein Name eigentlich hat und auf welches weiche Objekt in bestimmte Name überhaupt zeigen wird. Schauen wir uns am besten mal ein Beispiel dazu an und zunächst einmal in einer pseudo Programmiersprache, wo wir einfach mit derselben Sprache zeigen können, was passieren würde, wenn wir Static Scrobing oder Dynamic Scrobing verwenden würden. In dieser pseudo Programmiersprache haben wir hier ein kleines Programm und was das macht, ist, dass es zum einen mal eine globale Variable schreibt und dann zwei Funktionen definiert, zum einen diese Funktion A, in der es eine lokale Variable gibt, die interessanterweise den selben Name X hat, wie auch schon die globale Variable, die wir hier vorher definiert hatten. Und dann haben wir die zweite Funktion B, in der der Wert von X, was dann immer X dann genau bedeutet, die lesen wird und nach Y geschrien wird. Und los geht das Ganze hier und mit dem Aufruf von A, das heißt wir rufen zunächst A auf und A rufen dann B auf, also sprich, dann geht es hier rein. So, was passiert jetzt, wenn wir dieses Programm ausführen, das hängt davon ab, ob wir Static Scrobing oder Dynamic Scrobing verwendet haben. Fangen wir mal an, für den Fall, dass die schwache Static Scrobing verwendet. In dem Fall würde Y den Wert einzukommen. Der große Folgender will lesen, um Y zu beschreiben hier unten den Wert von X. Das heißt zunächst wird geschaut, ob innerhalb dieser Funktion eine lokale Variable X existiert, was aber nicht der Fall ist. Das heißt, es wird auf den umgebenden Scope geschaut, der statisch diese Funktion B umgibt und das ist in dem Fall der globale Scope und siehe da, da gibt es eine Variable X, die hat den Wert 1 und das heißt dieser Wert 1 wird schlussendlich hier in die Variable Y geschrien. Ganz anders sieht es aus, wenn die Schwache Dynamic Scrobing verwendet, denn in dem Fall würde Y den Wert 3 bekommen. Der Grund ist, dass wir wieder suchen, wo dieses X definiert, dass wir schon wieder nach, ob in dieser Funktion B irgendwo ein X existiert, das ist nicht der Fall. Und was jetzt auch passiert ist, dass wir den dynamisch nähsten Scope suchen, wo es eine Variable X nimmt. Das heißt, es wird geschaut, wann gab es denn zuletzt einen Binding, in dem X einen Wert zugeordnet wurde, sprich wir schauen einfach in der Ausführung zurück und sehen dann, dass es da eine globale Variable X gab, die definiert wurde, gerade bevor wir dieses B hier aufrufen haben und damit ist das das, das dynamisch am nächsten war. Das heißt, es wird diese Variable X gewesen und nicht einfach die globale Variable X darum und das heißt schlussendlich, dass dieser Wert 3 hier nach Y geschehen wird. Was dieses kleine Beispiel also investriert, ist, dass je nachdem, ob die Schwache Static Scroping oder Dynamisch Scroping verwendet, die Semantik von diesem Stück Kot, was ganz anders ist. Das heißt, es ist sehr wichtig, dass man versteht, welche Scroping-Regel, der denn überhaupt in der Programmiersprache, die man verwendet, angemeldet wird. Da diese Idee von Dynamisch Scroping für viele Flächen ein bisschen ungewöhnelt und gewöhnungsbedürftig ist, schauen wir uns das Ganze mal noch mit dem zweiten Beispiel an und zwar in Form eines kleinen Quizes. Was wir in dem Quiz verwenden, ist eine Programmiersprache, die doch recht populär ist, aber gleichzeitig auch Dynamisch Scroping verwendet und zwar ist es die Sprache Perl. Hier ist also ein Stück Perl-Code, was genau der macht, möchte ich jetzt erstmal gar nicht weiter erläutern und die Frage für Sie ist, was gibt dieser Kot denn aus? Also schlussendlich gibt es hier irgendwo so ein Print Statement und die Frage ist, welchen Wert wird dieser Kot denn denn ausgeben? Und ich würde es ja in dieser Stelle bitten, das Video einfach mal wieder kurz anzuhalten, selber darüber nachzudenken, was dieser Kot voll ausgeben könnte, in den Elias abzuschimmen, um zu sehen, ob sie es ja noch richtig lagen und vielleicht auch umzusehen, was die anderen so abstimmen und anschließend dann weiter zu schauen, um zu gucken, was die Lösung ist. Also jetzt bitte ich hier erstmal Pause machen. So, dann schauen wir uns mal die Lösung an. Also was dieser Kot schlussendlich ausgibt, ist der Wert 1 und jetzt ist die große Frage herum. Also wir haben hier dieses Print Statement, das gibt das aus, was bar zurückgibt, bar ist hier, bar gibt das zurück, was fu zurückgibt und ich frage es jetzt, warum kommt da eins raus? Wenn Perl Statics Coping hätte, was es aber nicht hat, dann würde, wenn wir hier fu aufrufen, dieser Wert b, der gelesen wird und schlussendlich auch zurückgegeben und dann schlussendlich auch rausgegeben wird, eben der Wert sein, der hier oben geschrieben wird, denn dann würden wir den umgebenden statischen Corrupter fu schauen und da diese Variable b finden, die da ganz oben definiert ist. Perl hat jetzt aber kein Statics Coping, sondern hat stattdessen Dynamics Coping und das bedeutet, dass der letzte Wert mit dem b definiert wurde benutzt wird, denn das ist der dynamisch schnellste an diesem b, was wir hier lesen und da bevor wir fu aufrufen, also sprich bevor wir hier oben überhaupt rauskommen, der letzte Wert, wo b geschrieben wurde, das hier ist, also b1 nach b schreiben, wird dann eben dieser Wert 1 hier gelesen und dieser Wert 1 wird dann hier zurückgegeben, wird dementsprechend auch hier zurückgegeben und wird dementsprechend dann schlussendlich hier rausgegeben. Wer das alles ein bisschen komisch fand, der sollte sich einfach mal ein bisschen Perl anschauen und ein bisschen in der Buchspielwitz ganz interessant, weil dieses Dynamics Coping eben doch anders ist als in den meisten anderen Programmi sprachen und ist immer interessant, einfach mal so eine Variation von der Symante, die die so eine Sprache eigentlich haben kann, anzuschauen, um da noch besser zu verstehen, was die Symante ist, in der Sprache, die ich den nun gerade verwende. So, nach diesem kleinen Blick in Dynamics Coping schauen wir uns jetzt nochmal das Statics Coping ein bisschen genauer an und insbesondere die Frage, wie das dann überhaupt implementiert ist. Was wir ja schon gesehen haben, ist, dass innerhalb der Programmausführung dieser Function Stack aufgebaut wird, wo es für ihn auch nur eine Funktion ein Location Frame gibt, der dann jeweils auf den Stack gepusht wird, wenn eine Funktion aufgerufen wird und wenn die Funktion wieder zurück kehrt, dann wird der Stack entsprechend wieder runter gebraucht. Gleichzeitig brauchen wir, um die Static Scopes aufzulösen, ihr ja irgendwo hier die Information, was denn der Static Scope oder auch der umgebende Static Scope an einem bestimmten Punkt in der Programmausführung ist. Und all das ist, wie wir gerade an den Beispiel von Perl gesehen haben, bei Static Scoping eben nicht davon abhängig, welche Funktionen schon aufgerufen wurden, also es geht nicht darum, was auf dem Function Stack ist. Und das bedeutet auch, dass uns der Function Stack eigentlich nicht besonders viel dabei hilft, rauszufinden, was denn die umgebenden Static Scopes an einem bestimmten Programmpunkt sind. Also die Frage ist, wie kann das Programm zur Ausführung die Beinigungen überhaupt auflösen und sozusagen wissen, was die Bedeutung von einem Namen ist, wenn der Function Stack an sich dabei nicht hilft. Und der Trick jeweils ist, dass in jedem Education Frame, also in jedem dieser Schweicherbereiche auf dem Stack eben nicht nur alles drinnen ist, was wir schon gesehen haben, sondern außerdem auch noch der sogenannte Static Link. Und das ist im Prinzip einfach nur ein Point dazu dem jeweiligen Perl Scope, der gerade ausgeführten Funktionen. Schauen wir uns dazu am besten mal einen Beispiel an. Und zwar haben wir im Beispiel eine Reihe von ineinander verschachtelten Funktionen. Anstatt diese Funktionen jetzt alle hinzuschreiben, stelle ich das mal so ein bisschen schematischer dar. Also wir haben eine Funktion A, die von oben bis unten geht, also der Block der Funktion. Und damit auch der Scope, die die Funktion definiert, ist solange dieses langgezogenen L, was ich dann gemacht habe. Innerhalb der Funktion A haben wir zwei weitere Funktionen definiert, die also in A reingeschachtelt sind, nämlich einmal die Funktion B von hier nach hier und einmal die Funktion E von hier nach hier. Und in B haben wir jetzt nochmal zwei Funktionen, die da drinnen definiert sind, nämlich einmal C und einmal D. Das ist ja sozusagen der Programm Text ein bisschen schematisch dargestellt. Und jetzt ist die Frage, in welche Reihenfolge diese Funktionen denn überhaupt zur Laufzeit ausgeführt werden. Und ein guter Weg, das zu veranschaulichen, ist, indem wir uns einmal mal den Functionsdeck für eine bestimmte Zeitpunkt innerhalb der Ausführungen anschauen. Also los jetzt in dem Beispiel damit, dass A aufgerufen wird, also irgendwo gibt es eine Mainfunktion oder vielleicht auch irgendeine andere Funktionen, die A aufruft. Was es A jetzt macht, ist E aufzurufen. E ruft in unser Beispiel anschließend B auf, B ruft anschließend D auf und D ruft dann die Funktion C auf. Und dann kann C natürlich noch mehr Sachen aufrufen und der Steck wächst weiter nach oben. Die Frage ist jetzt, woher weiß man, wenn man innerhalb einer dieser Funktionen ist, wie die Namen aufgelöst werden sollen. Also man fängt natürlich innerhalb der eigenen Funktion, um dem damit definierten Scope anzusuchen. Aber wenn der Name da nicht existiert, dann muss man ja zu den statisch imgebenden Scopes schauen. Sprich, man muss im Prinzip dieser Verschachtelung, die wir noch auf der linken Seite sieht, nach außen folgen. Bloß das eben das Programm, wenn es einmal ausgeführt wird, diese Verschachtelung ist nicht so sieht, wie ich das so schon hingemalt habe, sondern diese Information wird, wie ich das gerade eben schon kurz erklärt habe, in diesem Static Link gespeichert. Nehmen wir Blau dafür. Und was ich jetzt einfach mal zeige, durch so blau feile ist, wie dieser Static Link aussieht. Und zum Beispiel, wenn ich jetzt in der Halbe von C bin, also ich bin jetzt hier, dann müsste der Static Link auf B zeigen, denn der umgebende Static Scope ist eben nicht einfach das, was im falschen Set gleich und drunter liegt, das D, sondern der Static Link von C zeigt auf dieses B. Genauso für D, auch da zeigt das Static Link auf B, weil B eben die so taktisch umgebende Funktion von C ist. Für B selbst zeigt das Static Link auf A, denn A ist die Funktion, die um B herum ist. Und genau das gleiche für E nochmal, denn das zeigt auch wieder auf A. Das heißt, dieses Static Link erlaubt jetzt zur Laufzeit rauszufinden, was der umgebende Static Scope ist. Und wenn jetzt zum Beispiel eine Variable in C benutzt, wenn aber da nicht definiert ist, dann folgen wir den Static Link und gehen nach B. Und falls die Variable da auch nicht definiert ist, folgen wir wieder den Static Link und gehen nach A und schauen, ob die da dann existiert. Neben diesen ganzen Scopes, die wir jetzt gesehen haben, also die dadurch entstehen, dass der Programmierende bestimmte Funktion definiert und Variable definiert und die vielleicht auch inneinander Verschachtel gibt es in ziemlich vielen Programmierenden Sprachen auch noch implizit einen weiteren Scope, nämlich der Scope, der durch bestimmte vordefinierte Objekte bestückt wird. Und diese wird in den Objekts oder vordefinierten Objekten für verschiedene Sachen verwendet. Ein typisches Beispiel sind alle möglichen Typen oder APIs, die einfach Teil der Sprache sind und die implizit innerhalb dieses Scopes zur Verfügung stehen. Dieses Scope ist nicht wirklich sichtbar im Sinne von, dass der irgendwo im Programm Text, den der Programmierende schreibt, sichtbar wäre, so wie die Funktionsscopes, die wir bis jetzt gesehen haben, sondern ist ganz einfach impliziter und ist immer der äußeste Scope. Und es bedeutet, wenn ich jetzt einen Namen benutze und der Flächen all den Scopes, die ich mithilfe von ZX Scoping oder Dynamics Scoping versucht zu finden, nicht existiert, dann wird schlussendlich immer noch geschaut, ob diese Name vielleicht eines dieser Build-in-Objects ist und wenn ja, dann wird der Name vielleicht aufgelöst. Das heißt, diese Build-in-Objects können von allen Scopes aus gelesen werden, außer natürlich, wenn sie verschreckt sind, was dann entsprechend den Regeln, die wir ja am Anfang schon gesehen haben, natürlich immer möglich ist, also ein Inderscope kann Objekte, die eigentlich Build-in-Type oder Build-in-API sind, verschenken. Um das Ganze mal einen konkreten Beispiel zu zeigen, habe ich hier mal ein kleines Stück JavaScript Code, in dem ich ein Array-Stimme erschille und zwar indem ich diesen Konstruktoraufrufe New Array. Jetzt ist die Frage, was bedeutet Array überhaupt. Und das ist genau so ein Beispiel für ein Build-in-name oder eine Build-in-API, nämlich in der Form, dass irgendwo in dem umgebenden Scope, die mich hier gar nicht sehen, dieser Name Array definiert ist und eben an den Konstruktor von Arrays gewohnt ist. Wenn ich das Ganze jetzt aufrufe, dann wird hier also ausgegeben, was in diesen Array drin ist und in dem Fall geben wir das dann einen Array mit 1,2, also diesen 2 werden 1 und 2 aus. So schön so gut, was ich jetzt natürlich auch machen kann, ist, dass ich in meinem Script etwas definiere, was dem auch Array heißt und ich kann zum Beispiel jetzt diesen Konstruktor sozusagen lokal überschreiben, indem ich hier irgendein anderes Array erstelle und zum Beispiel immer 4, 5 und 6 rein schreife, egal was diesem Array denn tatsächlich übergeben wurde. Die Frage ist, was passiert jetzt? Wenn ich jetzt dieses newArray aufrufe, dann wird dieser Name Array eben zu diesem Array hier oben aufgelöst und diese Funktion, die man auch als Konstruktor verwenden kann, gibt es dann entsprechend dieses Array mit 4, 5 und 6 zurück. Das heißt, dieses Array hier unten wird eben nicht die Werte 1 und 2 haben, die ich eigentlich da erwarte, sondern 4, 5 und 6. Schauen wir mal, ob das auch so ist. Und tatsächlich, es gibt jetzt auch mein Array 4, 5 und 6, eben weil ich dieses Bild, ein Objekt, überschrieben habe mit dieser lokalen Definition von Array. Dass das so einfach geht, ist ein bisschen eine Besonderheit von JavaScript und nennt sich MonkeyPatching. Das sieht in dem Fall so aus, als könnte man dann ganz schön viel Unfug treiben und das kann man auch, aber es ist auf vielen Stellen nützlich und wird zum Beispiel verwendet, um ältere Browser, in denen vielleicht bestimmte APIs einfach fehlen, zu patchen in die Webseite, dann eben kurz bevor die oder am Anfang der Ausführung der eigentlichen Webseite diese APIs patched oder monkey patched, indem dann einfach diese fehlenden APIs definiert werden in der Form, wie ich es hier gerade gezahlt habe. So, aus dem Abschluss dieser Einheit zum Thema Scoping gibt es noch ein weiteres Quiz. Und zwar wieder in der Form von einer Stütz-Sorstruppe eine Frage, was machte diese Sorstruppe eigentlich. Und zwar diesmal in Python. Sollte es kein Hinweis, Python benutzt Static Scoping, also anders als das, was wir vorhin in Perl gesehen haben, gilt die Static Scoping. Ich werde wieder nicht viel zu dem Code erstmal sagen, sondern gibt Ihnen jetzt die Möglichkeit, da mal für ein paar Sekunden oder Minuten auch nachzudenken und zu überlegen, was dieser Code denn schon so endlich ausgibt, das Ganze dann im Elias Bedarf zu stimmen, so dass Sie sich selbst überprüfen können und auch sehen, was andere abstimmen und anschließend nachdem, was wir gemacht haben, dann bitte erst einmal hinschauen. So, schauen wir die Lösung an. Also, was hier passiert ist, folgendes. Wir rufen hier unten ja, an einem Moment, wir rufen zunächst erstmal hier F auf. F ist hier definiert und das F, außer dass es noch mal verschaffelte Funktionen drin hat, als erstes macht, ist eine lokalere Variable zu beschreiben mit dem wir jetzt beheben. Python ist so, dass alle Variablen in dem Moment als lokalere Variable in Implicit D klariert werden, wenn sie innerhalb einer Funktion G mehr als schräg, dass es eine lokalere Variable X, die hier den Wert B bekommt. Anschließend rufen wir h auf. Sprich, der Code springt hierhin. Was in h ist erstes passiert, ist, dass wir gleich G aufrufen und G ruft dann Print von X auf. Das heißt, wir müssen uns dieses X hier auflösen. In G direkt gibt es kein X, denn X wurde nie geschrieben in G. Also schauen wir in den statischen G-Scope, sprich den Scope von F und da finden wir dieses X hier, was wir hier schon beschrieben haben und was aktuell den Wert B hat. Sprich, das erste, was ausgegeben wird, ist ein B. Nach dem G, das dann hier ausgegeben wird, sind wir wieder hier und kämen von G zurück. Schreiben jetzt eine Variable X innerhalb von h. Wie ich gesagt habe, kreiert das Implicit eine lokalere Variable X, die in h gültig ist. Die hat jetzt den Wert C und wenn wir dann Print von X machen, bekommen wir also A das C ausgeben. Als zweites. Anschließend kehrt h zurück, sprich wir sind jetzt hier und jetzt geben wir wieder ein X aus. Die Frage ist, welches X ist das? Das ist nicht das X von hier oben, was wir hier geschrieben haben, denn das ist ja in dem Scope von h, der aber nur innerhalb von h sichtbar ist. Sprich wir sehen das nächstes, in dem Moment, wo hier unten das X ausgegeben wird, schauen wir im Scope von f nach und da gibt es einen X, nämlich dieses hier und das hat immer noch den Wert B, denn wir haben es nicht überschrieben, was wir hier geschrieben hatten, weil die lokalere Variable von h. Das heißt, wir geben dieses B, was hier steht, als drittes aus und dann kehrt der Kot hier zurück von f, sprich wir sind jetzt hier und an der Stelle geben wir nochmal den X aus, schauen wir also im aktuellen Scope, sprich diesen globalen Scope hier nach, wo es einen X gibt, finden dieses X hier oben, das hat den Wert a, das ist das Einzige, was wir hier mal eingeschrieben haben, sprich schlussendlich gibt der Kot hier auch noch a aus, also insgesamt trompt b, c, b, a raus. So, und das sollte auch schon wieder gewesen sein von diesem dritten Teil im Modul Name Scopes and Binding, das ging ja jetzt um Scopes, das wissen wir jetzt, was dieses Scopes überhaupt sind, haben Static, Direct Scoping gesehen, Desktop Scoping gesehen und auch noch andere Varianten davon, die im Prinzip alle festlegen, wo ist denn überhaupt ein Name gültig und wie genau macht die Programmierschwache, dass das der Name dann zu einem bestimmten Objekt aufgelöst wird. Was wichtig ist, ist, dass man überweist, welches Scoping hier in der jeweiligen Programmierschwache gelten, denn nur so kann man natürlich Kot schreiben, der schlussendlich auch das macht, was man erwartet. Und damit erstmal Danke fürs Zuhören und bis zum nächsten Mal.