Grundlagen der Informatik I “Programmierung”

Grundlagen der Informatik I “Programmierung” Grundlagen der Informatik I “Programmierung”

22.08.2013 Aufrufe

3.5 Copy- und Referenz-Semantik In den vorigen Abschnitten ist bereits des öfteren darauf hingewiesen worden, daß Zuweisungen, Tests und ähnliche Operationen auf Objekten recht verschiedene Effekte haben können und daß deshalb auch mehrere Instruktionen scheinbar gleicher Natur existieren. Dies hat damit zu tun, daß Objekte eines einfachen Datentyps direkt angesprochen werden, Objekten eines Klassentyps aber nur über Verweise erreichbar sind. In diesem Abschnitt wollen wir daher den Unterschied zwischen der sogenannten Copy-Semantik (Wertesemantik) und der Referenzsemantik (Verweissemantik) klarstellen. 3.5.1 Einfache Typen und Klassentypen Eigentlich sollte es nur wenig Probleme bei der Beurteilung des Effektes von Zuweisungen und Vergleichen geben, da die Regeln eindeutig sind: in Eiffel enthalten alle Größen eines Klassentyps Verweise und nicht etwa die Objekte selbst. Standardoperationen beziehen sich daher auf Verweise – Eiffel hat eine Referenzsemantik. Entwurfsprinzip 3.5.1 (Regeln der Semantik von Eiffel) Eine Zuweisung der Form a:=b ist eine Wertzuweisung, wenn a und b von einem einfachen Typ (INTEGER, BOOLEAN, CHARACTER, REAL, und DOUBLE) sind. Sie ist eine Verweiszuweisung – und nicht etwa eine Objektzuweisung – wenn a und b von einem Klassentyp sind. Analog ist ein Test a=b bzw. a/=b ein Wertevergleich zwischen Größen einfacher Typen und ein Vergleich der Verweise zwischen Größen von Klassentypen. Eine Zuweisung von Objekten (d.h. eine Zuweisung der Komponenten) bzw. ein Vergleich zwischen (den Komponenten von) Objekten fällt daher nicht unter die Standardoperationen, die mit den Symbolen :=, = und /= bezeichnet werden, sondern ist eine Operation, die eine gesonderte Instruktion benötigt. Eiffel stellt hierfür die in Abschnitt 3.3.4 besprochenen Routinen clone, copy und equal bzw. die “tiefen” Varianten deep clone, deep copy und deep equal zur Verfügung. Das folgende Beispiel soll die Unterschiede verdeutlichen. Beispiel 3.5.2 In Abbildung 3.13 hatten wir die Klasse PERSON und die Initialisierungsprozedur init mit namen beschrieben. Es seien p 1, p 2, p 3, p 4 Größen vom Typ PERSON. Nach Ausführung der Instruktionen !!p 1.init mit namen(Meyer","Bertrand"); p 2 := p 1; p 3 := clone(p 1); !!p 4.init mit namen("Kreitz",Christoph") ist p 1=p 2 wahr, nicht aber p 1=p 3. Dagegen gilt equal(p 1,p 2) und equal(p 1,p 3). Die Instruktion p 2:=p 4 würde dafür sorgen, daß p 2=p 4 gilt, p 2.copy(p 4) dagegen nicht – auch hier gilt danach nur equal(p 2,p 4). p 2.copy(p 4) ist übrigens nicht anwendbar, solange p 2 noch keinen anderen Wert erhalten hatte. Die Folge der Referenzsemantik ist, daß nach einer Zuweisung a:=b zwischen Größen eines Klassentyps beide Größen auf dasselbe Objekt verweisen. Änderungen des Objektes selbst betreffen somit sowohl a als auch b, Änderungen der Verweise dagegen nicht. Auch diesen Unterschied wollen wir an einem Beispiel verdeutlichen. Beispiel 3.5.3 Nehmen wir an, wir hätten in der Klasse PERSON eine weitere Routine setze vater deklariert, welche bei Eingabe einer Größe vom Typ Person der Komponente vater eines Personenobjektes einen Verweis auf die so bezeichnete Person zuweist. Es seien p 1, p 2, p 3, p 4 Größen vom Typ PERSON wie zuvor. Nach Ausführung der Instruktionen !!p 1.init mit namen("Kreitz",Christoph");

!!p 2.init mit namen("Kreitz","Helmut"); p 3 := p 1; gilt, wie bereits erklärt, p 1=p 3. Nach Ausführung von p 4 := p 1; p 4 := p 2;; hat sich an dem durch p 1 bezeichneten Objekt nichts geändert und es gilt weiterhin p 1=p 3. Nach p 4 := p 1; p 4.setze vater(p 2);; hat sich dagegen nicht nur die Vater-komponente von p 4 verändert, sondern auch die von p 1, da beide auf dasselbe Objekt verweisen. p 1=p 3 gilt also nicht mehr. Der Grund hierfür ist, daß die Zuweisung a:=b eine dauerhafte Beziehung zwischen a und b bewirkt. Solange nicht einer der beiden Verweise verändert wird, zeigen beide auf dasselbe Objekt. Der Zweck dieser scheinbar komplizierten Semantik ist, daß interne Objekte dafür Objekte der realen Wirklichkeit beschreiben sollen. Änderungen dieser Objekte sollen daher auch bei allen Kunden sichtbar werden, die darauf zugreifen. So ist z.B. die Sitzbelegungsliste für einen Flug von Frankfurt nach New York ein einzelnes Objekt, auf das alle möglichen Reisebüros auf festdefinierte Art Zugriff haben. Wird nun ein Sitz durch ein Darmstädter Reisebüro belegt, so muß er für alle anderen Reisebüros blockiert sein – ansonsten gäbe es ein heilloses Durcheinander im Flugverkehr. Aus diesem Grunde sind Verweise von dem zugreifenden Reisebüro auf die Sitzbelegungsliste wesentlich sinnvoller als etwa Kopien. Die Tatsache, daß eine Operation auf Objekten einen weitreichenden Effekt auf andere Größen haben kann, die auf dasselbe Objekt verweisen, macht es notwendig, derartige Operationen mit großer Sorgfalt einzusetzen. Insbesondere muß man sich darüber klar sein, ob man wirklich ein Objekt verändern will und nicht etwa eine veränderte Kopie erzeugen möchte. Daher ist es notwendig, in einer Programmiersprache Operationen, die auf den Objekten arbeiten und nicht auf einem Verweis, als solche klar zu kennzeichnen. In Eiffel geschieht dies durch Verwendung der Punktnotation entity.operation(argumente). Sie besagt, daß die Operation auf das Objekt zugreift und es ggf. verändert. Abbildung 3.17 faßt die wichtigsten Eigenschaften dieser Interpretation von Eiffel-Instruktionen zusammen. Einfache Typen werden durch Copy-Semantik interpretiert: Zuweisung und Vergleiche beziehen sich auf Werte. Eine Zuweisung a:=b erzeugt in a eine Kopie des Wertes von b, die selbst keine Verbindung zu b mehr hat. Klassentypen werden durch Referenz-Semantik interpretiert: Zuweisung und Vergleiche beziehen sich auf Verweise und können daher zwei Größen binden. Gleiche Verweise zeigen auf dasselbe Objekt. Eine Operation auf einer der beiden Größen kann über das gemeinsam genutzte Objekt die Eigenschaften der anderen verändern. Abbildung 3.17: Semantik von Eiffel-Typen Es sei nochmals darauf hingewiesen, daß es natürlich auch für Klassentypen Operationen gibt, die explizit eine Copy-Semantik in sich tragen. Das sind im einfachen Fall die Operationen clone, copy und equal, welche eine flache Kopie behandeln. Sie verfolgen eine Stufe eines Verweises und kopieren bzw. vergleichen alle Komponenten einzeln. Hierbei verwenden sie allerdings wieder die Referenz-Semantik. Eine hundertprozentige Copy-Semantik erhält man nur, indem man alle Verweise bis zum Ende verfolgt, also eine tiefe Kopie verfolgt, wie bei deep clone, deep copy und deep equal. Diese Routinen sind jedoch sehr rechenintensiv.

!!p 2.init mit namen("Kreitz","Helmut");<br />

p 3 := p 1;<br />

gilt, wie bereits erklärt, p 1=p 3. Nach Ausführung von<br />

p 4 := p 1;<br />

p 4 := p 2;;<br />

hat sich an dem durch p 1 bezeichneten Objekt nichts geän<strong>der</strong>t und es gilt weiterhin p 1=p 3. Nach<br />

p 4 := p 1;<br />

p 4.setze vater(p 2);;<br />

hat sich dagegen nicht nur die Vater-komponente von p 4 verän<strong>der</strong>t, son<strong>der</strong>n auch die von p 1, da beide<br />

auf dasselbe Objekt verweisen. p 1=p 3 gilt also nicht mehr.<br />

Der Grund hierfür ist, daß die Zuweisung a:=b eine dauerhafte Beziehung zwischen a und b bewirkt. Solange<br />

nicht einer <strong>der</strong> beiden Verweise verän<strong>der</strong>t wird, zeigen beide auf dasselbe Objekt. Der Zweck dieser scheinbar<br />

komplizierten Semantik ist, daß interne Objekte dafür Objekte <strong>der</strong> realen Wirklichkeit beschreiben sollen.<br />

Än<strong>der</strong>ungen dieser Objekte sollen daher auch bei allen Kunden sichtbar werden, die darauf zugreifen.<br />

So ist z.B. die Sitzbelegungsliste für einen Flug von Frankfurt nach New York ein einzelnes Objekt, auf das alle<br />

möglichen Reisebüros auf festdefinierte Art Zugriff haben. Wird nun ein Sitz durch ein Darmstädter Reisebüro<br />

belegt, so muß er für alle an<strong>der</strong>en Reisebüros blockiert sein – ansonsten gäbe es ein heilloses Durcheinan<strong>der</strong><br />

im Flugverkehr. Aus diesem Grunde sind Verweise von dem zugreifenden Reisebüro auf die Sitzbelegungsliste<br />

wesentlich sinnvoller als etwa Kopien.<br />

Die Tatsache, daß eine Operation auf Objekten einen weitreichenden Effekt auf an<strong>der</strong>e Größen haben kann,<br />

die auf dasselbe Objekt verweisen, macht es notwendig, <strong>der</strong>artige Operationen mit großer Sorgfalt einzusetzen.<br />

Insbeson<strong>der</strong>e muß man sich darüber klar sein, ob man wirklich ein Objekt verän<strong>der</strong>n will und nicht etwa eine<br />

verän<strong>der</strong>te Kopie erzeugen möchte. Daher ist es notwendig, in einer Programmiersprache Operationen, die auf<br />

den Objekten arbeiten und nicht auf einem Verweis, als solche klar zu kennzeichnen. In Eiffel geschieht dies<br />

durch Verwendung <strong>der</strong> Punktnotation entity.operation(argumente). Sie besagt, daß die Operation auf das<br />

Objekt zugreift und es ggf. verän<strong>der</strong>t. Abbildung 3.17 faßt die wichtigsten Eigenschaften dieser Interpretation<br />

von Eiffel-Instruktionen zusammen.<br />

Einfache Typen werden durch Copy-Semantik interpretiert: Zuweisung und Vergleiche beziehen<br />

sich auf Werte. Eine Zuweisung a:=b erzeugt in a eine Kopie des Wertes von b, die<br />

selbst keine Verbindung zu b mehr hat.<br />

Klassentypen werden durch Referenz-Semantik interpretiert: Zuweisung und Vergleiche beziehen<br />

sich auf Verweise und können daher zwei Größen binden. Gleiche Verweise zeigen<br />

auf dasselbe Objekt. Eine Operation auf einer <strong>der</strong> beiden Größen kann über das gemeinsam<br />

genutzte Objekt die Eigenschaften <strong>der</strong> an<strong>der</strong>en verän<strong>der</strong>n.<br />

Abbildung 3.17: Semantik von Eiffel-Typen<br />

Es sei nochmals darauf hingewiesen, daß es natürlich auch für Klassentypen Operationen gibt, die explizit<br />

eine Copy-Semantik in sich tragen. Das sind im einfachen Fall die Operationen clone, copy und equal,<br />

welche eine flache Kopie behandeln. Sie verfolgen eine Stufe eines Verweises und kopieren bzw. vergleichen alle<br />

Komponenten einzeln. Hierbei verwenden sie allerdings wie<strong>der</strong> die Referenz-Semantik. Eine hun<strong>der</strong>tprozentige<br />

Copy-Semantik erhält man nur, indem man alle Verweise bis zum Ende verfolgt, also eine tiefe Kopie verfolgt,<br />

wie bei deep clone, deep copy und deep equal. Diese Routinen sind jedoch sehr rechenintensiv.

Hurra! Ihre Datei wurde hochgeladen und ist bereit für die Veröffentlichung.

Erfolgreich gespeichert!

Leider ist etwas schief gelaufen!