Methoden mit bool-Parametern und "Lesbarkeit" im Kontext
-
Xin schrieb:
CStoll schrieb:
Xin schrieb:
CStoll schrieb:
Schön, wenn du eine Sprache hast, die zwischen Zuständen und Teilobjekten unterscheiden kann. C++ kann das leider nicht, also brauchst du gar nicht versuchen, es dazu zu bringen.
Super Einstellung. "Ich" kann das nicht, also brauchst "Du" es nicht zu versuchen.
Ich versuche es trotzdem. Sich derart dagegen zu wehren bringt aber nix, ich zwinge schließlich niemanden hier, es zu nutzen.Doch, du versuchst krampfhaft, mir zu erklären, daß dein Ansatz besser ist.
Vielleicht macht Dir diese Antwort verständlich, wie krampfhaft ich versuche Dich von etwas zu überzeugen. Denk selbst drüber nach, oder lass es - es zwingt Dich niemand.
Schön, daß du jetzt anfängst, meine Beiträge inhaltlich zu ignorieren.
OK, fassen wir nochmal die bisherigen Beispiele zusammen, die laufen alle auf einen ähnlichen Denkfehler hinaus: Du kannst mit Ableitung die Fähigkeiten einer Klasse erweitern, aber nicht einschränken.
-
WindowFlags vs. Window:
Die Klasse WindowFlags hat einen operator bool() (und auch wenn du das "s" noch so sehr betonst, ein einzelnes Flag ist auch von diesem Typ), die Klasse Window als bool zu betrachten ist sinnlos (und wenn nicht, dann mit einer völlig anderen Semantik als für WindowFlags). Da ist es egal, ob du eine technische (op bool ist privat und der Compiler beschwert sich, wenn man es nutzen will) oder konzeptionelle (irgendwo in der Doku steht "benutze nie 'if(win)...'") Einschränkung hast - du hast eine Einschränkung.
(und im Ernstfall sind mir technische Einschränkungen lieber) -
Ableitungen von int:
Du hast alle Maßangaben (Längen, Gewichte etc) von int abgeleitet, um Schreibarbeit zu sparen. Aber damit hast du gleichzeitig massenweise Mehraufwand, um sie vernünftig nutzen zu können: -
Alle Operatoren liefern int-Werte, also brauchst du entweder Typumwandlungen von int in deine Typen (aber dann geht die Typsicherheit verloren, wenn du beliebig Gewichte und Längen miteinander verwursten kannst) oder eigene überladene Operatoren (aber dann brauchst du die Verwandtschaft mit int nicht mehr)
-
btw, op+ und op- zu überladen mag ja noch recht einfach sein, aber bei op* und op/ wird's dann haarig (die schlucken zwei beliebige Maßangaben und geben eine völlig andere Angabe wieder heraus) - davon, was bei op& und Co. rauskommen sollte, will ich gar nicht anfangen.
(erzähl mir jetzt bitte nichts von Templates - ich kenne eine Template-Lösung dafür, aber die braucht keine Vererbung von int) -
Wertekombination durch Vererbung:
In den wenigstens Fällen sind die Attribute eines Objekts unabhängig voneinander (die Maximalgeschwindigkeit eines Autos hängt von der Motorleistung ab, die linke obere Ecke eines Fensters von der rechten oberen Ecke etc). Die einzelnen Basisklassen sind aber konzeptionell unabhängig voneinander - also mußt du in der abgeleiteten Klasse dafür sorgen, daß sie sich konsistent zueinander ändern.
PS: Die Allergie hatte ich übrigens erwähnt, weil du mit den Allergiewarnungen angefangen hast - es gibt halt auch Menschen, die unter mehr leiden als einem (eher harmlosen) Heuschnupfen (btw, ich kenne auch jemanden mit einer Nussallergie). Und die sind dankbar, wenn sie rechtzeitig über (potentiell) gefährliche Nahrungsmittel informiert werden.
PPS: Mich hast du übrigens auch zum Nachdenken gebracht - mit dem Ergebnis, daß ich deine Lösung nach längerem Nachdenken als unsinnig eingestuft habe.
-
-
CStoll schrieb:
Xin schrieb:
CStoll schrieb:
Xin schrieb:
CStoll schrieb:
Schön, wenn du eine Sprache hast, die zwischen Zuständen und Teilobjekten unterscheiden kann. C++ kann das leider nicht, also brauchst du gar nicht versuchen, es dazu zu bringen.
Super Einstellung. "Ich" kann das nicht, also brauchst "Du" es nicht zu versuchen.
Ich versuche es trotzdem. Sich derart dagegen zu wehren bringt aber nix, ich zwinge schließlich niemanden hier, es zu nutzen.Doch, du versuchst krampfhaft, mir zu erklären, daß dein Ansatz besser ist.
Vielleicht macht Dir diese Antwort verständlich, wie krampfhaft ich versuche Dich von etwas zu überzeugen. Denk selbst drüber nach, oder lass es - es zwingt Dich niemand.
Schön, daß du jetzt anfängst, meine Beiträge inhaltlich zu ignorieren.
Sorry, aber inhaltlich kam nicht mehr viel und Du spielst hier ein unsinniges Spiel mit mir: Antworten, um dagegen zu sein. Dass ich seit x Seiten Dir zustimme, dass die Komposition in C++ besser als die Ableitung ist, ignorierst Du und behauptest auch noch, dass ich krampfhaft versuche zu erklären, dass Vererbung besser wäre.
Wo soll ich denn einen Grund sehen, Dich da inhaltlich überhaupt zu beachten.CStoll schrieb:
OK, fassen wir nochmal die bisherigen Beispiele zusammen,
Wir? Wer ist "wir"?
Ich fasse es mal so auf, dass Du zusammenfasst und ich ergänze.
CStoll schrieb:
WindowFlags vs. Window:
Die Klasse WindowFlags hat einen operator bool() (und auch wenn du das "s" noch so sehr betonst, ein einzelnes Flag ist auch von diesem Typ),Hier ignorierst Du erstens mehrfach genannte Möglichkeit das durch Trennung in zwei Klassen zu ändern... und die oben genannte Tatsache, dass ich die Komposition seit Seite iirc 7 als die bessere Möglichkeit ansehe...
CStoll schrieb:
die Klasse Window als bool zu betrachten ist sinnlos (und wenn nicht, dann mit einer völlig anderen Semantik als für WindowFlags). Da ist es egal, ob du eine technische (op bool ist privat und der Compiler beschwert sich, wenn man es nutzen will) oder konzeptionelle (irgendwo in der Doku steht "benutze nie 'if(win)...'") Einschränkung hast - du hast eine Einschränkung.
(und im Ernstfall sind mir technische Einschränkungen lieber)Welche technische Einschränkung bietet Dir denn ein "int Flags", die "übliche" und bewerte "Technik".
Selbst, wenn ich ableite (Komposition in C++ besser, S. 7. blahblah), bin ich besser eingeschränkt, als mit einem popligen int, dass mangels Typ eigentlich alles darstellen kann.
Halt stop, nicht alles, es stellt zum Beispiel definitiv keine Zahl dar. Müsstest Du hier nicht operator + und operator -, und operator * und operator / erstmal abschalten, bevor Du hier was von technischen Einschränkungen schreibst?Schließe Dein Scheunentor und dann reden wir weiter. Und um Dein Scheunentor zu schließen, wirst Du vermutlich wieder bei class WindowFlags landen.
Noch ein "Detail", das in Deiner "Zusammenfassung" fehlt.
CStoll schrieb:
Ableitungen von int:
Du hast alle Maßangaben (Längen, Gewichte etc) von int abgeleitet, um Schreibarbeit zu sparen. Aber damit hast du gleichzeitig massenweise Mehraufwand, um sie vernünftig nutzen zu können:Uii... Mehraufwand, um Typsicher zu arbeiten?!
Hier liegen die Prioritäten definitiv anders. Aber wer überhaupt Klassen nutzt, sollte sich nicht über Mehraufwand beschweren, denn früher wurde sowas alles auch problemlos mit Arrays gelöst. Für die Typsicherheit hat man sich dann doch für den Mehraufwand der Klassen entscheiden und sicherlich möchtest Du heute auch nicht mehr zu Byte-Arrays zurückkehren.CStoll schrieb:
Alle Operatoren liefern int-Werte, also brauchst du entweder Typumwandlungen von int in deine Typen (aber dann geht die Typsicherheit verloren, wenn du beliebig Gewichte und Längen miteinander verwursten kannst) oder eigene überladene Operatoren (aber dann brauchst du die Verwandtschaft mit int nicht mehr)
Ich sehe in der Verwandschaft mit "Zahl" nichts schlechtes.
int p = Quarktaschen( 3 ) + Zitronenkuchen( 2 ) + Kaesekuchen( 5 );
cout "Genug Futter für " << p << "Personen da." << endl;CStoll schrieb:
btw, op+ und op- zu überladen mag ja noch recht einfach sein, aber bei op* und op/ wird's dann haarig (die schlucken zwei beliebige Maßangaben und geben eine völlig andere Angabe wieder heraus) - davon, was bei op& und Co. rauskommen sollte, will ich gar nicht anfangen.
Damit solltest Du aber anfangen, weil es die Qualität Deiner Software erhöht.
5 Kilogramm * 20 Meter / 4Sekunde^2 ergibt nunmal nicht 25.CStoll schrieb:
(erzähl mir jetzt bitte nichts von Templates - ich kenne eine Template-Lösung dafür, aber die braucht keine Vererbung von int)
Ich erzähle hier nichts von Templates - ich habe keine, aber ich bin gespannt, Deine Templatelösung zu sehen, die mir die Verbindung von Newton zu den Grundeinheiten erstellt.
CStoll schrieb:
[*]Wertekombination durch Vererbung:
In den wenigstens Fällen sind die Attribute eines Objekts unabhängig voneinander (die Maximalgeschwindigkeit eines Autos hängt von der Motorleistung ab, die linke obere Ecke eines Fensters von der rechten oberen Ecke etc). Die einzelnen Basisklassen sind aber konzeptionell unabhängig voneinander - also mußt du in der abgeleiteten Klasse dafür sorgen, daß sie sich konsistent zueinander ändern.Stimmt. Und wo liegt das Problem?
Mal abgesehen davon, dass die Relation zwischen zwei Eigenschaften bei Vererbung und Komposition beschrieben werden muss - woher soll der Computer sie schließlich wissen.
Das ist hier ungefähr so wichtig, wie die Paprikaallergie Deiner Oma.CStoll schrieb:
PS: Die Allergie hatte ich übrigens erwähnt, weil du mit den Allergiewarnungen angefangen hast - es gibt halt auch Menschen, die unter mehr leiden als einem (eher harmlosen) Heuschnupfen (btw, ich kenne auch jemanden mit einer Nussallergie). Und die sind dankbar, wenn sie rechtzeitig über (potentiell) gefährliche Nahrungsmittel informiert werden.
...
Wer als Nussallergiker Nüsse kauft, braucht den Hinweis nicht. Sollte er ihn doch brauchen, ist er vorrangig Intelligenzallergiker. Wann begreifst Du, dass die Aussage sich nicht auf die Allergie bezieht, sondern auf die Intelligenzleistung, die erforderlich ist, dass man als Nussallergiker nunmal keine Nüsse kauft, selbst wenn da keine Warnung auf der Packung steht...
Deine Oma kauft ja auch keine Paprika, wenn sie dagegen allergisch ist und Du wirst vermutlich niemals das Gras eines Fussballstadions pflegen, obwohl weder auf Paprika, noch auf dem Rasen Warnhinweise für Allergiker angebracht sind...CStoll schrieb:
PPS: Mich hast du übrigens auch zum Nachdenken gebracht - mit dem Ergebnis, daß ich deine Lösung nach längerem Nachdenken als unsinnig eingestuft habe.
Das 'längere Nachdenken' glaube ich Dir ehrlich gesagt nicht. Wer nachdenkt stellt Fragen und keine Behauptungen auf. Wer nachdenkt nimmt Informationen auf. Du konzentrierst Dich seit mehreren Seiten darauf, gegen etwas zu sein, dass nicht mehr zur Debatte steht, weil wir uns darüber schon einig waren. Es war Dir offenbar trotz längerem Nachdenken nicht möglich die unterschiedliche Themen zwischen Vererbung für Flags, WindowFlags und Typsicherung entsprechend voneinander gelöst zu besprechen.
Das Thema Vererbung für Flags ist seit x Seiten geklärt, erledigt, vorbei.
Du drängst mich mit jedem Posting in eine Position, die ich gar nicht mehr vertrete (Seite 7... Komposition besser in C++... jaddajadda...)
Und dass einige Dinge hier hypothetischer Natur sind, sollte Dir spätestens daran auffallen, wenn ich "class Meter : public int" schreibe, weil in C++ es nicht möglich ist von Primitiven abzuleiten.Deine "Zusammenfassung" ist eine Zusammenfassung Deiner Sichtweise. Da ist alles drin, was Du brauchst, um dagegen zu sein, aber nichts, was darauf hinweist, dass Du meine Texte gelesen hättest.
Das hat nichts mit denken zu tun, sondern dass ist einfach nur weiter texten, hübsch kombiniert mitCStoll schrieb:
Doch, du versuchst krampfhaft, mir zu erklären, daß dein Ansatz besser ist.
Ich denke, Dich hier inhaltlich zu ignorieren, ist eine sehr freundliche Form, auf einen derartigen Diskussionsstil zu reagieren.
Vielleicht kommt es in der x. Wiederholung bei Dir an: Ich zwinge Dich nicht, etwas zu nutzen. Ich zwinge Dir auch nicht ein Verständnis für Typsicherheit auf. Du kannst meinetwegen programmieren was und wie Du willst.
Alles, was ich hier angeboten habe, war eine Möglichkeit, typsicherer zu arbeiten. Diese Möglichkeit dient als Inspirationshilfe, die weiterhin verbesserungsfähig ist, was auch schon x mal geschrieben wurde.
Und ich habe keinen Bock auch nur eine weitere Seite in diesem Thread, Dich darauf aufmerksam zu machen.
Und darum habe ich auch kein Problem damit, dass Du Dich von mir inhaltlich ignoriert fühlst.
-
Vielleicht kommt es bei der xten Wiederholung bei Dir an:
1. Auf Seite 7 kann ich Deine Zustimmung, Komposition sei in dem Fall besser als Vererbung, nicht finden. Also such sie gefälligst bitteschön und schreib endlich die richtige Seitenzahl hin! Ebenfalls ist es möglich, daß Du Dich wie üblich diffus ausgedrückt hast- dann zitier einfach Deine Zustimmung mal!
2. Deine indirekte Selbstbeweihräucherung ist dumm. Diesmal keine Begründung mehr für meine Behauptung.
-
Xin schrieb:
int p = Quarktaschen( 3 ) + Zitronenkuchen( 2 ) + Kaesekuchen( 5 );
cout "Genug Futter für " << p << "Personen da." << endl;int p = Quarktaschen( 3 ) + Zitronenkuchen( 2 ) + Kaesekuchen( 5 ); cout << "Genug Futter für " << p << "Personen da." << endl;
-
Xin schrieb:
CStoll schrieb:
Xin schrieb:
CStoll schrieb:
Xin schrieb:
CStoll schrieb:
Schön, wenn du eine Sprache hast, die zwischen Zuständen und Teilobjekten unterscheiden kann. C++ kann das leider nicht, also brauchst du gar nicht versuchen, es dazu zu bringen.
Super Einstellung. "Ich" kann das nicht, also brauchst "Du" es nicht zu versuchen.
Ich versuche es trotzdem. Sich derart dagegen zu wehren bringt aber nix, ich zwinge schließlich niemanden hier, es zu nutzen.Doch, du versuchst krampfhaft, mir zu erklären, daß dein Ansatz besser ist.
Vielleicht macht Dir diese Antwort verständlich, wie krampfhaft ich versuche Dich von etwas zu überzeugen. Denk selbst drüber nach, oder lass es - es zwingt Dich niemand.
Schön, daß du jetzt anfängst, meine Beiträge inhaltlich zu ignorieren.
Sorry, aber inhaltlich kam nicht mehr viel und Du spielst hier ein unsinniges Spiel mit mir: Antworten, um dagegen zu sein. Dass ich seit x Seiten Dir zustimme, dass die Komposition in C++ besser als die Ableitung ist, ignorierst Du und behauptest auch noch, dass ich krampfhaft versuche zu erklären, dass Vererbung besser wäre.
Wo soll ich denn einen Grund sehen, Dich da inhaltlich überhaupt zu beachten.Wenn du mir irgendwo zugestimmt hast, dann vermutlich in einem kleinen Nebensatz, der in den ganzen "Ableitung ist besser/schöner/leichter verständlich"-Beiträgen untergegangen ist.
Xin schrieb:
CStoll schrieb:
OK, fassen wir nochmal die bisherigen Beispiele zusammen,
Wir? Wer ist "wir"?
Ich fasse es mal so auf, dass Du zusammenfasst und ich ergänze.
Ja, so kannst du es auffassen.
Xin schrieb:
CStoll schrieb:
WindowFlags vs. Window:
Die Klasse WindowFlags hat einen operator bool() (und auch wenn du das "s" noch so sehr betonst, ein einzelnes Flag ist auch von diesem Typ),Hier ignorierst Du erstens mehrfach genannte Möglichkeit das durch Trennung in zwei Klassen zu ändern... und die oben genannte Tatsache, dass ich die Komposition seit Seite iirc 7 als die bessere Möglichkeit ansehe...
Ja, diese Trennung hast du zwar erwähnt, aber im selben Satz wieder aufgehoben, indem du WindowFlags von WindowFlag ableiten wolltest. Und gegen eine saubere Trennung von "Flag" und "Flags" (bzw. Flaggable) habe ich auch nichts einzuwenden.
Xin schrieb:
CStoll schrieb:
die Klasse Window als bool zu betrachten ist sinnlos (und wenn nicht, dann mit einer völlig anderen Semantik als für WindowFlags). Da ist es egal, ob du eine technische (op bool ist privat und der Compiler beschwert sich, wenn man es nutzen will) oder konzeptionelle (irgendwo in der Doku steht "benutze nie 'if(win)...'") Einschränkung hast - du hast eine Einschränkung.
(und im Ernstfall sind mir technische Einschränkungen lieber)Welche technische Einschränkung bietet Dir denn ein "int Flags", die "übliche" und bewerte "Technik".
Selbst, wenn ich ableite (Komposition in C++ besser, S. 7. blahblah), bin ich besser eingeschränkt, als mit einem popligen int, dass mangels Typ eigentlich alles darstellen kann.Nein, ich verwende keinen "int Flags" - und wenn doch, kommt der Nutzer da nicht ohne weiteres dran. Ich biete dem Nutzer eine typsichere (und alleine existierende) Flag-Klasse und Methoden zum Setzen, Rücksetzen und abfragen von Flags in meinen Klassen.
Xin schrieb:
Schließe Dein Scheunentor und dann reden wir weiter. Und um Dein Scheunentor zu schließen, wirst Du vermutlich wieder bei class WindowFlags landen.
Die Klasse WindowFlags hatte ich schon recht weit vorne akzeptiert, nur nicht die Tatsache, daß du Flags und Flag in ein und die selbe Klasse gepackt hast.
Xin schrieb:
CStoll schrieb:
Ableitungen von int:
Du hast alle Maßangaben (Längen, Gewichte etc) von int abgeleitet, um Schreibarbeit zu sparen. Aber damit hast du gleichzeitig massenweise Mehraufwand, um sie vernünftig nutzen zu können:Uii... Mehraufwand, um Typsicher zu arbeiten?!
Hier liegen die Prioritäten definitiv anders. Aber wer überhaupt Klassen nutzt, sollte sich nicht über Mehraufwand beschweren, denn früher wurde sowas alles auch problemlos mit Arrays gelöst. Für die Typsicherheit hat man sich dann doch für den Mehraufwand der Klassen entscheiden und sicherlich möchtest Du heute auch nicht mehr zu Byte-Arrays zurückkehren.Du arbeitest aber nicht besonders typsicher, wenn alles ein int ist - und irgendwo ganz hinten dann festgestellt wird, daß das doch nicht der Fall ist. Und der Aufwand bleibt sich gleich, ob du nun von int ableitest oder int als Member verwendest - allerdings bei ersterem bleibt es viel länger unentdeckt, wenn du etwas übersiehst.
Xin schrieb:
CStoll schrieb:
Alle Operatoren liefern int-Werte, also brauchst du entweder Typumwandlungen von int in deine Typen (aber dann geht die Typsicherheit verloren, wenn du beliebig Gewichte und Längen miteinander verwursten kannst) oder eigene überladene Operatoren (aber dann brauchst du die Verwandtschaft mit int nicht mehr)
Ich sehe in der Verwandschaft mit "Zahl" nichts schlechtes.
int p = Quarktaschen( 3 ) + Zitronenkuchen( 2 ) + Kaesekuchen( 5 );
cout "Genug Futter für " << p << "Personen da." << endl;Verschiedene Kuchensorten sind sich vielleicht noch ähnlich genug, um so behandelt zu werden, aber was soll physikalisch herauskommen, wenn ich meine Körpergröße mit meinem Gewicht addiere?
Xin schrieb:
CStoll schrieb:
btw, op+ und op- zu überladen mag ja noch recht einfach sein, aber bei op* und op/ wird's dann haarig (die schlucken zwei beliebige Maßangaben und geben eine völlig andere Angabe wieder heraus) - davon, was bei op& und Co. rauskommen sollte, will ich gar nicht anfangen.
Damit solltest Du aber anfangen, weil es die Qualität Deiner Software erhöht.
5 Kilogramm * 20 Meter / 4Sekunde^2 ergibt nunmal nicht 25.Mit deinem Ansatz schon - und genau darauf wollte ich auch hinaus: Woher soll der Compiler wissen, was für ein Typ herauskommen soll, wenn du zwei wahllos herausgegriffene int-Derivate multiplizierst?
Xin schrieb:
CStoll schrieb:
(erzähl mir jetzt bitte nichts von Templates - ich kenne eine Template-Lösung dafür, aber die braucht keine Vererbung von int)
Ich erzähle hier nichts von Templates - ich habe keine, aber ich bin gespannt, Deine Templatelösung zu sehen, die mir die Verbindung von Newton zu den Grundeinheiten erstellt.
Nur grob skizziert und auch noch nicht vollständig:
template<int Meter,int Sekunde,int Kilogramm,...> class Measure { double val; public: Measure operator+(const Measure&r) { return Measure(val+r.val); } template<int M2,int S2,int K2,...> Measure<Meter+M2,Sekunde+S2,Kilogramm+K2,...> operator*(const Measure<M2,S2,K2,...>& r) { return Measure<Meter+M2,Sekunde+S2,Kilogramm+K2,...>(val*r.val); } ... }; typedef Measure<1,0,0,...> Laenge; typedef Measure<0,1,0,...> Zeit; typedef Measure<0,0,1,...> Masse; ... typedef Measure<1,-2,1,...> Kraft;// 1 N == 1 m * s^-2 * kgXin schrieb:
CStoll schrieb:
[*]Wertekombination durch Vererbung:
In den wenigstens Fällen sind die Attribute eines Objekts unabhängig voneinander (die Maximalgeschwindigkeit eines Autos hängt von der Motorleistung ab, die linke obere Ecke eines Fensters von der rechten oberen Ecke etc). Die einzelnen Basisklassen sind aber konzeptionell unabhängig voneinander - also mußt du in der abgeleiteten Klasse dafür sorgen, daß sie sich konsistent zueinander ändern.Stimmt. Und wo liegt das Problem?
Mal abgesehen davon, dass die Relation zwischen zwei Eigenschaften bei Vererbung und Komposition beschrieben werden muss - woher soll der Computer sie schließlich wissen.
Das ist hier ungefähr so wichtig, wie die Paprikaallergie Deiner Oma.Bei Komposition speicher ich nur die Grundeigenschaften des Objekts (z.B. reichen zwei Ecken aus, um die Lage des Fensters zu beschreiben) und berechne den Rest auf Verlangen - bei Vererbung hast du vier Punkte und mußt die dazugehörigen Zuweisungsoperatoren manuell anpassen. Zeig mir doch mal, wie du die Zuweisung "wnd = PointUpperLeft(47,11);" implementieren würdest.
Xin schrieb:
CStoll schrieb:
PS: Die Allergie hatte ich übrigens erwähnt, weil du mit den Allergiewarnungen angefangen hast - es gibt halt auch Menschen, die unter mehr leiden als einem (eher harmlosen) Heuschnupfen (btw, ich kenne auch jemanden mit einer Nussallergie). Und die sind dankbar, wenn sie rechtzeitig über (potentiell) gefährliche Nahrungsmittel informiert werden.
...
Wer als Nussallergiker Nüsse kauft, braucht den Hinweis nicht. Sollte er ihn doch brauchen, ist er vorrangig Intelligenzallergiker. Wann begreifst Du, dass die Aussage sich nicht auf die Allergie bezieht, sondern auf die Intelligenzleistung, die erforderlich ist, dass man als Nussallergiker nunmal keine Nüsse kauft, selbst wenn da keine Warnung auf der Packung steht...
Deine Oma kauft ja auch keine Paprika, wenn sie dagegen allergisch ist und Du wirst vermutlich niemals das Gras eines Fussballstadions pflegen, obwohl weder auf Paprika, noch auf dem Rasen Warnhinweise für Allergiker angebracht sind...Nein, du begreifst immer noch nicht, wozu diese Warnungen da sind - und daß sie nicht nur auf Produkten stehen, die "offensichtlich" Nüsse enthalten.
Ein Beispiel: In Weizenmüsli sind normalerweise keine Nüsse enthalten, also ist es für den Allergiker unbedenklich. Aber der selbe Hersteller produziert auch Müsliflocken mit Nuss - und wer sagt dem Allergiker jetzt, daß er nicht die selbe Abfüllanlage wahlweise für Nuss-Müsli und Weizenmüsli verwendet? (und selbst bei perfekter Hygiene ist nicht 100% auszuschließen, daß doch einige Nuss-Reste in die Weizenflocken geraten)
Xin schrieb:
Vielleicht kommt es in der x. Wiederholung bei Dir an: Ich zwinge Dich nicht, etwas zu nutzen. Ich zwinge Dir auch nicht ein Verständnis für Typsicherheit auf. Du kannst meinetwegen programmieren was und wie Du willst.
Alles, was ich hier angeboten habe, war eine Möglichkeit, typsicherer zu arbeiten. Diese Möglichkeit dient als Inspirationshilfe, die weiterhin verbesserungsfähig ist, was auch schon x mal geschrieben wurde.
Und ich habe keinen Bock auch nur eine weitere Seite in diesem Thread, Dich darauf aufmerksam zu machen.
Und darum habe ich auch kein Problem damit, dass Du Dich von mir inhaltlich ignoriert fühlst.Ja, du setzt Vererbung ein - und anschließend brauchst du Hilfskonstruktionen, um die damit verbundenen Schwachpunkte wieder auszugleichen. Und diese sehen schlimmer aus als alles, was ich ohne Vererbung entwickelt hätte. Der Grundansatz, Flags zur Sicherung der Typsicherheit in eine eigene Klasse zu packen, ist gut - aber warum du von dieser Klasse unbedingt erben mußt, konntest du bisher nicht vermitteln. (oder hast du diese Vererbungsbeziehung auch nur eingebaut, weil sie deinen Typerweiterungen am ähnlichsten sah?)
-
scrub schrieb:
Vielleicht kommt es bei der xten Wiederholung bei Dir an:
1. Auf Seite 7 kann ich Deine Zustimmung, Komposition sei in dem Fall besser als Vererbung, nicht finden. Also such sie gefälligst bitteschön und schreib endlich die richtige Seitenzahl hin! Ebenfalls ist es möglich, daß Du Dich wie üblich diffus ausgedrückt hast- dann zitier einfach Deine Zustimmung mal!
Fangen wir mal an auf Seite 3: Hier kann ich schonmal klar rauslesen, dass Komposition eine Möglichkeit von vielen ist und ich lese keine Wertung, dass es eine schlechte wäre.
Xin schrieb:
CStoll schrieb:
Da ist es mir lieber, genau zu wissen, wann ich denn nun auf die Flags zugreife (Sprich: Im Endeffekt kann ich mich mit der Flag-Klasse schon anfreunden, aber die Vererbungsbeziehung halte ich immer noch für sinnlos).
Damit kann ich gut leben. Hier stellst Du klar, dass es Dir nicht gefällt [...]. Es ist eine Möglichkeit und es gibt viele Möglichkeiten in C++ Daten zu verarbeiten.
Das es mir nich um "krampfhafte Überzeugungversuche" geht, findet sich auf Seite 4.
Xin schrieb:
Jede Perspektive hat Vor- und Nachteile. Nur weil wir in der strukturierten Programmierung Flags als Teil einer Struktur begreifen mussten, muss eine Struktur als Erweiterung von Flags keine Nachteile bringen.
Die Frage ist, wo holt man die meisten Vorteile heraus.oder Seite 5:
Xin schrieb:
Dir gefällt die Idee nicht, das ist okay.
Auf Seite 6 auch mal die Wertung zur Komposition:
Xin schrieb:
Es ist technisch gleichwertig zu w->Mode.
Und bevor sich hier CStoll mit seinen Verträgen anfängt, es bezieht sich auf die Memberbeziehung der Vererbung.
Weiter auf Seite 6 sieht man auch, dass ich mich kritisch mit meinen Sourcen auseinandersetze und nicht auf krampfhafte Überzeugungsarbeit aus bin:
Xin schrieb:
Ich habe übrigens ein Argument gegen die mehrfache Verwendung, das ihr noch nicht habt. -erklärung-
Kommen wir nun auf Seite 7:
Xin schrieb:
CStoll schrieb:
PS: Ich hab' nochmal über die Typerweiterungen nachgedacht - und in C++ sind die wohl besser mit Konvertierungsoperatoren darstellbar:
class WinFlag {...}; class Window { WinFlag f; public: operator WinFlag&() {return f;} ... };Dem stimme ich zu.
Falls es jemanden auffällt... Ich stimme ihm zu, dass er einen Konvertierungsoperator nimmt.
Wenn man die Bedeutung jetzt nicht sofort begreift, dann überlege man kurz, dass er auf einen Member konvertiert, weil er eine Komposition hat - bei Vererbung müsste er schließlich nicht konvertieren. Komposition in C++ besser geeignet als Vererbung. Das steht da.
Den Thread zu verfolgen hilft, denn die Bedeutung erschließt sich um so einfacher, wenn man davor gelesen hat, dass das Ganze aufgrund Mehrdeutigkeiten bei Mehrfachvererbung von Flags entstanden ist.CStoll ging darauf nicht weiter ein - wozu auch, denn es herschte Einigkeit.
Wenn Dir das zu diffus ist, meinetwegen. Darum habe ich auf den nachfolgenden Seiten auch immer mal wieder festgestellt, dass ich nicht gegen Komposition bin. Nur für den Fall.
Aber das geht ja auch unter.Zu dem "Also such sie gefälligst"... Denk Dir eine gefälligst eine entsprechend freundliche Antwort dazu, schließlich spielt es keine Rolle, was ich schreibe - ich begehe sowieso nur indirekte Selbstbeweihräucherung, dient Unregistrierten, um irgendwelche unqualifizierten Postings zu setzen oder wird direkt ignoriert.
In diesem Sinne...CStoll schrieb:
Xin schrieb:
Sorry, aber inhaltlich kam nicht mehr viel und Du spielst hier ein unsinniges Spiel mit mir: Antworten, um dagegen zu sein. Dass ich seit x Seiten Dir zustimme, dass die Komposition in C++ besser als die Ableitung ist, ignorierst Du und behauptest auch noch, dass ich krampfhaft versuche zu erklären, dass Vererbung besser wäre.
Wo soll ich denn einen Grund sehen, Dich da inhaltlich überhaupt zu beachten.Wenn du mir irgendwo zugestimmt hast, dann vermutlich in einem kleinen Nebensatz, der in den ganzen "Ableitung ist besser/schöner/leichter verständlich"-Beiträgen untergegangen ist.
Naja, "Dem stimme ich zu" ist kein Nebensatz und es wäre es für eine Argumentation natürlich durchaus sinnvoll sich anzusehen, wo ich zustimme und was das für Deine Argumentation bedeutet.
CStoll schrieb:
Xin schrieb:
CStoll schrieb:
WindowFlags vs. Window:
Die Klasse WindowFlags hat einen operator bool() (und auch wenn du das "s" noch so sehr betonst, ein einzelnes Flag ist auch von diesem Typ),Hier ignorierst Du erstens mehrfach genannte Möglichkeit das durch Trennung in zwei Klassen zu ändern... und die oben genannte Tatsache, dass ich die Komposition seit Seite iirc 7 als die bessere Möglichkeit ansehe...
Ja, diese Trennung hast du zwar erwähnt, aber im selben Satz wieder aufgehoben, indem du WindowFlags von WindowFlag ableiten wolltest. Und gegen eine saubere Trennung von "Flag" und "Flags" (bzw. Flaggable) habe ich auch nichts einzuwenden.
Wo habe ich sie wieder aufgehoben!?
CStoll schrieb:
Xin schrieb:
CStoll schrieb:
die Klasse Window als bool zu betrachten ist sinnlos (und wenn nicht, dann mit einer völlig anderen Semantik als für WindowFlags). Da ist es egal, ob du eine technische (op bool ist privat und der Compiler beschwert sich, wenn man es nutzen will) oder konzeptionelle (irgendwo in der Doku steht "benutze nie 'if(win)...'") Einschränkung hast - du hast eine Einschränkung.
(und im Ernstfall sind mir technische Einschränkungen lieber)Welche technische Einschränkung bietet Dir denn ein "int Flags", die "übliche" und bewerte "Technik".
Selbst, wenn ich ableite (Komposition in C++ besser, S. 7. blahblah), bin ich besser eingeschränkt, als mit einem popligen int, dass mangels Typ eigentlich alles darstellen kann.Nein, ich verwende keinen "int Flags" - und wenn doch, kommt der Nutzer da nicht ohne weiteres dran. Ich biete dem Nutzer eine typsichere (und alleine existierende) Flag-Klasse und Methoden zum Setzen, Rücksetzen und abfragen von Flags in meinen Klassen.
An meine Flags da muss auch keiner rankommen. Man kann aber, was mich nicht sonderlich stört, da ich so Window als Erweiterung von WindowFlags beschreibe und ich diese Perspektive als legitim ansehe.
Ich habe die einzelnen Flags als konstante Instanzen von WindowFlags beschrieben, weil ich keine Lust hatte, dafür eine zweite Klasse WindowFlag zu definieren. Das hindert aber niemanden, die Trennung sauberer zu vollziehen.
Da WindowFlags und Window eine Einheit bilden, stört mich das nicht.
Die klare Trennung von WindowFlags und WindowFlag sehen wir beide für die optimale Lösung.
Kömmen wir hier auf einen gemeinsamen Nenner?CStoll schrieb:
Xin schrieb:
Schließe Dein Scheunentor und dann reden wir weiter. Und um Dein Scheunentor zu schließen, wirst Du vermutlich wieder bei class WindowFlags landen.
Die Klasse WindowFlags hatte ich schon recht weit vorne akzeptiert, nur nicht die Tatsache, daß du Flags und Flag in ein und die selbe Klasse gepackt hast.
Jow, Deine Akzeptanz der WindowFlags Klasse habe ich schon mitbekommen.
Der Vorschlag die einzelnen Flags in eine Klasse WindowFlag zu packen, kam afair von mir, als Reaktion auf die Kritik, dass die Flags im Namensraum des Windows erscheinen.CStoll schrieb:
Xin schrieb:
Hier liegen die Prioritäten definitiv anders. Aber wer überhaupt Klassen nutzt, sollte sich nicht über Mehraufwand beschweren, denn früher wurde sowas alles auch problemlos mit Arrays gelöst. Für die Typsicherheit hat man sich dann doch für den Mehraufwand der Klassen entscheiden und sicherlich möchtest Du heute auch nicht mehr zu Byte-Arrays zurückkehren.
Du arbeitest aber nicht besonders typsicher, wenn alles ein int ist
Es ist nicht alles ein int, es ist alles int-verwandt.
int a; Meter m,n; Meter result; result = m + n; // geht, ergibt Meter a = result; // geht, ergibt Typlose Zahl result = a; // geht nicht, da nicht vom Typ Meter. result = Meter( a ); // geht, explizite TypvorgabeEdit: Ja, ich weiß, dass das auch über operator int() geht... es geht nicht darum, ob etwas möglich ist, sondern die Dinge aus verschiedenen Perspektiven zu betrachten.
CStoll schrieb:
Xin schrieb:
Ich sehe in der Verwandschaft mit "Zahl" nichts schlechtes.
int p = Quarktaschen( 3 ) + Zitronenkuchen( 2 ) + Kaesekuchen( 5 );
cout "Genug Futter für " << p << "Personen da." << endl;Verschiedene Kuchensorten sind sich vielleicht noch ähnlich genug, um so behandelt zu werden, aber was soll physikalisch herauskommen, wenn ich meine Körpergröße mit meinem Gewicht addiere?
Es kommt das gleiche raus, als würdest Du das mit ints machen. Eine typlose Zahl.
Nur weil Du damit nichts anfangen kannst, ist Körpergröße mit dem Gewicht zu addieren eine legitime Anfrage.
Ich sehe keinen Grund, die Beantwortung der Frage zu verweigern, nur weil ich grade nicht weiß, wozu das gut sein soll.CStoll schrieb:
Xin schrieb:
CStoll schrieb:
btw, op+ und op- zu überladen mag ja noch recht einfach sein, aber bei op* und op/ wird's dann haarig (die schlucken zwei beliebige Maßangaben und geben eine völlig andere Angabe wieder heraus) - davon, was bei op& und Co. rauskommen sollte, will ich gar nicht anfangen.
Damit solltest Du aber anfangen, weil es die Qualität Deiner Software erhöht.
5 Kilogramm * 20 Meter / 4Sekunde^2 ergibt nunmal nicht 25.Mit deinem Ansatz schon - und genau darauf wollte ich auch hinaus: Woher soll der Compiler wissen, was für ein Typ herauskommen soll, wenn du zwei wahllos herausgegriffene int-Derivate multiplizierst?
Jow, wenn der Compiler Newton nicht kennt, bekomme ich eine typlose 25 raus.
Anstatt mich darüber zu ärgern, dass ich das nicht kompilieren kann, habe ich wenigstens ein Ergebnis.
Wenn ich verschiedene Kuchensorten addiere, dann bekomme ich auch nur eine kuchentyplose Zahl raus und keine Personenanzahl. Ich kann aber mit der Zahl weiterarbeiten und ich kann die Zahl nicht einfach auf einen anderen Typ zuweisen.
Wenn die Formel nicht implementiert ist, kann ich
Newton n = KiloGramm( 5 ) * Meter( 20 ) / QuadratSekunde(4);
nicht zuweisen.Ich muss wissen, was ich tue, aber wenn ich das weiß, kann ich weiterarbeiten:
Newton n = Newton( KiloGramm( 5 ) * Meter( 20 ) / QuadratSekunde(4) );CStoll schrieb:
Xin schrieb:
CStoll schrieb:
(erzähl mir jetzt bitte nichts von Templates - ich kenne eine Template-Lösung dafür, aber die braucht keine Vererbung von int)
Ich erzähle hier nichts von Templates - ich habe keine, aber ich bin gespannt, Deine Templatelösung zu sehen, die mir die Verbindung von Newton zu den Grundeinheiten erstellt.
Nur grob skizziert und auch noch nicht vollständig:
template<int Meter,int Sekunde,int Kilogramm,...> class Measure {...}; typedef Measure<1,-2,1,...> Kraft;// 1 N == 1 m * s^-2 * kgNetter Ansatz.
CStoll schrieb:
Xin schrieb:
CStoll schrieb:
[*]Wertekombination durch Vererbung:
In den wenigstens Fällen sind die Attribute eines Objekts unabhängig voneinander (die Maximalgeschwindigkeit eines Autos hängt von der Motorleistung ab, die linke obere Ecke eines Fensters von der rechten oberen Ecke etc). Die einzelnen Basisklassen sind aber konzeptionell unabhängig voneinander - also mußt du in der abgeleiteten Klasse dafür sorgen, daß sie sich konsistent zueinander ändern.Stimmt. Und wo liegt das Problem?
Mal abgesehen davon, dass die Relation zwischen zwei Eigenschaften bei Vererbung und Komposition beschrieben werden muss - woher soll der Computer sie schließlich wissen.
Das ist hier ungefähr so wichtig, wie die Paprikaallergie Deiner Oma.Bei Komposition speicher ich nur die Grundeigenschaften des Objekts (z.B. reichen zwei Ecken aus, um die Lage des Fensters zu beschreiben) und berechne den Rest auf Verlangen - bei Vererbung hast du vier Punkte und mußt die dazugehörigen Zuweisungsoperatoren manuell anpassen. Zeig mir doch mal, wie du die Zuweisung "wnd = PointUpperLeft(47,11);" implementieren würdest.
Gar nicht, der Punkt oben Links wäre automatisch als Klasse ansprechbar und würde damit gesetzt.
PointUpperRight hingegen würde per Operator erledigt, da PointUpperLeft und PointLowerRight oder Area entsprechend überarbeitet werden müssen. Hier habe ich den gleichen Aufwand, wie Du.
Erbe ich all diese Punkte allerdings direkt von class Field, brauche ich mich um nichts mehr zu kümmern, sondern würde die ganze Funktionalität über using einbinden.CStoll schrieb:
Xin schrieb:
CStoll schrieb:
PS: Die Allergie hatte ich übrigens erwähnt, weil du mit den Allergiewarnungen angefangen hast - es gibt halt auch Menschen, die unter mehr leiden als einem (eher harmlosen) Heuschnupfen (btw, ich kenne auch jemanden mit einer Nussallergie). Und die sind dankbar, wenn sie rechtzeitig über (potentiell) gefährliche Nahrungsmittel informiert werden.
...
Wer als Nussallergiker Nüsse kauft, braucht den Hinweis nicht. Sollte er ihn doch brauchen, ist er vorrangig Intelligenzallergiker. Wann begreifst Du, dass die Aussage sich nicht auf die Allergie bezieht, sondern auf die Intelligenzleistung, die erforderlich ist, dass man als Nussallergiker nunmal keine Nüsse kauft, selbst wenn da keine Warnung auf der Packung steht...
Deine Oma kauft ja auch keine Paprika, wenn sie dagegen allergisch ist und Du wirst vermutlich niemals das Gras eines Fussballstadions pflegen, obwohl weder auf Paprika, noch auf dem Rasen Warnhinweise für Allergiker angebracht sind...Nein, du begreifst immer noch nicht, wozu diese Warnungen da sind - und daß sie nicht nur auf Produkten stehen, die "offensichtlich" Nüsse enthalten.
Ich stelle die Warnungen auf anderen Lebensmittel nicht in Frage.
Ich spreche ausschließlich Warnungen vor Nüssen auf Nusspackungen. Ist das so schwer zu begreifen?
Sind Nüsse in Nusspackungen wirklich so überraschend, dass man davor warnen muss?CStoll schrieb:
Der Grundansatz, Flags zur Sicherung der Typsicherheit in eine eigene Klasse zu packen, ist gut - aber warum du von dieser Klasse unbedingt erben mußt,
... Ich spreche die ganze Zeit von "Möglichkeit", von "Alternative", nicht vom "Muss" oder "Zwang".
Bitte höre auf, in meine Aussagen irgendwas reinzubasteln, was ich nicht sage.CStoll schrieb:
konntest du bisher nicht vermitteln. (oder hast du diese Vererbungsbeziehung auch nur eingebaut, weil sie deinen Typerweiterungen am ähnlichsten sah?)
... lohnt es sich überhaupt, darauf nochmals zu antworten?
Immerhin habe ich schon geschrieben, dass ich das aus Genesys übernommen habe und mir den einfachsten Weg ausgesucht habe, um das in C++ zu nutzen. Und fang jetzt bitte nicht an, mir etwas zu erzählen, dass man nicht einfach von einer Sprache auf die andere übertragen kann, ich habe diesen Thread gelesen und ich habe keinen Bock auf noch eine Wiederholung.
-
Xin schrieb:
CStoll schrieb:
Xin schrieb:
Ich sehe in der Verwandschaft mit "Zahl" nichts schlechtes.
int p = Quarktaschen( 3 ) + Zitronenkuchen( 2 ) + Kaesekuchen( 5 );
cout "Genug Futter für " << p << "Personen da." << endl;Verschiedene Kuchensorten sind sich vielleicht noch ähnlich genug, um so behandelt zu werden, aber was soll physikalisch herauskommen, wenn ich meine Körpergröße mit meinem Gewicht addiere?
Es kommt das gleiche raus, als würdest Du das mit ints machen. Eine typlose Zahl.
Nur weil Du damit nichts anfangen kannst, ist Körpergröße mit dem Gewicht zu addieren eine legitime Anfrage.
Ich sehe keinen Grund, die Beantwortung der Frage zu verweigern, nur weil ich grade nicht weiß, wozu das gut sein soll.Durch Beantwortung der Frage würde man den Mathematikern ins Gesicht schlagen

Anderst wird es noch deutlicher (und lustiger) ... 3 Bäume - 8 Häuser = ?
Es macht definitiv keinen Sinn solch eine Frage zu stellen!Darum geht es doch auch bei der Typsicherheit, man beschränkt Methoden/Operationen auf Typen mit denen sie auch Sinn ergeben kann.
Bzw. funktioniert die Methode/Operation auch nur mit Objekten des Typs, mit dem es Sinn ergibt. (Je nach Art der Typisierung)
-
Tellerrand schrieb:
Xin schrieb:
CStoll schrieb:
Xin schrieb:
Ich sehe in der Verwandschaft mit "Zahl" nichts schlechtes.
int p = Quarktaschen( 3 ) + Zitronenkuchen( 2 ) + Kaesekuchen( 5 );
cout "Genug Futter für " << p << "Personen da." << endl;Verschiedene Kuchensorten sind sich vielleicht noch ähnlich genug, um so behandelt zu werden, aber was soll physikalisch herauskommen, wenn ich meine Körpergröße mit meinem Gewicht addiere?
Es kommt das gleiche raus, als würdest Du das mit ints machen. Eine typlose Zahl.
Nur weil Du damit nichts anfangen kannst, ist Körpergröße mit dem Gewicht zu addieren eine legitime Anfrage.
Ich sehe keinen Grund, die Beantwortung der Frage zu verweigern, nur weil ich grade nicht weiß, wozu das gut sein soll.Durch Beantwortung der Frage würde man den Mathematikern ins Gesicht schlagen

Anderst wird es noch deutlicher (und lustiger) ... 3 Bäume - 8 Häuser = ?
Es macht definitiv keinen Sinn solch eine Frage zu stellen!Darum geht es doch auch bei der Typsicherheit, man beschränkt Methoden/Operationen auf Typen mit denen sie auch Sinn ergeben kann.
Bzw. funktioniert die Methode/Operation auch nur mit Objekten des Typs, mit dem es Sinn ergibt. (Je nach Art der Typisierung)Nur eine paar Zeilen weiter steht, warum es doch Sinn ergibt, wenn der Compiler grade die passende Formelsammlung nicht parat hat.
Abgesehen davon, werden sich die Mathematiker nicht geschlagen fühlen, immerhin müssen sie zur Zeit damit leben, dass alles nur typlose Integer (bzw. Floats) sind.
-
Wenn ich Code schreibe, möchte ich doch Details der Implementierung möglichst zentral halten und vor dem Aufrufer verbergen:
if (window & WindowFlags::UseFullscreen) // schlecht if (window.isFullscreen()) // besserDamit ist es für den Aufrufer egal, ob die Flags zu einer Basisklasse oder zur Fensterklasse gehören. Er weiss gar nicht, dass es Flags gibt, er sieht nur das Fenster. Ausserdem hat man einen zentralen Einstiegspunkt für Änderungen und Erweiterungen.
Möglicherweise möchte man später die Information "Fullscreen ja/nein" direkt vom Window-Manager abfragen; es kann sein, dass die Abfrage Multithreading-fähig sein muss usw.Es ist sicher alles auf vielerlei Arten möglich, aber es sollte doch so selbsterklärend, einfach und pragmatisch wie möglich bleiben. Das erspart auch Arbeit bei der Dokumentation.
Mein Lösungsansatz in Sachen Fenster sieht übrigens so aus:
Ich habe seit Jahren zwei Dateien; in der einen ist der Code zum Öffnen eines Win32-Fensters, in der anderen das ganze für X11. Es ist sperrig, es ist hässlich. Ich habe keine Sekunde daran verschwendet, dies in eine OOP-Struktur zu integrieren. Aber der Code ist ausgiebig getestet und x-mal von mir wiederverwendet worden, jedesmal per copy&paste binnen Sekunden. Wenn ihr mit einer Fensterklasse diese Wiederverwendungsrate erreichen wollt, müsst ihr noch verdammt oft vererben und komposi... äh... ihr wisst schon.
Ich sage ausdrücklich nicht, dass das gut oder nachahmenswert sei, aber es bildet doch ein gewisses Argument in der Debatte um Wiederverwendbarkeit und Strukturierung von Code.
-
Xin schrieb:
Anstatt mich darüber zu ärgern, dass ich das nicht kompilieren kann, habe ich wenigstens ein Ergebnis.
Das ist also die viel gelobte Qualität deiner Software?
Vielleicht ist es besser nicht ganz so schöne Syntax zu haben sondern lieber etwas mehr Sicherheit im Code zu haben

-
Xin schrieb:
Nur eine paar Zeilen weiter steht, warum es doch Sinn ergibt, wenn der Compiler grade die passende Formelsammlung nicht parat hat.
Man gestattet also unsinnige Operationen weil?
Xin schrieb:
Abgesehen davon, werden sich die Mathematiker nicht geschlagen fühlen, immerhin müssen sie zur Zeit damit leben, dass alles nur typlose Integer (bzw. Floats) sind.
Der Mathematiker wundert sich über Integer / Float nicht, denn die verschiedenen Zahlensysteme sind bis auf einige Ausnahmen, wie die rationalen, komplexen, ..., gut umgesetzt. (Lisp wäre gründlicher aber es reicht auch so)
Nur wenn man schon eine Maßeinheit einführt, dann sollte man diese auch in Berechnungen beachten.
Der Mathematiker wird sich wundern, wenn aus Meter plus Gramm eine natürliche Zahl entsteht.
(Hmmm, eigentlich sind es eher die Physiker)Aber was nutzt eine Klasse Meter, wenn ich Werte daraus mit Gewicht addieren kann und das Resultat ein Integer ist?
Wozu dann die extra Klasse überhaupt?
-
2am schrieb:
Wenn ich Code schreibe, möchte ich doch Details der Implementierung möglichst zentral halten und vor dem Aufrufer verbergen:
if (window & WindowFlags::UseFullscreen) // schlecht if (window.isFullscreen()) // besserVom Prinzip her habe ich da kein Problem mit, es lässt sich auch problemlos in eine Klasse WindowFlags einbrinen.
Was mir hier fehlt sind zusammenhängende Abfragen:if( window & ( WindowFlags::UseFullScreen | WindowFlags::HasFocus ) )
Ich schätze auch die 5 Takte, die man hier spart, insbesondere bei Flags, die in stark zu optimierenden Algorithmen auftauchen. Das fehlt mir beim Aufruf von Funktionen (selbst, wenn sie inline kompiliert werden).
Ich entwickle grundsätzlich optimierungskritisch, d.h. eine (inline-)Funktion wie isFullscreen wird bei mir nur dann benutzt, wenn ich auch wirklich ausschließlich das eine Flag abfragen möchte.2am schrieb:
Mein Lösungsansatz in Sachen Fenster sieht übrigens so aus:
Ich habe seit Jahren zwei Dateien; in der einen ist der Code zum Öffnen eines Win32-Fensters, in der anderen das ganze für X11. Es ist sperrig, es ist hässlich. Ich habe keine Sekunde daran verschwendet, dies in eine OOP-Struktur zu integrieren. Aber der Code ist ausgiebig getestet und x-mal von mir wiederverwendet worden, jedesmal per copy&paste binnen Sekunden. Wenn ihr mit einer Fensterklasse diese Wiederverwendungsrate erreichen wollt, müsst ihr noch verdammt oft vererben und komposi... äh... ihr wisst schon.
So habe ich früher auch mal gearbeitet. Inzwischen lagere ich alle interessanten Klassen und Algorithmen in ein Framework aus und alle Programme nutzen das identische Framework. Weiterentwicklungen werden über SVN wieder zusammengeführt.
Shade Of Mine schrieb:
Xin schrieb:
Anstatt mich darüber zu ärgern, dass ich das nicht kompilieren kann, habe ich wenigstens ein Ergebnis.
Das ist also die viel gelobte Qualität deiner Software?
Eleganz vor Frikelei. Machbarkeit vor Eleganz.
Shade Of Mine schrieb:
Vielleicht ist es besser nicht ganz so schöne Syntax zu haben sondern lieber etwas mehr Sicherheit im Code zu haben

Mit Einheiten zu rechnen bietet a) mehr Sicherheit und b) sorgt für kompaktere und leichter lesbare Parameterlisten. Wenn dies nicht möglich ist, mache ich das selbe wie jeder andere.
Kommt man von höherer Typsicherheit also wieder auf das Normalmaß herunter, hat man keinen Verlust.Tellerrand schrieb:
Xin schrieb:
Nur eine paar Zeilen weiter steht, warum es doch Sinn ergibt, wenn der Compiler grade die passende Formelsammlung nicht parat hat.
Man gestattet also unsinnige Operationen weil?
Man nicht garantieren kann, dass sie unsinnig sind und zumindest ich möchte keine Möglichkeiten einschränke, die ich nicht verstehe.
Was ist Gewicht * Strecke? Was ist Zeit im Quadrat?
Gewicht * Strecke / Zeit / Zeit ist jedenfalls Kraft.Was ich verstehe ist, dass ich nicht ungefragt irgendwas auf einen festgelegten Typ zuweisen kann.
Wenn ich also 4 Kühlschränke mit 3 Broten addiere, dann erhalte ich 7 Objekte. Objekte kann man zählen. Warum sollte ich das verbieten?Tellerrand schrieb:
Xin schrieb:
Abgesehen davon, werden sich die Mathematiker nicht geschlagen fühlen, immerhin müssen sie zur Zeit damit leben, dass alles nur typlose Integer (bzw. Floats) sind.
Der Mathematiker wundert sich über Integer / Float nicht, denn die verschiedenen Zahlensysteme sind bis auf einige Ausnahmen, wie die rationalen, komplexen, ..., gut umgesetzt. (Lisp wäre gründlicher aber es reicht auch so)
Nur wenn man schon eine Maßeinheit einführt, dann sollte man diese auch in Berechnungen beachten.Bin ich absolut dafür. Aber wenn man Maßeinheiten einführt und eine Rechnung nicht vom Compiler nicht verstanden wird, weil der Entwickler etwas neues macht, dann ist es nicht Aufgabe der Sprache ihm das grundsätzlich zu verbieten.
Am Rande, in meiner kleinen Umfrage zum Thema Programmiersprachen, äußerten sich auch Mathematiker über die fehlenden Ausdrucksmöglichkeiten durch Programmiersprachen.
Von daher bin ich vorsichtig, wenn Menschen aus dem Informatik-Umfeld darüber spekulieren, dass Mathematiker, Physiker usw. die Ideen der Informatiker so toll finden. Auch hier schadet ein gelegentlicher Perspektivenwechsel nicht.Tellerrand schrieb:
Aber was nutzt eine Klasse Meter, wenn ich Werte daraus mit Gewicht addieren kann und das Resultat ein Integer ist?
Wozu dann die extra Klasse überhaupt?Wozu? Damit Du weißt, dass ein Meter plus ein Meter wieder ein Meter ergibt. Oder ein Meter * Meter einen Quadratmeter. Das ist ein Mehrwert und ein Mehrwert rechtfertigt eine Klasse.
Da wo Du es nicht weißt, hast Du nicht mehr als zuvor - aber eben auch nicht weniger.
Woher soll ich wissen, wem Meter + Gewicht hilft? Ich kann garantieren, dass ein class Meter + ein class Meter wieder ein class Meter ergibt. Wie soll ich garantieren, dass Meter + Gewicht grundsätzlich sinnlos ist? Wenn ich das nicht garantieren kann, wie soll ich dann eine Einschränkung begründen?
Vor dem BMI gab es diese "Formel" für richtiges Gewicht: Gewicht = Groesee - 100
Mathematisch bedeutet das auch Groesse = Gewicht + 100cm
Wenn jemand das rechnen will, warum sollte ich ihm das verbieten?
Soll er doch rechnen. Was die Sprache nicht darf, ist ein solches Ergebnis kritiklos einem Typ wie Meter zuweisen.
Bei Gewicht + 100cm kommt beispielsweise typlose 175 raus. Wenn ich das einer Größe zuordnen will, dann muss ich das bestätigen: Groesse = Zentimeter( Gewicht + 100 );Ich muss verstehen, was meine Einschränkung bedeutet und dafür garantieren, dass sie nützlich ist. Verbaue ich einem Entwickler etwas, so dass dieser auf Workarounds o.ä. umsteigen muss, habe ich aus Unverständnis einen Fehler begangen.
Ich sehe mich nicht in der Lage alle mathematischen und physikalischen Formen, die existieren und in Zukunftexistieren werden, in meinen Klassen abzubilden. Deswegen darf ich aber nicht die Kreativität der Entwickler enschränken.Tellerrand schrieb:
Anderst wird es noch deutlicher (und lustiger) ... 3 Bäume - 8 Häuser = ?
Es macht definitiv keinen Sinn solch eine Frage zu stellen!Bei der Rechnung würden hier typlose -5 Objekte herauskommen. Und? Das stimmt doch.
3 Personen sind im Fahrstuhl, 8 steigen aus, wieviele müssen einsteigen, damit der Fahrstuhl leer ist?
Nur weil die Frage in der Realität keinen Sinn ergibt, lässt sich das mathematisch problemlos ausrechnen.
Mathematisch lassen sich aus negativen Zahlen Wurzeln ziehen, aber nur weil ich das beim Kauf eines Grundstücks die Kantenlänge einer negativen Baufläche in der Regel nicht verstehe, muss das mathematisch nicht sinnlos sein.Ich bin da eher vorsichtig, wenn ich nicht sicher bin, ob nicht doch jemand für derartiges eine sinnvolle Anwendung findet.
Ich kann verstehen, dass ich auf eine Variable für Äpfel nicht ungefragt Birnen zuweisen kann. Trotzdem muss ich es erlauben, wenn der Entwickler das so für richtig hält. Mein Job ist es hierbei eine Hilfe zu bieten, kein Verbot.
Birne b = Birne( 3 ); Apfel a = Apfel( b );
-
Ohne jetzt die vollen 13 Seiten gelesen zu haben:
Ich kann verstehen, dass ich auf eine Variable für Äpfel nicht ungefragt Birnen zuweisen kann. Trotzdem muss ich es erlauben, wenn der Entwickler das so für richtig hält. Mein Job ist es hierbei eine Hilfe zu bieten, kein Verbot.
Birne b = Birne( 3 ); Apfel a = Apfel( b );Würde das nicht bedeuten, das Apfel für alle Typen eine Konvertierung anbieten muss ? Wenn nicht, verbietet die Sprache die Konvertierung von T nach Apfel.
Wie schaut denn nun die Hilfe aus um T in einen Apfel zu konvertieren ?
-
Xin schrieb:
(...)
if( window & ( WindowFlags::UseFullScreen | WindowFlags::HasFocus ) )Ich schätze auch die 5 Takte, die man hier spart, insbesondere bei Flags, die in stark zu optimierenden Algorithmen auftauchen. Das fehlt mir beim Aufruf von Funktionen (selbst, wenn sie inline kompiliert werden).
Ich entwickle grundsätzlich optimierungskritisch, d.h. eine (inline-)Funktion wie isFullscreen wird bei mir nur dann benutzt, wenn ich auch wirklich ausschließlich das eine Flag abfragen möchte.Vor jeder Optimierung sollte eine Prüfung der Notwendigkeit und der Machbarkeit stehen. In C++ zu programmieren, und dabei in Takten zu denken ist ziemlich sinnlos. Du weisst ja nicht, was der Compiler daraus macht und noch viel weniger, was am besten für aktuelle hochoptimierende Multikern-Prozessoren ist.
(Selbst wenn meine Unterstellung falsch ist, weisst du sicher nicht, was die nächste Compilergeneration aus deinem Code macht und wie der auf der nächsten Prozessorgeneration läuft.)Darüberhinaus wird eine Prüfung der speziellen Form (WindowFlags::Dieses | WindowFlags::Jenes) eher nicht innerhalb kritischer Schleifen auftauchen, ist es doch "loop invariant code".
-
Knuddlbaer schrieb:
Ohne jetzt die vollen 13 Seiten gelesen zu haben: [...]
Würde das nicht bedeuten, das Apfel für alle Typen eine Konvertierung anbieten muss ? Wenn nicht, verbietet die Sprache die Konvertierung von T nach Apfel.Wie schaut denn nun die Hilfe aus um T in einen Apfel zu konvertieren ?
Es lohnt deswegen nicht, die letzten 13 Seiten nachzulesen, aber die Antwort ist nein.
In dem Fall handelt es sich um eine Ableitung von int, wobei die Klassen einen expliziten Konstruktor für int besitzen. (Ja, es ist bekannt, dass das kein C++ ist...)
Ansonsten nehme man operator int().2am schrieb:
Xin schrieb:
(...)
if( window & ( WindowFlags::UseFullScreen | WindowFlags::HasFocus ) )Ich schätze auch die 5 Takte, die man hier spart, insbesondere bei Flags, die in stark zu optimierenden Algorithmen auftauchen. Das fehlt mir beim Aufruf von Funktionen (selbst, wenn sie inline kompiliert werden).
Ich entwickle grundsätzlich optimierungskritisch, d.h. eine (inline-)Funktion wie isFullscreen wird bei mir nur dann benutzt, wenn ich auch wirklich ausschließlich das eine Flag abfragen möchte.Vor jeder Optimierung sollte eine Prüfung der Notwendigkeit und der Machbarkeit stehen.
Man kann sich auch angewöhnen, manche Dinge grundsätzlich in optimaler Form zu schreiben.
Insbesondere dann, wenn die optimale Form schneller zu schreiben ist, als über die Möglichkeit einer Prüfung nachzudenken.2am schrieb:
In C++ zu programmieren, und dabei in Takten zu denken ist ziemlich sinnlos. Du weisst ja nicht, was der Compiler daraus macht und noch viel weniger, was am besten für aktuelle hochoptimierende Multikern-Prozessoren ist.
Ich weiß, was ein zustandsbasiertes System daraus machen kann.
In dem Fall spielt es keine Rolle, ob hier eine 386er CPU oder ein Quadcore-Cluster auf die Anweisung stößt.
Was ich weiß ist, dass ein Compiler viel optimieren kann und diese Details schlecht erkennen kann. Also wozu ihm die Arbeit nicht ersparen und mir garantieren, dass die Optimierung stattfindet?2am schrieb:
(Selbst wenn meine Unterstellung falsch ist, weisst du sicher nicht, was die nächste Compilergeneration aus deinem Code macht und wie der auf der nächsten Prozessorgeneration läuft.)
Solange sich die grundlegende Idee eines Computers nicht ändert, ändert sich grade an dieser Anweisung definitiv nichts mehr. Es ist eine der grundlegendsten Anweisungen, die man überhaupt machen kann.
Entsprechend ist die Anweisung von einem 386er genauso schnell (in Takten) verarbeitet, wie von einem Quadcore-Cluster. Schneller als 1 Takt geht auf getakteten Systemen nicht.2am schrieb:
Darüberhinaus wird eine Prüfung der speziellen Form (WindowFlags::Dieses | WindowFlags::Jenes) eher nicht innerhalb kritischer Schleifen auftauchen, ist es doch "loop invariant code".
Loop invariant?
Wenn hier ein Compiler was brauchbar optimiert, ist bleibt hier keine Variable sondern nur eine Konstante über. Konstanten sind allgemein äußerst invariant und ihr Wert ist im Vergleich zu zwei Funktionsaufrufen auch sehr schnell auszurechnen.
Und das soll eine Optimierung ja erreichen, möglichst wenig Arbeit, um schnell zu Ergebnissen zu kommen.
while( window.isDieses() && window.isJenes() ) lässt sich nunmal nicht auslagern und der Compiler muss verdammt klever sein, wenn er die zwei Funktionsaufrufe zu einem while( window.flags & (dieses|jenes) ) umwandeln kann.
-
Xin schrieb:
Eleganz vor Frikelei. Machbarkeit vor Eleganz.
Bei mir geht es so rum:
Stabilität über allem.Vorallem da Eleganz sehr subjektiv ist.
Mit Einheiten zu rechnen bietet a) mehr Sicherheit und b) sorgt für kompaktere und leichter lesbare Parameterlisten. Wenn dies nicht möglich ist, mache ich das selbe wie jeder andere.
Kommt man von höherer Typsicherheit also wieder auf das Normalmaß herunter, hat man keinen Verlust.Ich sehe da absolut keine Sicherheit wenn ich Kilogramm + Meter addieren kann. Und du hast es selber gesagt, dass da quark rauskommt aber es kompiliert wird.
Man nicht garantieren kann, dass sie unsinnig sind und zumindest ich möchte keine Möglichkeiten einschränke, die ich nicht verstehe.
Es ist deine Klasse in deiner Domain und du kannst nicht die Operationen der Klasse definieren? Das ist fragwürdig.
Soll ich deshalb immer einen Template Konvertierungsoperator anbieten der halt rand() returned damit jedeweder Code kompiliert?
C++ bietet hier typsicherheit an um eine Menge an Fehlern vorzubeugen. Das beste Beispiel ist wohl dieser Thread hier. Wieviele Probleme wurden bei der Vererbung von WinFlags -> Win aufgezählt und an wieviele hast du davor gedacht?
Das alles sind potentielle Fehler in der Software - und für was? Was ist der große Vorteil davon dass man die Typsicherheit über Board wirft? Eine einfachere Syntax.
Was ist Gewicht * Strecke? Was ist Zeit im Quadrat?
Gewicht * Strecke / Zeit / Zeit ist jedenfalls Kraft.Und was spricht dagegen dafür explizit etwas zu definieren? Ich kann jederzeit operatoren definieren damit Gewicht*Strecke/Zeit ein Objekt der Klasse Kraft liefert. Das Problem ist, wenn du daraus reine integers machst, verlierst du die komplette Typsicherheit und du kannst dir die Klassen sparen - rechne gleich mit integern - ist deutlich simpler und weniger aufwendig.
Kommen wir auf die einfachere Syntax zurück:
Ich kann jederzeit ein Kraft Objekt erstellen indem ich:Kraft k(g.asInt() * s.asInt() / z.asInt());schreibe.
Das ist syntaktisch nicht schön, aber man erkennt sofort dass hier etwas außergewöhnliches passiert. Natürlich nur wenn ich hier nicht die Operatoren passend überladen will (passend im Sinne von, dass kein Gewicht * Zeit ein Kraft Objekt liefert).
Dadurch erreiche ich eine Typsicherheit ohne einbussen der Funktionalität auf kosten einer (unter Umständen) komplizierteren Syntax. Denn um mehr geht es nicht - es geht nach wie vor nur um Syntax. Und ich denke nicht dass Syntax es wert ist dafür potentielle Fehler einzubauen. Allein der 1. Ansatz deiner WinFlags war voller Fehler. Keiner dieser Fehler wäre bei Komposition aufgetreten. Und technisch wären beide gleichwertig - lediglich Sicherheit <-> Syntax.
@Knuddlbaer:
Apfel muss nur eine Konvertierung für den Basistypen von Birne anbieten:struct Flags { }; struct Win : public Flags { Win(Flags f=Flags()) {} }; struct Socket : public Flags { Socket(Flags f=Flags()) {} }; int main() { Win w; Socket s(w); }Das Problem dabei ist halt: Win und Socket haben nichts gemeinsam. Sie haben lediglich ein gleiches Property. Wenn wir nun aber von dem Property public erben - passieren viele solcher Sachen. Es hat einen Grund warum es den Leitsatz gibt: Make sure inheritance models an is-a relationship.
-
@Side naja, das verständnisproblem kam daher, das ich diesem Thread nicht gefolgt bin. Ich hab daher die Aussage
Ich kann verstehen, dass ich auf eine Variable für Äpfel nicht ungefragt Birnen zuweisen kann. Trotzdem muss ich es erlauben, wenn der Entwickler das so für richtig hält. Mein Job ist es hierbei eine Hilfe zu bieten, kein Verbot.
Code:
Birne b = Birne( 3 );
Apfel a = Apfel( b );Allgemeiner gesehen als
T t = T(U);Man hat ja auch Häuser von Bäumen abgezogen und Butterbrote addiert =o) Ich schmöcker mal, scheint doch viel interesanntes in den langen Threads zu stecken.
-
Shade Of Mine schrieb:
Xin schrieb:
Eleganz vor Frikelei. Machbarkeit vor Eleganz.
Bei mir geht es so rum:
Stabilität über allem.Vorallem da Eleganz sehr subjektiv ist.
Stabilität sowieso. Bzgl. Eleganz gibt es durchaus einige Dinge, die man beachten kann und die haben häufig nichts mit festgelegten Regeln von Einrücken zu tun.
Da die Sache natürlich subjektiv bleibt, ist jede öffentliche Äußerung in die Richtung zur Kritik verdammt und grade hier spare ich mir das lieber.
Shade Of Mine schrieb:
Mit Einheiten zu rechnen bietet a) mehr Sicherheit und b) sorgt für kompaktere und leichter lesbare Parameterlisten. Wenn dies nicht möglich ist, mache ich das selbe wie jeder andere.
Kommt man von höherer Typsicherheit also wieder auf das Normalmaß herunter, hat man keinen Verlust.Ich sehe da absolut keine Sicherheit wenn ich Kilogramm + Meter addieren kann. Und du hast es selber gesagt, dass da quark rauskommt aber es kompiliert wird.
Hier wird wieder frei interpretiert. Ich sagte nicht "Quark". Ich sagte typlos. Das bedeutet, dass der Typ nicht aussagt, was man damit anfangen kann. Wenn der Compiler nicht weiß, was man damit anfangen kann, heißt das nicht, dass der Entwickler mit der Information damit nichts anfangen kann.
Shade Of Mine schrieb:
Man nicht garantieren kann, dass sie unsinnig sind und zumindest ich möchte keine Möglichkeiten einschränke, die ich nicht verstehe.
Es ist deine Klasse in deiner Domain und du kannst nicht die Operationen der Klasse definieren? Das ist fragwürdig.
Sorry, aber das hier steht in keinem Zusammenhang zu meinen Klassen, was Dir bewußt sein dürfte, da in C++ nicht von int geerbt werden kann.
Operatoren zu den Klassen kann ich problemlos aufzählen und dazu gehören nunmal auch die geerbten, da ich sie nicht verbieten würde, also die Möglichkeiten nicht einschränke.
Shade Of Mine schrieb:
Soll ich deshalb immer einen Template Konvertierungsoperator anbieten der halt rand() returned damit jedeweder Code kompiliert?
Soll ich auf Dein Posting antworten oder möchtest Du nur ein wenig herumsticheln, dann kann ich mir das auch schenken.
Shade Of Mine schrieb:
C++ bietet hier typsicherheit an um eine Menge an Fehlern vorzubeugen. Das beste Beispiel ist wohl dieser Thread hier. Wieviele Probleme wurden bei der Vererbung von WinFlags -> Win aufgezählt und an wieviele hast du davor gedacht?
Erstens sehe ich bei der Vererbung weiterhin kein zu großes Problem. if( win ) ist eine Definition, die sich aus der Vererbung ergibt, die CStoll und Dir nicht gefallen. Mir gefällt es auch nicht sonderlich, aber ein Problem habe ich damit nicht.
Shade Of Mine schrieb:
Das alles sind potentielle Fehler in der Software - und für was? Was ist der große Vorteil davon dass man die Typsicherheit über Board wirft? Eine einfachere Syntax.
Das hat grade nichts mit klassifizierten Einheiten zu tun...?
Shade Of Mine schrieb:
Was ist Gewicht * Strecke? Was ist Zeit im Quadrat?
Gewicht * Strecke / Zeit / Zeit ist jedenfalls Kraft.Und was spricht dagegen dafür explizit etwas zu definieren?
Nichts und ich habe auch nicht behauptet, dass etwas dagegen sprechen würde.
Trotzdem kann es sein, dass man diese Typen aus einer Lib nimmt und erstmal feststellt, dass eine Konvertierung nicht dabei ist.
Shade Of Mine schrieb:
Ich kann jederzeit operatoren definieren damit Gewicht*Strecke/Zeit ein Objekt der Klasse Kraft liefert. Das Problem ist, wenn du daraus reine integers machst, verlierst du die komplette Typsicherheit und du kannst dir die Klassen sparen - rechne gleich mit integern - ist deutlich simpler und weniger aufwendig.
Ich verliere die Typsicherheit nicht. Ein Typ ist nur dann gegeben, wenn es sicher ist, ihn zu benennen. Ansonsten darf gerechnet werden, aber der Entwickler bekommt eine typlose Information.
Er kann nun entweder etwas passendes definieren, oder muss die Verantwortung dafür übernehmen, eine typlose Information zu klassifizieren.
Shade Of Mine schrieb:
Kommen wir auf die einfachere Syntax zurück:
Ich kann jederzeit ein Kraft Objekt erstellen indem ich:Kraft k(g.asInt() * s.asInt() / z.asInt());schreibe.
Richtig, kannst Du. Das ist eine andere Möglichkeit. Es spricht nichts dagegen - aber in meinen Augen auch nichts dafür im Vergleich zu einer (theoretisch möglichen) Ableitung.
Shade Of Mine schrieb:
Dadurch erreiche ich eine Typsicherheit ohne einbussen der Funktionalität auf kosten einer (unter Umständen) komplizierteren Syntax.
Falsch. Du erreichst nicht mehr Typsicherheit, der einzige Unterschied ist, dass Du bei jeder Variable "asInt()" dahinter schreiben musst. Du erhältst also wieder ein typloses int.
In meinem Fall wird - sofern nicht typsicher gerechnet werden kann - mit ints gerechnet und Du erhältst ebenfalls ein typloses int.
In beiden Fällen kannst Du das typlose int nicht zuweisen. Du gewinnst also mit asInt keinen Vorteil.Shade Of Mine schrieb:
Denn um mehr geht es nicht - es geht nach wie vor nur um Syntax. Und ich denke nicht dass Syntax es wert ist dafür potentielle Fehler einzubauen. Allein der 1. Ansatz deiner WinFlags war voller Fehler. Keiner dieser Fehler wäre bei Komposition aufgetreten. Und technisch wären beide gleichwertig - lediglich Sicherheit <-> Syntax.
Ich weiß nicht, von welchen Fehlern Du sprichst. Was ich beschrieb, funktioniert problemlos und korrekt - auch unter Mehrfachvererbung, sobald Du die Operatoren in den Namensraum der Klasse holst.
Shade Of Mine schrieb:
@Knuddlbaer:
Apfel muss nur eine Konvertierung für den Basistypen von Birne anbieten:struct Flags { }; struct Win : public Flags { Win(Flags f=Flags()) {} }; struct Socket : public Flags { Socket(Flags f=Flags()) {} }; int main() { Win w; Socket s(w); }Das Problem dabei ist halt: Win und Socket haben nichts gemeinsam. Sie haben lediglich ein gleiches Property. Wenn wir nun aber von dem Property public erben - passieren viele solcher Sachen. Es hat einen Grund warum es den Leitsatz gibt: Make sure inheritance models an is-a relationship.
struct Flags { }; struct Win { Flags f; Win(Flags f=Flags()) {} }; struct Socket { Flags f; Socket(Flags f=Flags()) {} }; int main() { Win w; Socket s(w.f); }Das rettet die Welt?
Wie wir sehen, haben win und socket hier etwas gemeinsames, nämlich die gleichen Flags. Und wenn das passt, dann passt das - und wenn nicht, dann fragt Socket die falschen Flags ab.
Das ist kein Vererbungs oder Kompositionsproblem, das wäre ein Designfehler - egal als ob Vererbung oder Komposition.
-
Xin schrieb:
struct Flags { }; struct Win { Flags f; Win(Flags f=Flags()) {} }; struct Socket { Flags f; Socket(Flags f=Flags()) {} }; int main() { Win w; Socket s(w.f); }Das rettet die Welt?
Es ist auf jedenfall schon mal klarer. Wenn wir nämlich nicht von Win und Socket ausgehen, sondern von etwas näher verwandten Sachen wie Win und Dialog wobei Dialog keinen CCtor für Win bietet. Da hat man so leicht mehrdeutigkeiten für den Programmierer.
Aber das lustige ist: du verteidigst immer noch nur die Nachteile - aber Vorteile nennst du immer noch keine.
Ansonsten darf gerechnet werden, aber der Entwickler bekommt eine typlose Information.
Problem ist aber:
Kraft k = gewicht * hoehe;Das wird ziemlich sicher klappen, da du eine Konvertierung von int zu Kraft haben willst - richtig?
Aber genau das ist das Problem - convenience ist nicht immer das beste. Wenn man einfach gewicht*hoehe verbietet, gibt es da keine Probleme. Und wenn ich in die seltene Situation komme wo ich das brauche, gibt es immer noch ein
Kraft k = gewicht.asInt() * hoehe.asInt();Hier sieht man dann sofort dass etwas "Typenloses" raus kommt und vom Programmierer erst interpretiert werden muss. Während das bei "gewicht * hoehe" nicht der Fall ist - es ist eine definierte Operation also erwarte ich ein vernünftiges Ergebnis.
Klar ist es schlecht diese Operation zu verbieten - aber es gibt eben Abstufungen zwischen "operation direkt implementiert im interface" und "operation möglich". Ich denke dass man gewicht mit hoehe nicht multiplizieren können muss. Dass es nicht teil des interfaces von Höhe ist diese Operation zu implementieren. Es sollte aber möglich sein wenn ich es unbedingt will.
Das führt zu sicheren Programmen da man einfach Fehler wie gewicht*hoehe wo man breite*hoehe meinte einfach zur Compilezeit eliminiert.
-
Xin schrieb:
if (window & WindowFlags::UseFullscreen) // schlecht if (window.isFullscreen()) // besserVom Prinzip her habe ich da kein Problem mit, es lässt sich auch problemlos in eine Klasse WindowFlags einbrinen.
Was mir hier fehlt sind zusammenhängende Abfragen:if( window & ( WindowFlags::UseFullScreen | WindowFlags::HasFocus ) )
[/quote]Und da sind wir wieder bei der semantischen Frage: Was bedeutet diese Abfrage? "Das Fenster hat beide Flags"? Oder doch "Das Fenster hat mindestens eins der Flags"? (Mit der für int üblichen Bedeutung, die du bisher als Rechengrundlage genommen hast, ist es letzteres)Xin schrieb:
Shade Of Mine schrieb:
Xin schrieb:
Anstatt mich darüber zu ärgern, dass ich das nicht kompilieren kann, habe ich wenigstens ein Ergebnis.
Das ist also die viel gelobte Qualität deiner Software?
Eleganz vor Frikelei. Machbarkeit vor Eleganz.
Und wo steht in deiner Prioritätenliste die Typsicherheit? Soweit ich das überblicke, sehr weit unten.
Xin schrieb:
Shade Of Mine schrieb:
Vielleicht ist es besser nicht ganz so schöne Syntax zu haben sondern lieber etwas mehr Sicherheit im Code zu haben

Mit Einheiten zu rechnen bietet a) mehr Sicherheit und b) sorgt für kompaktere und leichter lesbare Parameterlisten. Wenn dies nicht möglich ist, mache ich das selbe wie jeder andere.
Kommt man von höherer Typsicherheit also wieder auf das Normalmaß herunter, hat man keinen Verlust.Ja, solange man mit Einheiten rechnet und nicht nur mit aufbereiteten int's - indem du alle Einheiten von int ableitest, pulverisierst du dir deine heißgeliebte Typsicherheit wieder (Beispiel: Du hast eine Einheit Kraft und Weg - das Produkt davon wäre eigentlich eine Leistung, aber nun bekommst du plötzlich eine reine Zahl heraus, weil Leistung nicht in deiner Einheitensammlung erwähnt wird).
btw, außerdem brauchst du praktisch unendlich viele Einheitenkombinationen, um alle möglichen Multiplikationen darstellen zu können - mit der bereits angerissenen Template-Klasse Measure<...> hast du die alle auf einen Haufen.
Xin schrieb:
Tellerrand schrieb:
Xin schrieb:
Nur eine paar Zeilen weiter steht, warum es doch Sinn ergibt, wenn der Compiler grade die passende Formelsammlung nicht parat hat.
Man gestattet also unsinnige Operationen weil?
Man nicht garantieren kann, dass sie unsinnig sind und zumindest ich möchte keine Möglichkeiten einschränke, die ich nicht verstehe.
Was ist Gewicht * Strecke? Was ist Zeit im Quadrat?
Gewicht * Strecke / Zeit / Zeit ist jedenfalls Kraft.Gewicht*Strecke ist ein Wert, den man in kg*m angibt, Zeit im Quadrat hat die Einheit Quadratsekunden - was die physikalisch darstellen, ist erstmal bedeutungslos. Ich kann diese Zwischenwerte bei Bedarf als Measure<1,0,1,...> bzw. Measure<0,2,0,...> behandeln und miteinander verrechnen, ohne mich um ihre physikalische Bedeutung zu kümmern - der Quotient aus beidem ist ein Measure<1,-2,1,...>, also eine Kraft.
Xin schrieb:
Tellerrand schrieb:
Xin schrieb:
Abgesehen davon, werden sich die Mathematiker nicht geschlagen fühlen, immerhin müssen sie zur Zeit damit leben, dass alles nur typlose Integer (bzw. Floats) sind.
Der Mathematiker wundert sich über Integer / Float nicht, denn die verschiedenen Zahlensysteme sind bis auf einige Ausnahmen, wie die rationalen, komplexen, ..., gut umgesetzt. (Lisp wäre gründlicher aber es reicht auch so)
Nur wenn man schon eine Maßeinheit einführt, dann sollte man diese auch in Berechnungen beachten.Bin ich absolut dafür. Aber wenn man Maßeinheiten einführt und eine Rechnung nicht vom Compiler nicht verstanden wird, weil der Entwickler etwas neues macht, dann ist es nicht Aufgabe der Sprache ihm das grundsätzlich zu verbieten.
Wenn du schon Maßeinheiten einführst, solltest du auch darauf achten, daß der Compiler sie zu schätzen weiß, andernfalls sind sie nutzlos.
Xin schrieb:
Tellerrand schrieb:
Aber was nutzt eine Klasse Meter, wenn ich Werte daraus mit Gewicht addieren kann und das Resultat ein Integer ist?
Wozu dann die extra Klasse überhaupt?Wozu? Damit Du weißt, dass ein Meter plus ein Meter wieder ein Meter ergibt. Oder ein Meter * Meter einen Quadratmeter. Das ist ein Mehrwert und ein Mehrwert rechtfertigt eine Klasse.
Ja, das ist ein Mehrwert, der die Klasse rechtfertigt. Aber die implizite Behandlung des Meters als reinen int, die du durch deine (ich weiß: hypothetische) Ableitung nachgeworfen bekommst, rechtfertigst du damit noch lange nicht. Und außerdem mußt du dem Compiler noch zusätzlich sagen, daß "ein Meter plus ein Meter wieder ein Meter" bzw. "ein Meter * Meter einen Quadratmeter" ergibt - andernfalls stuft er beide als blanke int's ein.
Xin schrieb:
Woher soll ich wissen, wem Meter + Gewicht hilft? Ich kann garantieren, dass ein class Meter + ein class Meter wieder ein class Meter ergibt. Wie soll ich garantieren, dass Meter + Gewicht grundsätzlich sinnlos ist? Wenn ich das nicht garantieren kann, wie soll ich dann eine Einschränkung begründen?
Kannst du begründen, daß diese Addition irgendeinen Sinn ergibt? Wenn nein, warum willst du sie dann erlauben?
Xin schrieb:
Vor dem BMI gab es diese "Formel" für richtiges Gewicht: Gewicht = Groesee - 100
Mathematisch bedeutet das auch Groesse = Gewicht + 100cm
Wenn jemand das rechnen will, warum sollte ich ihm das verbieten?
Soll er doch rechnen. Was die Sprache nicht darf, ist ein solches Ergebnis kritiklos einem Typ wie Meter zuweisen.
Bei Gewicht + 100cm kommt beispielsweise typlose 175 raus. Wenn ich das einer Größe zuordnen will, dann muss ich das bestätigen: Groesse = Zentimeter( Gewicht + 100 );Ja, solche Formeln sind auch der Alptraum für jeden Physiker - und vermutlich auch nicht der richtige Einsatzort für ein typisiertes Einheitensystem. Und aus physikalischer Sicht würde ich die Formel eher als "Groesse/1cm == Gewicht/1kg + 100" schreiben.
Xin schrieb:
Ich sehe mich nicht in der Lage alle mathematischen und physikalischen Formen, die existieren und in Zukunftexistieren werden, in meinen Klassen abzubilden. Deswegen darf ich aber nicht die Kreativität der Entwickler enschränken.
Und darum gibt es Templates - mit denen können alle Einheiten und -kombinationen des SI-Systems mit einem Schlag erfasst werden.
(aber gib's zu, du hast dir den Ansatz noch nicht einmal angesehen)Xin schrieb:
Shade Of Mine schrieb:
Mit Einheiten zu rechnen bietet a) mehr Sicherheit und b) sorgt für kompaktere und leichter lesbare Parameterlisten. Wenn dies nicht möglich ist, mache ich das selbe wie jeder andere.
Kommt man von höherer Typsicherheit also wieder auf das Normalmaß herunter, hat man keinen Verlust.Ich sehe da absolut keine Sicherheit wenn ich Kilogramm + Meter addieren kann. Und du hast es selber gesagt, dass da quark rauskommt aber es kompiliert wird.
Hier wird wieder frei interpretiert. Ich sagte nicht "Quark". Ich sagte typlos. Das bedeutet, dass der Typ nicht aussagt, was man damit anfangen kann. Wenn der Compiler nicht weiß, was man damit anfangen kann, heißt das nicht, dass der Entwickler mit der Information damit nichts anfangen kann.
Dann solltest du dafür sorgen, daß der Compiler dein Einheitensystem versteht. Wenn ich gezwungen bin, die (typlosen) Rechenergebnisse von Hand in den richtigen Typ zu quetschen, bleibt von deiner Typsicherheit nicht mehr viel übrig.
Xin schrieb:
Shade Of Mine schrieb:
Man nicht garantieren kann, dass sie unsinnig sind und zumindest ich möchte keine Möglichkeiten einschränke, die ich nicht verstehe.
Es ist deine Klasse in deiner Domain und du kannst nicht die Operationen der Klasse definieren? Das ist fragwürdig.
Sorry, aber das hier steht in keinem Zusammenhang zu meinen Klassen, was Dir bewußt sein dürfte, da in C++ nicht von int geerbt werden kann.
Also ist alles, was nicht zu deiner Argumentation passt, unsinnig und irrelevant? Auch eine interessante Einstellung, um unbeliebten Argumenten aus dem Weg zu gehen.
Xin schrieb:
Operatoren zu den Klassen kann ich problemlos aufzählen und dazu gehören nunmal auch die geerbten, da ich sie nicht verbieten würde, also die Möglichkeiten nicht einschränke.
Hast du schonmal daran gedacht, daß int zu viele Operatoren zur Verfügung stellt, um es als Ausgangsbasis für ein typsicheres Einheitensystem dienen zu können? Wenn ich sowas entwerfe, beginne ich lieber bei einer leeren Klasse und definiere mir genau die Operationen, die ich als nötig ansehe. Dann muß ich mir keinen Kopf darüber machen, welche geerbten Operatoren Sinn machen - bzw. wie ich ihr Ergebnis interpretieren soll.
Xin schrieb:
Shade Of Mine schrieb:
C++ bietet hier typsicherheit an um eine Menge an Fehlern vorzubeugen. Das beste Beispiel ist wohl dieser Thread hier. Wieviele Probleme wurden bei der Vererbung von WinFlags -> Win aufgezählt und an wieviele hast du davor gedacht?
Erstens sehe ich bei der Vererbung weiterhin kein zu großes Problem. if( win ) ist eine Definition, die sich aus der Vererbung ergibt, die CStoll und Dir nicht gefallen. Mir gefällt es auch nicht sonderlich, aber ein Problem habe ich damit nicht.
if(win) ist eine Möglichkeit, die dein Entwurf bietet - zwar technisch unsinnig, aber trotzdem verfügbar. In einem vernüftigen Design sollten solche unsinnigen Anweisungen gar nicht erst möglich sein.
Xin schrieb:
Shade Of Mine schrieb:
Das alles sind potentielle Fehler in der Software - und für was? Was ist der große Vorteil davon dass man die Typsicherheit über Board wirft? Eine einfachere Syntax.
Das hat grade nichts mit klassifizierten Einheiten zu tun...?
Shade Of Mine schrieb:
Was ist Gewicht * Strecke? Was ist Zeit im Quadrat?
Gewicht * Strecke / Zeit / Zeit ist jedenfalls Kraft.Und was spricht dagegen dafür explizit etwas zu definieren?
Nichts und ich habe auch nicht behauptet, dass etwas dagegen sprechen würde.
Trotzdem kann es sein, dass man diese Typen aus einer Lib nimmt und erstmal feststellt, dass eine Konvertierung nicht dabei ist.
Shade Of Mine schrieb:
Ich kann jederzeit operatoren definieren damit Gewicht*Strecke/Zeit ein Objekt der Klasse Kraft liefert. Das Problem ist, wenn du daraus reine integers machst, verlierst du die komplette Typsicherheit und du kannst dir die Klassen sparen - rechne gleich mit integern - ist deutlich simpler und weniger aufwendig.
Ich verliere die Typsicherheit nicht. Ein Typ ist nur dann gegeben, wenn es sicher ist, ihn zu benennen. Ansonsten darf gerechnet werden, aber der Entwickler bekommt eine typlose Information.
Nur ist es immer schlecht, wenn der Entwickler dem Compiler explizit sagen muß, was für ein Typ da auftritt. Wer in der Lage ist (oder sogar gezwungen wird), das Ergebnis von "Gewicht*Strecke/Zeit/Zeit" in eine Kraft umzucasten, nur weil der Compiler nicht selbst erkennt, womit er rechnet, wird genauso schnell anfangen, beliebige Rechenergebnisse in beliebige Einheiten zu konvertieren - und schon ist dein Typsystem im Eimer.
Xin schrieb:
Er kann nun entweder etwas passendes definieren, oder muss die Verantwortung dafür übernehmen, eine typlose Information zu klassifizieren.
Shade Of Mine schrieb:
Kommen wir auf die einfachere Syntax zurück:
Ich kann jederzeit ein Kraft Objekt erstellen indem ich:Kraft k(g.asInt() * s.asInt() / z.asInt());schreibe.
Richtig, kannst Du. Das ist eine andere Möglichkeit. Es spricht nichts dagegen - aber in meinen Augen auch nichts dafür im Vergleich zu einer (theoretisch möglichen) Ableitung.
Shade Of Mine schrieb:
Dadurch erreiche ich eine Typsicherheit ohne einbussen der Funktionalität auf kosten einer (unter Umständen) komplizierteren Syntax.
Falsch. Du erreichst nicht mehr Typsicherheit, der einzige Unterschied ist, dass Du bei jeder Variable "asInt()" dahinter schreiben musst. Du erhältst also wieder ein typloses int.
In meinem Fall wird - sofern nicht typsicher gerechnet werden kann - mit ints gerechnet und Du erhältst ebenfalls ein typloses int.
In beiden Fällen kannst Du das typlose int nicht zuweisen. Du gewinnst also mit asInt keinen Vorteil.Da lobe ich mir doch die (oben erwähnte) Template-Variante - ich kann "Kraft k = g*s/(t*t);" schreiben und der Compiler wird mich darauf aufmerksam machen, wenn ich irgendwo in dieser Rechnung eine Einheit durcheinandergeworfen habe. Keine Probleme mit impliziten oder expliziten Umwandlungen nach int in Sichtweite.
Xin schrieb:
Shade Of Mine schrieb:
Denn um mehr geht es nicht - es geht nach wie vor nur um Syntax. Und ich denke nicht dass Syntax es wert ist dafür potentielle Fehler einzubauen. Allein der 1. Ansatz deiner WinFlags war voller Fehler. Keiner dieser Fehler wäre bei Komposition aufgetreten. Und technisch wären beide gleichwertig - lediglich Sicherheit <-> Syntax.
Ich weiß nicht, von welchen Fehlern Du sprichst. Was ich beschrieb, funktioniert problemlos und korrekt - auch unter Mehrfachvererbung, sobald Du die Operatoren in den Namensraum der Klasse holst.
Falls du es noch nicht bemerkt hast, wir sprechen hier nicht von Fehlern im Sinne von "syntaktisch falsch", sondern von Fehlern im Design - aber die hast du ja bisher erfolgreich ignoriert.