Hm... Wo soll da der Unterschied sein, ob du nun int oder Integer nimmst? Sowohl int als auch Integer ist immutable. Du musst in beiden Fällen das Objekt kopieren, ja.
Es reicht im übrigen auch, wenn das Objekt nach außen hin sich immutable verhält. Innen kann es auch mutable sein (Wird dadurch zwar nicht zwingend lesbarer, aber wenn's für die Performance kritisch ist, ist das denkbar). Solange es nach außen hin immutable wirkt, lässt sich das genau so verwenden wie komplett immutable Objekte auch.
Der Performance-Hit ist also wesentlich geringer als ihr euch das wahrscheinlich vorstellt
Grüße ~ Frase
_________________ "Für kein Tier wird so viel gearbeitet wie für die Katz'."
Mein Haupt-Verständnisproblem ist ja: Was mache ich, wenn ich etwas ändern möchte? Ich könnte ja ne Riesenklasse mit was weiß ich drin haben und möchte nur ein int ändern. Wie mache ich das?
Mein Haupt-Verständnisproblem ist ja: Was mache ich, wenn ich etwas ändern möchte? Ich könnte ja ne Riesenklasse mit was weiß ich drin haben und möchte nur ein int ändern. Wie mache ich das?
Da liegt ja schon der Hase im Pfeffer begraben: Man soll ja auch keine Riesenklassen haben
Wenn du was ändern möchtest, erzeugst du eine neue Instanz dieser Klasse, bei der alle Werte (bis auf den zu ändernden) gleich der Werte sind, die in der aktuellen, ursprünglichen sind. Das macht man üblicherweise, indem man die Werte über den Konstruktor mitgibt. Und ja, wenn dein Konstruktor dann plötzlich 30 Parameter nimmt, solltest du dir nochmal Gedanken um dein Design machen (Es schadet auch nicht, wenn man sich schon früher Gedanken macht ^^).
Grüße ~ Frase
_________________ "Für kein Tier wird so viel gearbeitet wie für die Katz'."
Sorry, ich würde der theorie "ALLES muß immer kopiert werden", bzw "ALLES muß immutable sein" doch ein wenig wiedersprechen.
Es mag situationen geben wo es durchaus sinnvoll sein kann, aber IMMER sicher nicht... ich würde mich nicht beschränken in dem ich sage ich mache nur das eine oder nur das andere.
Es kommt natürlich auch stark drauf an was du tust.. wenn es ein Programm ist wo es nicht um millisekunden beim berechnen geht ist natürlich eh alles egal.. aber ich habe mal mit einem Freund nen SoftwareRasterizer gebastelt. Er damals in Java, ich in C++.. wir haben beide mehr oder weniger alles identisch gehabt (eben mit gewissen unterschieden durch die sprache bedingt) - hatten anfangs auch sehr viel mit immer neuen instanzen gemacht etc. Hatten da am anfang ca. 20fps... nach allen möglichen optimierungen (was vorallem das entfernen von "new" operatoren betrifft) hatten wir ca. 150fps... da sieht man sehr deutlich das es eben NICHT immer das beste ist alles immutable zu machen.
Und nur für die Benchmark Statistik: Der Java Code war nach allen erdenklichen optimierungen immernoch ein gutes stück (ca. 20fps) langsamer als der entsprechende C++ Code..
Oh ich glaube, da gibt's ein kleines Missverständnis Ich hab' nicht gemeint (scheint aber wohl so rübergekommen zu sein... ^^), dass es sinnvoll wäre, auf Teufel komm raus seine komplette Applikation immutable zu machen. Das wäre genauso sinnfrei wie das sklavische Anwenden jeder anderen Design-Prinzipien.
Es gibt sogar eine ganze Reihe Dinge, die immutable nur sehr schwer umzusetzen sind. Exemplarisch seien hier mal ein paar genannt:
I/O bei Dateisystemen (Man stelle sich ne 500 MB Datei vor, die für jedes geänderte Byte komplett neu geschrieben wird)
I/O bei Konsolen (Es gibt nunmal nur ein stdout und das lässt sich auch nicht so einfach umbiegen ^^)
GUIs (Ist immutable nur schwer mit dem Eventmodell und den Handles der zugrunde liegenden Betriebsysteme vereinbar)
OpenGL (Der Device- und RenderingContext zum Beispiel... Da würde sich das OS freuen, wenn man für jeden Frame neue anfordern würde ^^)
Und dabei hab' ich die Performance-Penalty mal ganz außer Acht gelassen. Es gibt zwar auch hierfür Lösungen, aber die sind den "old-school" mutable Lösungen meist deutlich unterlegen.
Ich wollte mitnichten sagen, dass man seine Anwendung komplett immutable machen muss und soll. Es gibt einfach manche Dinge, die sich auch schöner in mutable code abbilden lassen und dort auch ohne das relativ automatische Multi-Threading sehr performant sind. Das ist ähnlich wie die Diskussion ob man nun rein funktional oder rein imperativ programmieren soll. Imho machen beide Extreme so allein keinen Sinn und genau das gefällt mir an Scala auch so verdammt gut: Man kann sich einfach das Beste aus allen Welten rauspicken. Objektorientierung für das ganze Konzept, für das Design der Applikation; funktionale Elemente für Teile der Implementierung; immutable Objekte, um das Datenmodell zu vereinfachen und Multithreading geschenkt zu bekommen und dann an den wenigen wirklich performance-kritischen Stellen wieder imperativen, mutable Code. Und im Falle von Scala spielen all diese Konzepte wunderbar Hand in Hand.
Ich hoffe, ich konnte etwas Licht in die Sache bringen ~ Frase
_________________ "Für kein Tier wird so viel gearbeitet wie für die Katz'."
Das mit den immutable Objects scheint bisher ganz gut zu klappen. Nur gibt es eine Sache, bei der ich keine Ahnung hab, wie man sicherstellen kann, dass man immer immutable Zugriff hat. Nämlich wenn man ein interface oder eine abstrakte Klasse hat und eine Referenz darauf speichert.
Dann kann man über diese Referenz auch Objekte übergeben, die nicht immutable sind. Man kann im interface ja nicht definieren: Alle Klassen die das implementieren, müssen jetzt aber immutable sein. Kopieren kann man in diesem Fall aber auch nicht, weil sich interfaces nicht instanziieren lassen.
Kleines Beispiel:
Code:
public interface A { public void foo(); }
final public class B { final private A a;
public B(A a) { this.a = a; // wie verhindere ich, dass man mir hier etwas unterschiebt, was nicht immutable ist? } }
Das ist eindeutig eines der Dinge, die man einfach per Konvention so handhabt. Es gibt keinen generellen Weg, sinnvoll zu gewährleisten, dass eine hereingegebene Klasse immutable ist. Das legst du einfach per Konvention so fest. Da das auch innerhalb deines eigenen Codes ist, sollte das auch nicht weiter tragisch sein Wenn das allerdings Teil einer öffentlichen API sein soll, würde ich davon ausgehen, dass der User da nicht so firm ist und durchaus mutable Objects reingibt. Da hilft dann nur, um sicher zu sein, eine Kopie davon zu machen.
Wie man interfaces kopiert? In die Verlegenheit bin ich noch nicht gekommen - eventuell kannst du da auch sinnvoll was an deinem Design ändern. Andernfalls... kopier' halt nur das, was das interface auch auszeichnet. Dein interface "A" sagt ja, dass es eine foo() Methode hat... Also brauchst du auch nur dafür zu sorgen, dass das neue Objekt in der foo() Methode das gleiche zurückliefert wie das alte und schon sind beide Objekte (Aus der Sicht des interfaces) nicht mehr voneinander zu unterscheiden. Interfaces nutzt man ja auch gerade deswegen, um zu sagen: "Mich interessiert nicht, wie das Objekt dahinter aufgebaut ist. Es muss sich nur in bestimmter Weise verhalten".
Immer dran denken, die Objekte müssen sich nach außen hin auch nur immutable verhalten. Wie genau sie intern aufgebaut sind, ist erstmal zweitrangig (Immutable macht auch intern meist Sinn, manchmal ist man mit mutable aber auch besser dran).
Und auch deine A-implementierende Klasse muss sich nur so verhalten, als wär sie eine Kopie der alten (Also die Werte der alten zurückgeben).
Hoffe das war jetzt nicht zu verwirrend geschrieben ~ Frase
_________________ "Für kein Tier wird so viel gearbeitet wie für die Katz'."
Danke für die Erläuterung. Ich weiß jetzt auf jeden Fall, dass es an der Stelle wo ich das mache, keine Probleme geben sollte. Aber wie es sich damit genau verhält werde ich in einem späteren Entwicklungsstadium rückwirkend begutachten können
Registriert: Do Sep 25, 2003 15:56 Beiträge: 7810 Wohnort: Sachsen - ERZ / C
Programmiersprache: Java (, Pascal)
@Frase: Wie wärs wenn du das Thema mal separierst. Das hat ja nicht wirklich mit deinem Spiel zu tun, und ist vielleicht auch unabhängig von diesem interessant.
_________________ Blog: kevin-fleischer.de und fbaingermany.com
Den Gedanken hatte ich auch schon, aber ich möchte mit Yang bei DGL ja auch gerade den Code und die verwendeten Techniken erläutern, in der Hoffnung, dass das irgendwer nützlich findet . Solang es beim aktuellen Beteiligungsgrad bleibt, denke ich, ist die Themenvermischung noch verschmerzbar Bin aber tatsächlich positiv überrascht ob der Menge des Feedbacks Dafür bei der Gelegenheit mal Danke ^^
~ Frase
_________________ "Für kein Tier wird so viel gearbeitet wie für die Katz'."
Die Sache mit der Clock klingt interessant. Wird das auch für die Bewegung der/des Spielers/Gegner benutzt? Damit hätte man einen ziemlich hohen Grad an Determinismus, was für Replay-Funktionen / Time Reverse und so etwas interessant sein dürfte.
ja, das wird auch für Spielerbewegungen genutzt werden. Generell für alles mit einem zeitlichen Verlauf Der hohe Grad an Determinismus war auch ein Hauptgrund für diese Herangehensweise. Es ist wirklich sehr angenehm, wenn sich das Spiel / Datenmodell beweisbar immer gleich verhält (Wie ne ordentliche Simulation). Das ist auch gerade für die Unit-Tests / Integrations-Tests sehr praktisch. Und für Replay-Funktionen freilich auch, ja
Ein Zurückgehen in der Zeit werde ich aber explizit nicht unterstützen. Hab' dafür keinen Usecase und es würde das ganze daher nur unnötig verkomplizieren. Der Code ist weeesentlich simpler, wenn man nur eine Richtung in der Zeit erlaubt.
Ich erlaube ja nichtmal, dass die Zeit stehenbleibt (In der Simulation). Es wird natürlich trotzdem nen Pause-Modus geben Aber da wird dann die komplette Simulation angehalten und nicht mit einer stillstehenden Zeit fortgeführt (Kleiner, aber feiner Unterschied ^^).
~ Frase
_________________ "Für kein Tier wird so viel gearbeitet wie für die Katz'."
Registriert: Do Jun 28, 2007 17:58 Beiträge: 193
Programmiersprache: Pascal, C
Frase hat geschrieben:
Der Code ist weeesentlich simpler, wenn man nur eine Richtung in der Zeit erlaubt.
Genau das hat sich Gott wohl auch gedacht
Ich persönlich halte eine globale "Clock" nicht für unbedingt nötig, wirkliche Probleme hatte ich mit der "Zeitdifferenz"-Methode noch nie, auch wenn du mit deiner Methode natürlich die Rechenfehler minimierst.
In beiden Fällen muss man aber sowieso dafür sorgen, dass zum Beispiel Kollisionsüberprüfungen nicht mit dem aktuellen "ist"-Zustand rechnen, sondern mit Richtungsvektoren arbeiten. Diese werden ja nur durch die Zeitdifferenz skaliert. Und so klein, dass man bei einem Double Angst um gigantische Ungenauigkeiten bei jeder Addition haben muss, werden die Zeitdifferenzen ja auch nicht - meistens bewegen sich diese in einem Bereich von um die 0,01s und bei Bewegungsgeschwindigkeiten von 1 LE/s bewegt man sich da in einem Bereich, mit dem ein Double auf jeden Fall klar kommt.
Die Frage ist, ob der zusätzliche Aufwand mit praktisch messbaren Ergebnissen zu rechtfertigen ist.
so viel höher ist der Aufwand doch gar nicht Im Gegenteil, wenn man im Hinterkopf behält, wie leicht man damit Replays machen kann, hat man mit der Clock weniger Aufwand, weil man dadurch recht viel geschenkt bekommt, was man bei der Herangehensweise mit der Zeitdifferenz erst noch umständlich nachbilden müsste. Außerdem ist die Clock imho eine natürlichere Modellierung der Zeit als das Zusammenstöpseln aus Zeitdifferenzen (was relativ technisch ist).
Die höhere Genauigkeit ist eigentlich mehr ein Nebeneffekt. Hauptsächlich wollte ich den ganzen Spaß möglichst elegant in meinem Datenmodell abbilden
Ich denke, bei der traditionellen Zeitdifferenz-Methode sieht man den Wald vor lauter Bäumen nicht. Diese ganze Logik in einer Clock zu kapseln, die man einfach nach der Zeit fragen kann, ist so viel natürlicher und imho direkter als so "low-level" die Zeitdifferenzen der einzelnen Frames durch die Gegend zu reichen. Das ist meine Hauptmotivation Die höhere Genauigkeit kommt mir vor allem erstmal in den Tests zugute, wo ich dann viel exakter auf bestimmte Werte prüfen kann, weil ich weniger Angst vor Rundungsfehlern haben muss.
Grüße ~ Frase
_________________ "Für kein Tier wird so viel gearbeitet wie für die Katz'."
Mitglieder in diesem Forum: 0 Mitglieder und 1 Gast
Du darfst keine neuen Themen in diesem Forum erstellen. Du darfst keine Antworten zu Themen in diesem Forum erstellen. Du darfst deine Beiträge in diesem Forum nicht ändern. Du darfst deine Beiträge in diesem Forum nicht löschen. Du darfst keine Dateianhänge in diesem Forum erstellen.