Unveränderlichkeit in den Griff bekommen

13

Ich bin neu in der objektorientierten Programmierung, und ein Konzept, das mich lange beschäftigt hat, ist Unveränderlichkeit. Ich glaube, die Glühbirne ist letzte Nacht ausgegangen, aber ich möchte Folgendes überprüfen:

Wenn ich auf Aussagen stoße, dass ein unveränderliches Objekt nicht geändert werden kann, bin ich verwirrt, weil ich zum Beispiel Folgendes tun kann:

NSString *myName = @"Bob";
myName = @"Mike";

Dort habe ich gerade meinen Namen vom unveränderlichen Typ NSString geändert. Mein Problem ist, dass sich das Wort "Objekt" auf das physische Objekt im Speicher oder die Abstraktion "meinName" beziehen kann. Die erstere Definition gilt für den Begriff der Unveränderlichkeit.

Was die Variable betrifft, so ist eine (für mich) klarere Definition der Unveränderlichkeit, dass der Wert eines unveränderlichen Objekts nur geändert werden kann, indem auch seine Position im Speicher, dh seine Referenz (auch als Zeiger bezeichnet), geändert wird.

Ist das richtig oder bin ich noch im Wald verloren?

Michael Mangold
quelle
13
Ihr Typ ist kein NSString, es ist ein " Zeiger auf und NSString", der nicht unveränderlich ist. Ich weiß nichts über Ziel C, aber ich vermute in Ihrem Beispiel, @"Mike"dass eine neue Instanz von erstellt NSStringund dem Zeiger zugewiesen wird myName. Sie haben also nicht das Objekt geändert, auf das verwiesen myNamewurde, sondern nur das, auf das verwiesen wurde.
fwgx
2
@fwgx Gib es als Antwort und du bekommst meine Gegenstimme.
Gulshan
Vielen Dank an alle für die Antworten, sie sind sehr hilfreich. Ich verstehe jetzt, dass das unveränderliche Objekt der Wert im Speicher ist, nicht die Variable, die darauf verweist.
Michael Mangold
@ Gulshan Fertig, siehe unten ....
fwgx
Um die Unveränderlichkeit zu verstehen, empfehle ich, eine Programmiersprache zu lernen, die das Binden (dh Benennen von Objekten) und das Verändern (dh das Zuweisen eines Namens zu einem anderen Objekt) klar voneinander trennt. ML (in irgendeiner Form: SML, Ocaml, F #) ist ein gutes Beispiel.
Gilles 'SO - hör auf, böse zu sein'

Antworten:

4

Es hört sich so an, als würden Sie in die richtige Richtung gehen, haben es aber noch nicht ganz verstanden. Das ist falsch:

Dort habe ich gerade meinen Namen vom unveränderlichen Typ NSString geändert. Mein Problem ist, dass sich das Wort "Objekt" auf das physische Objekt im Speicher oder die Abstraktion "meinName" beziehen kann.

In Ihrem Code-Snippet myNamehandelt es sich nicht um einen unveränderlichen Typ NSString, sondern um einen veränderlichen Typ NSString*(Zeiger auf NSString). Es hört sich so an, als ob der Schlüssel, den Sie vermissen, darin besteht, zu verstehen, dass ein Zeiger nur ein anderer Wert ist und dass er ein völlig anderes Leben hat als das, auf das er zeigt (oder Dinge, wenn Sie ihn im Laufe seines Lebens teilweise ändern).

Du sagst:

... Der Wert eines unveränderlichen Objekts kann nur geändert werden, indem auch seine Position im Speicher, dh seine Referenz (auch als Zeiger bezeichnet), geändert wird.

Das ist falsch. Ein Objekt nicht besitzen die Zeiger dieser Punkt auf sie, noch ist eine Speicherstelle des Objekts gesteuert oder auf andere Weise durch irgendwelche Hinweise auf ihr betroffen.

Die beiden NSStringObjekte in Ihrem Beispiel ( @"Bob"und @"Mike") sind also vollständig von der myNameVariablen getrennt. Sie sind auch völlig voneinander getrennt. Wenn Sie myNameauf zeigen, @"Mike"anstatt auf zu zeigen @"Bob", ändern Sie die NSStringObjekte nicht.


Der Vollständigkeit halber werde ich bemerken, dass Garbage Collectors dies insofern komplexer machen, als Änderungen an Zeigern sich auf die Objekte auswirken können, auf die sie zeigen (ed). Dies ist jedoch ein Implementierungsdetail, das das beobachtbare Verhalten des Codes nicht beeinflussen sollte.

John Bartholomew
quelle
17

Sie sind bei Worten verloren. Unveränderlichkeit bedeutet: Solange Sie die Variable nicht ändern, enthält sie immer den gleichen Wert, unabhängig davon, was Sie mit anderen Variablen tun.

Gegenbeispiel in C (etwas vereinfacht, vorausgesetzt eine Architektur, die das erlaubt):

 char *a = "Hello World";
 char *b = a;
 b[0] = 'Y';

Jetzt "enthält" a nicht mehr (dh zeigt auf) den String "Hello World", sondern "Yello World".

In Sprachen, in denen Zeichenfolgen unveränderlich sind, wie Java und (EDIT: safe) C #, können Sie dies nicht tun. Auf keinen Fall. Dies bedeutet, dass jeder Teil des Programms einen sicheren Verweis auf den String behalten kann und sich darauf verlassen kann, dass sich dessen Inhalt niemals ändert. Andernfalls müssten sie eine Kopie erstellen, um auf der sicheren Seite zu sein.

Die Variable ist jedoch noch veränderbar. Sie können es auf ein anderes Objekt zeigen lassen. Es ist nur so, dass sich das Objekt selbst nicht hinter deinem Rücken verändert.

user281377
quelle
1
Sie können den Inhalt von Strings technisch in C # ändern, Sie müssen nur unsafeCode verwenden.
Aaronaught
1
Aaronaught: Danke für die Info, du hast recht; Für alle, die wissen müssen, wie: msdn.microsoft.com/en-us/library/ms228599.aspx
user281377
10

Sie verwechseln Variablen mit Objekten. Variablen können zum Speichern von Referenzen auf Objekte verwendet werden, sie sind jedoch KEINE Objekte. Es sind Objekte, die unveränderlich sind, keine Variablen. Sie können also die Variablen von einem Objekt in ein anderes ändern, aber Sie können die Attribute des Objekts nicht ändern, wenn es unveränderlich ist.

Stellen Sie sich das Objekt als einen lauten, betrunkenen Nachbarn vor. Wenn er vernünftig (veränderlich) ist, können Sie möglicherweise an seine Tür klopfen und ihn in einen Lebensstil verwandeln, in dem er nicht so viel Lärm macht. Aber wenn er unveränderlich ist, besteht Ihre einzige Änderung in der Hoffnung, dass jemand anderes einzieht!

Kilian Foth
quelle
3
Ich hatte einige Nachbarn, die ich gerne stumm geschaltet hätte.
Dave Nay
Ich glaube nicht, dass Sie Ihr Beispiel im zweiten Absatz brauchen, da Ihre Erklärung gut genug ist. IMO könnte das Beispiel nur verwirren. Jedoch +1 für eine prägnante Antwort auf die Frage des Jungen.
Paul McCabe
@ DaveNay: Ich entschuldige mich für das Stealth-Wortspiel. War überhaupt nicht beabsichtigt.
Kilian Foth
6

Eine Variable ist kein Objekt. Eine Variable ist ein Name, der sich auf ein Objekt (oder allgemeiner auf einen Wert) bezieht.

Zum Beispiel ist "der Torhüter" ein Name, mit dem wir uns auf das Objekt (die Person) beziehen, die für die Verteidigung des Tores verantwortlich ist. Aber wenn ich diese Person durch eine andere ersetze (weil die frühere verletzt ist oder so), wird die neue Person jetzt als "Torhüter" bezeichnet.

Die Zuweisungsanweisung macht Variablen veränderbar (einige Sprachen wie Haskell haben sie nicht und verwenden tatsächlich unveränderliche Variablen). Hiermit können Sie die Bedeutung eines Namens neu definieren und den Wert neu zuweisen.

Jetzt Objekte selbst kann unveränderlich sein. Vor ein paar tausend Jahren hätte man sich Diamanten als unveränderlich vorstellen können. Egal, was Sie mit einem Diamanten gemacht haben, Sie konnten ihn nicht ändern. Egal, ob Sie es Waggawooga nannten (was locker "der größte glänzende Stein unseres Stammes" bedeutet) oder nicht mehr so ​​nannten (weil Sie einen größeren gefunden haben), der Diamant blieb derselbe. Im Gegensatz dazu ist das Stück Holz, das Sie früher mit Ihrem Waggawooga in lustige Bilder geschnitzt haben, nicht dasselbe geblieben. Es erwies sich als wandelbar. Auch wenn es die ganze Zeit den gleichen Namen hatte.

Sowohl Variablen als auch Werte können (unabhängig) unveränderlich sein. In diesem Fall sind es die Objekte, die unveränderlich sind. Sobald Sie ein erstellt haben NSString, können Sie es nicht mehr ändern. Sie können es benennen und weitergeben, aber es bleibt gleich. Im Gegensatz dazu NSMutableStringkann nach dem Anlegen zB durch Aufruf der setStringMethode geändert werden.

back2dos
quelle
Ich liebe den Waggawooga-Vergleich!
Michael K
Nur um das Original-Poster nicht mehr als nötig zu verwirren: Obwohl Ihre Aussage, dass eine Variable kein Objekt ist, gut ist, wird eine Variable nicht als "ein Name, der sich auf einen Wert bezieht" definiert. Möglicherweise wird eine Variable benannt und verweist auf einen Speicherort , der einen Wert enthält. In vielen Programmiersprachen müssen Variablen nicht benannt werden, und in vielen Sprachen kann dieselbe Variable mehr als einen Namen haben.
Eric Lippert
4

Ich glaube, Sie fühlen sich verloren, weil Sie zwei Konzepte mischen: das Objekt selbst und den Variablennamen, der an dieses Objekt gebunden ist.

Unveränderliche Objekte können nicht geändert werden. Zeitraum. Variablenname (Symbol), der an ein unveränderliches Objekt gebunden ist, kann jedoch so geändert werden, dass er an ein anderes unveränderliches Objekt gebunden ist .

Mit anderen Worten, was Sie in diesen beiden Zeilen getan haben, war:

  1. Erstelle ein unveränderliches String Objekt mit dem Wert "Bob"
  2. Binden Sie das Symbol myNamean dieses Objekt
  3. Erstelle ein unveränderliches String Objekt mit dem Wert "Mike"
  4. Binden Sie das Symbol myNamean dieses Objekt
vartec
quelle
2

Ihr Typ ist kein NSString" Zeiger auf einen NSString", der nicht unveränderlich ist. Ich weiß nichts über Ziel C, aber ich vermute in Ihrem Beispiel, @"Mike"dass eine neue Instanz von erstellt NSStringund dem Zeiger zugewiesen wird myName . So haben Sie das Objekt nicht geändert , das myNamewar zeigte auf, gerade was es zeigte.

fwgx
quelle
0

Hier ist ein Beispiel für ein veränderbares Objekt: Ein Array von charin C:

char str[10];

Ich kann die ändern Inhalt der strin mein Herz Inhalt (so lange es nicht mehr als 10 Zeichen). Damit es von den C-String-Bibliotheksfunktionen als String erkannt wird, muss eine nachgestellte 0 vorhanden sein, damit es Strings mit einer Länge von bis zu 9 Zeichen aufnehmen kann:

strcpy(str, "hello"); // str now contains the string "hello\0"
strcpy(str, "world"); // str now contains the string "world\0"

str[0] = 'W';         // str now contains "World\0"

und so weiter .

Vergleichen Sie dies mit einem String-Objekt in Java:

String foo = "Hello";

Die String - Instanz (der Teil des Speichers, das die Zeichen ‚H‘ enthält, ‚E‘, ‚L‘, ‚l‘ und ‚o‘) kann nicht verändert werden; Ich kann den Inhalt dieser Zeichenfolge nicht ändern. Wenn du etwas schreibst wie

foo = foo + " World";

Sie fügen "World" nicht an das Ende der "Hello" -Instanz an. Sie erstellen eine neue Instanz , kopieren "Hello World" darauf und aktualisieren foo, um auf diese neue Zeichenfolgeninstanz zu verweisen.

fooenthält selbst nicht die String-Instanz; Es bezieht sich nur auf diese Instanz (ähnlich einem Zeiger in C oder Obj-C), weshalb Typen wie String als Referenztypen bezeichnet werden.

John Bode
quelle