Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

TrommlBomml

Community-Fossil

Beiträge: 2 117

Wohnort: Berlin

Beruf: Software-Entwickler

  • Private Nachricht senden

61

16.01.2014, 12:08

Weil Getter und Setter logischerweise immer gebraucht werden. Wenn du mir erzählen möchtest, dass eine gute OOP keine Eigenschaften eines Objektes veröffentlichen soll. Ich wüsste ehrlich gesagt nicht, warum das so schlechtes Design ist. Das man keine Attribute einer Klasse direkt veröffentlicht ist klar, aber Properties bzw. Getter- und Setter sind doch vollkommen legitim. Und ich finde es eher eine ziemlich ungünstige Einschränkung, wenn man keine Eigenschaften veröffentlicht. Ich kenne auch ehrlich gesagt genau 0 Projekte, sei es OpenSource oder ClosedSource, die diesen Ansatz verfolgen. Was soll denn der Vorteil davon sein, außer das die Schnittstellen vielleicht genauer, aber komplizierter werden?

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

62

16.01.2014, 12:24

Weil Getter und Setter logischerweise immer gebraucht werden.

I beg to differ, meiner Erfahrung nach braucht man Getter und Setter extrem selten. So selten, dass mir gerade nichtmal ein Beispiel einfällt, wo man welche brauchen könnte...

Wenn du mir erzählen möchtest, dass eine gute OOP keine Eigenschaften eines Objektes veröffentlichen soll.

Was genau meinst du mit "Eigenschaften"?

Ich wüsste ehrlich gesagt nicht, warum das so schlechtes Design ist.

Weil es Implementierungsdetails der Klasse aus der Schnittstelle leaked. Oft selbst dort noch wo nicht einfach nur direkt ein Datenmember exposed wird, was allerdings bei einem beachtlichen Teil aller Properties, über die ich bisher so gestolpert bin, leider der Fall ist...

Was soll denn der Vorteil davon sein, außer das die Schnittstellen vielleicht genauer, aber komplizierter werden?

Die Schnittstellen werden meiner Erfahrung nach wesentlich klarer und einfacher. Inbesondere hilft es, die Kopplung von verwendendem Code an einen konkreten Typ zu vermeiden und steigert damit die Wiederverwendbarkeit... ;)

Sacaldur

Community-Fossil

Beiträge: 2 301

Wohnort: Berlin

Beruf: FIAE

  • Private Nachricht senden

63

16.01.2014, 12:31

Wenn man Properties verbieten will, weil sie unsauberen (im Sinne der OOP) Code ermöglichen, sollte es auch mechanismen geben, die Getter und/oder Setter unterbinden, die lediglich einen Wert einem Member zuweisen oder den Wert eines Members zurückliefern.
Der Grund, der gegen Getter und Setter spricht, dürfte die Verwendung sein. Deine (dot) Meinung dazu dürfte, wenn ich mich nicht irre, sein, dass man grundsätzlich nur einen Getter oder nur einen Setter braucht, da es andernfalls häufig schlechtes Design dazu führt, beides zu haben.
Übertragen auf die Properties heißt das aber auch nur, dass auf diese von außen auch nur entweder lesend oder schreibend zugegriffen werden sollte. In C# gibt es bspw. die Möglichkeit, dass der Setter oder der Getter privat sind, wodurch diese nicht von außen verwendet werden können, man aber dennoch die Wertprüfungen (im Falle eines privaten Setters), die ggf. durchgeführt werden, bei jeder Zuweisung ausgeführt werden.

Ich finde dots Hintergründe berechtigt, Properties sollten aber dennoch aufgenommen werden.

Auch angucken könnte man sich in dem Zusammenhang die Herangehensweise von Python. Und wenn man schon einen Blick auf Python wirft, kann man sich auch die Magic Member ansehen, über welche das Standardverhalten (bspw. Operatorüberladung) beeinflusst wird.
Ich finde diese Lösungen in Python durchaus elegant (es entstehen nicht unmengen von Schlüsselwörter bzw. die vorhandenen werden nicht je nach Kontext anders interpretiert), allerdings auch im Kontext von Python. Ich will also nicht sagen, dass du dich daran orientieren sollst, allerdings kann es nicht schaden, andere herangehensweisen gesehen zu haben.
Spieleentwickler in Berlin? (Thema in diesem Forum)
---
Es ist ja keine Schande etwas falsch zu machen, als Programmierer tu ich das täglich, [...].

TrommlBomml

Community-Fossil

Beiträge: 2 117

Wohnort: Berlin

Beruf: Software-Entwickler

  • Private Nachricht senden

64

16.01.2014, 12:32

Das klingt für mich alles ziemlich wage und theoretisch. Mit Eigenschaften meine ich Felder einer Klasse. Programme bestehen doch nunmal aus Daten und Logik. Ich denke bestes Beispiel ist doch wohl Darstellung von Daten. Wenn du getrennte Schichten für Darstellung und Logik hast, dann muss die Darstellung die Daten aus der Logik-Schicht bekommen. Wie soll das denn bitte ohne Getter gehen?! (Ich vernachlässige jetzt mal aus Einfachsheitsgründen Darstellungsobjekte, bspw. ViewModels).

David Scherfgen

Administrator

Beiträge: 10 382

Wohnort: Hildesheim

Beruf: Wissenschaftlicher Mitarbeiter

  • Private Nachricht senden

65

16.01.2014, 12:59

@dot:
Was ist denn mit sowas wie SetPosition oder SetColor für irgendwelche grafischen Objekte? Oder SetCaption für ein GUI-Element?
Wie würdest du das anders machen? Klar könnte man SetPosition auch MoveTo nennen (oder so ähnlich), aber im Kern bliebe es dasselbe.

Sacaldur

Community-Fossil

Beiträge: 2 301

Wohnort: Berlin

Beruf: FIAE

  • Private Nachricht senden

66

16.01.2014, 13:25

War ich wirklich so langsam im Schreiben meines Beitrags? (Hatte dots Beitrag nicht gesehen...)

Dagegen habe ich auch nichts gesagt. In diesem Fall muss die View Daten aus den antsprechenden Objekten erhalten, sie muss aber keine Daten zuweisen. Und seitens der Logik könnte es ausreichend sein, die Daten dem Konstruktor zu übergeben.

Ein anderes Beispiel wäre eine Klasse, die bspw. eine Internetverbindung aufbauen soll (z. B. für ein Spiel über Internet). Eine Eigenschaft dieser Klasse könnten die Informationen über die aktuell offene Verbindung sein (entfernte Adresse, entfernter Port, ...). Man könnte auf die Idee kommen, über das Zuweisen von Werten an diese Eigenschaft die Verbindung zu ändern, allerdings sollte dafür (meiner Meinung nach) eine separate Methode vorhanden sein, da das Aufbauen der Verbindung ggf. das Beenden der aktuellen Verbindung erfordert, der Aufbau der neuen Verbindung fehlschlagen kann etc. Wenn erst die bestehende erfolgreich abgebaut wurde und der Aufbau der neuen Verbindung fehlschlagen würde, würde unerwarteterweise ein leerer Eintrag an dieser Stelle stehen, da keine Verbindung da ist. Man könnte diesen Fall vermeiden, indem man daraufhin einen Wiederaufbau zum vorherigen Server durchführt, allerdings kann auch dieser fehlschalgen und es ist dennoch grundsätzlich nicht mehr der gleiche Zustand.


@David:
Diese könnten auch im Konstruktor zugewiesen werden.
Wenn sich eine Überschrift ändern kann, dann hat man entweder eine feste Anzahl an Überschriften und einen eigenartigen Mechamismus zum Ändern des Inhalts oder der Inhalt richtet sich nach bestimmten Objekten im Hintergrund.
ein Beispiel für letzteres könnte eine Serverliste und eine Vorschau des selektierten Servers sein. Dort gäbe es eine Überschrift, die den Namen des selektierten Servers anzeigt (oder die Felder, die andere Daten anzeigen). In dem Fall wäre es ohnehin angenehmer, wenn man nicht die Daten selbst setzen müsste, sondern definieren könnte, woher die Daten bezogen werden.
Wenn man letzteres machen kann, dann dürfte es an anderen Stellen ziemlich uninteressant sein, was diesem Element als Datenquelle zugewiesen wurde.
Wenn der Text fest zugewiesen ist, dann wird er auch nur einmal gesetzt und sollte dann auch gänzlich unwichtig sein.

Wen man will, kann man an dieser Stelle um einen Setter herum kommen (Zuweisen beim Konstruktoraufruf), wenn das Design allerdings nicht über code vorgenommen wird bzw. beim generierten Code die Eigenschaften nicht über den Konstruktor zugewiesen werden können (bspw. bei WPF der Fall), ist ein Setter erforderlich.
In beiden Fällen sollte ein Getter aber nicht notwendig sein (und der Setter nur einmalig aufgerufen werden).


@LetsGo:
Soweit ich das einschätze, geht es hier nicht um Getter+Setter vs. direkter Zugriff, sondern um Getter+Seter vs. entweder Getter oder Setter.
Spieleentwickler in Berlin? (Thema in diesem Forum)
---
Es ist ja keine Schande etwas falsch zu machen, als Programmierer tu ich das täglich, [...].

  • »Spiele Programmierer« ist der Autor dieses Themas

Beiträge: 1 223

Wohnort: Deutschland Bayern

Beruf: Schüler

  • Private Nachricht senden

67

16.01.2014, 13:33

Ich kann Dots Argumentation ehrlich gesagt auch nicht ganz nachvollziehen.
Ich bin auch grundsätzlich gegen die Philosophie, Programmierer durch die Sprache disziplinieren zu wollen.

Eine Meiner Meinung nach sehr interessante Sprache ist "D".
Properties werden dort als "Set*" bzw. "Get*" im Namen deklariert, wobei man auf entsprechende Funktionen dann zugreifen kann wie auf Properties in C#. So etwas finde ich in so fern sinnvoll, als das ein unnötiges Syntaxkonstrukt eingespart wird.

Das ist auch der Grund, weshalb ich dieses "Copy"-Konstrukt nicht so gut finde. Es bringt Komplexität in die Sprache die leicht zu vermeiden wäre.
Für so Dinge wie automatische "Copy"-Generation würde ich eher Versuchen, die Sprache flexibel genug zu machen, dass solche Funktionalität in Form von Bibliotheksfunktionen eingebaut werden kann.

Referenzzählung sehe ich auch sehr kritisch.
Aus Sicht der Performance ist es in C++ wegen der Cachebelastung auch ein Horror. Ich würde lieber versuche, dass Konzept von C++ mit verschiedenen Formen der Besitzverhältnisse zu vereinfachen und auszubauen.

Zitat

Wen man will, kann man an dieser Stelle um einen Setter herum kommen

Ja, aber warum?
Welchen Vorteil hat es konkret, wenn ich jedesmal ein neues Objekt erstellen muss und alle Werte kopieren?

Zitat

Man könnte auf die Idee kommen, über das Zuweisen von Werten an diese Eigenschaft die Verbindung zu ändern,

Missbrauch gibt es immer. Es gibt zum Beispiel auch so Speziallisten, die Exceptions zum Beenden einer Schleife verwenden. Fast alle Sprachfeatures kann man auch falsch einsetzen.

Zitat

In beiden Fällen sollte ein Getter aber nicht notwendig sein

Properties müssen ja nicht immer einen Setter und Getter besitzen.

TrommlBomml

Community-Fossil

Beiträge: 2 117

Wohnort: Berlin

Beruf: Software-Entwickler

  • Private Nachricht senden

68

16.01.2014, 13:48

@dot:
Was ist denn mit sowas wie SetPosition oder SetColor für irgendwelche grafischen Objekte? Oder SetCaption für ein GUI-Element?
Wie würdest du das anders machen? Klar könnte man SetPosition auch MoveTo nennen (oder so ähnlich), aber im Kern bliebe es dasselbe.


Danke David! Meine Rede. Wenn man das alles vermeidet, dann wird der Code meiner Meinung nach vielleicht irgendwo strikter und klarer, aber doch auch komplizierter.

LukasBanana

Alter Hase

Beiträge: 1 097

Beruf: Shader Tools Programmer

  • Private Nachricht senden

69

16.01.2014, 13:58

Ich bin auch grundsätzlich gegen die Philosophie, Programmierer durch die Sprache disziplinieren zu wollen.

Dito.

Und Davids Beispiel ist mir auch als erstes Eingefallen. SetPosition, SetColor etc. brauche ich persönlich für Grafik Objekte sehr häufig.
Warum sollte man das nur über Konstruktoren machen? Die Position kann sich ja ständig ändern.

Die Attribute für setter und getter will ich also auf jeden Fall einbauen, bzw. habe es schon.
Auch möchte ich die Attribute noch erweitern. Ein weiteres Attribut gibt es z.B. für Klassen:

Quellcode

1
2
// Pack-Attribut (#p)
#p class Test { /* ... */ }

Wird zu:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#if defined(_MSC_VER)
#   pragma pack(push, packing)
#   pragma pack(1)
#   define __XX__PACK_STRUCT__
#elif defined(__GNUC__)
#   define __XX__PACK_STRUCT__ __attribute__((packed))
#else
#   define __XX__PACK_STRUCT__
#endif

class Test { /* ... */ } __XX__PACK_STRUCT__;

#ifdef _MSC_VER
#   pragma pack(pop, packing)
#endif

#undef __XX__PACK_STRUCT__

Das habe ich z.B. oft gebraucht, wenn ich Strukturen direkt aus einer Datei lesen wollte.
Da aber der Compiler bei Optimierung Byte-Alignments nach belieben einbauen kann, sollte das dadurch verhindert werden.

Die Syntax mit dem '#' gefällt mir noch nicht so gut, bisher ist das aus Gründen des Parsers so gelöst.
(Eigentlich wollte ich das wie in HLSL mit bspw. dem "[unroll]" Attribut machen.)

Zur (mitlerweile) etwas älteren Frage:

Zitat von »dot«

Gibt es eigentlich schon ein Konzept von Klassen oder überhaupt eines Typsystems? Wie sieht es mit Vererbung aus?

Mit Vererbung habe ich auch schon angefangen, allerdings wird diese Sprache nicht (wie bswp. C# oder Java) eine rein OOP Sprache werden.
Nicht alles muss also ein Objekt sein (afaik ist in C# sogar jedes Integer-Literal ein Objekt).
Ich persönlich erachte u.A. Interfaces - die erzwungener Maßen keine Funktions-Implementierungen haben können - als eher unwichtig in einer Sprache.
Wer ein reines Interface habe will, der soll eine reine abstrakte Klasse schreiben - das geht mit meiner Sprache auch, so wie in C++ mit "virtual ... = 0",
bei mir heißt es dann halt "abstract ...".

EDIT:

Zitat von »dot«

Du hast offenbar eingebautes Reference Counting? Wie genau werden zyklische Abhängigkeiten vermieden bzw. behandelt? Gibt es andere Formen von Besitzverhältnissen? Wenn nein würde mich interessieren, wieso du dich gerade für Reference Counting entschieden hast.

Es gibt standard C++ pointer und smart pointer, aber nur smart pointer können allokiert werden, weil es nur managed memory geben soll.
So könnte man z.B. eine Baumstruktur anlegen, ohne dass Zyklen beim Reference-Counting entstehen:

Quellcode

1
2
3
4
5
6
class BinaryTree {
    int data
    BinaryTree* parent // (non-owner)
    BinaryTree@ childA // (owner)
    BinaryTree@ childB // (owner)
}


Ich habe genau deshalb Reference-Counting ewählt, weil das schon in C++11 und boost implementiert ist.
Außerdem halte ich Garbage-Collection für ineffizienter (zumindest was die Leistung betrifft).
In Objective-C z.B. wird GC zwar generell unterstützt, für iPhone/ iPad ist es aber nicht verfügbar.

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »LukasBanana« (16.01.2014, 14:16)


Architekt

Community-Fossil

Beiträge: 2 481

Wohnort: Hamburg

Beruf: Student

  • Private Nachricht senden

70

16.01.2014, 14:39

Ich kann Dots Argumentation ehrlich gesagt auch nicht ganz nachvollziehen.
Ich bin auch grundsätzlich gegen die Philosophie, Programmierer durch die Sprache disziplinieren zu wollen.

Eine Meiner Meinung nach sehr interessante Sprache ist "D".
Properties werden dort als "Set*" bzw. "Get*" im Namen deklariert, wobei man auf entsprechende Funktionen dann zugreifen kann wie auf Properties in C#. So etwas finde ich in so fern sinnvoll, als das ein unnötiges Syntaxkonstrukt eingespart wird.

Das ist bzw. war Konvention. Der D Compiler kann schon seit Ewigkeiten Methoden/Funktionen wie Properties behandeln, will heißen, dass man leere () weglassen kann. Gab auch einige Zeit lang die Debatte, dass solche Methoden extra mit @property markiert werden müssten und der -property Flag wurde eingeführt. Mittlerweile ist aber mehrheitlich abgestimmt worden, dass für jede Methode die leeren () weggelassen werden dürfen (z.B. für UFCS), wie ursprünglich vorgesehen. Daher wird @property deprecated und der -property Flag abgeschafft werden. Aber das ist wohl schon etwas Offtopic, wollte es nur klar stellen. :)
Der einfachste Weg eine Kopie zu entfernen ist sie zu löschen.
- Stephan Schmidt -

Werbeanzeige