Grundlagen der Informatik I “Programmierung”
Grundlagen der Informatik I “Programmierung” Grundlagen der Informatik I “Programmierung”
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.
- Seite 49 und 50: Wenn wir eine Menge von Sprachen be
- Seite 51 und 52: Da wir im folgenden den Begriff der
- Seite 53 und 54: Für die Zuordnung zwischen der Obj
- Seite 55 und 56: Diese Form der Definition findet ih
- Seite 57 und 58: K1: Kommutativ-Gesetz E1 ∧E2 ≡
- Seite 59 und 60: Axiomenschemata: L1 A ∨ ¬A L2 (A
- Seite 61 und 62: In dem Kapitel über die Programmve
- Seite 63 und 64: 2. Es werden Quantoren eingeführt,
- Seite 65 und 66: s (T, state) = wahr s (F, state) =
- Seite 67 und 68: • x ist gebunden in p(t1, ..., tn
- Seite 69 und 70: Der Wert einer Aussage mit mehreren
- Seite 71 und 72: Wichtig ist, daß die Auswahl des W
- Seite 73 und 74: Wir geben hier eine Funktion an, di
- Seite 75: wichtigste formale Sprache zur Besc
- Seite 78 und 79: Wir wollen jedoch deutlich darauf h
- Seite 80 und 81: Buch, sondern sollten besser als ei
- Seite 82 und 83: Viel sinnvoller ist es, bei der Bes
- Seite 84 und 85: Entsprechend ihrer beabsichtigten B
- Seite 86 und 87: Klassen sind rein statische Beschre
- Seite 88 und 89: leeren Verweis (d.h. von machen Per
- Seite 90 und 91: haben wie z.B. “(jahr:INTEGER)”
- Seite 92 und 93: und diese erzeugten Objekte mit Ver
- Seite 94 und 95: Bei der Erzeugung von Objekten mitt
- Seite 96 und 97: über den Namen eines Attributs Wer
- Seite 98 und 99: • Die Veränderung und Auswertung
- Seite 102 und 103: 3.5.2 expanded: Klassen mit Copy-Se
- Seite 104 und 105: class LIST[X] creation new feature
- Seite 106 und 107: Dieses Problem wird durch das Konze
- Seite 108 und 109: 3.7.1 Zusicherungen Eiffel logische
- Seite 110 und 111: class ARRAY[X] creation make featur
- Seite 112 und 113: class ARRAY[X] creation make featur
- Seite 114 und 115: formulieren und zu überwachen. Eig
- Seite 116 und 117: 3.8.2 Export geerbter Features Norm
- Seite 118 und 119: Ist also p ein Personenobjekt und a
- Seite 120 und 121: Definition 3.8.5 (Konformität) Ein
- Seite 122 und 123: Um die Beschreibung des Typsystems
- Seite 124 und 125: Nachkommenklassen aber folgt entity
- Seite 126 und 127: deferred class LIST[X] feature leng
- Seite 128 und 129: class STUDENT feature universität:
- Seite 130 und 131: Das Problem ist nun, daß beide Elt
- Seite 132 und 133: Prinzipiell wäre es sogar möglich
- Seite 134 und 135: Das bedeutet also, daß die Erbenkl
- Seite 136 und 137: Die eigentliche Montage eines Syste
- Seite 138 und 139: Verständlichkeit der Module: Die L
- Seite 140 und 141: dynamische Semantik: Die dynamische
- Seite 142 und 143: Constant ::= Manifest constant | Id
- Seite 145 und 146: Kapitel 4 Systematische Entwicklung
- Seite 147 und 148: 4.1.2 Grundideen des objektorientie
- Seite 149 und 150: jedoch dringend zu empfehlen, jegli
!!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.