"to MI or not to MI"
-
Ich bin noch immer verwirrt.
Wie genau kann nun Kreis feststellen wann sich sein Radius geaendert hat?Wenn ich
class Kreis : private Radius, private PunktXY { public: Radius& AsRadius() { return *this; } }; //oder waere class Kreis : public Radius, public PunktXY { };//korrekter?
schreibe, weiss ich in Kreis ja nicht wann sich Radius geaendert hat.
Wie wuerde das aussehen wenn ich das wissen will?Wenn C++ hier ungeeignet ist, koennen wir auch gerne in Scala oder Ruby modellieren.
PS:
Wenn Kreis/Rechteck doof ist, koennen wir auch etwas anderes machen. Solange es etwas grundlegendes ist - damit wir uns nicht in details der Modellierung verlieren. Also zB ein Auto dass einen Motor und 4 Tueren hat und davon Leiten wir dann Sportwagen oder aehnliches ab. Sowas in der Art halt. Nimm dir ruhig irgendein Modell hier mit dem du zufrieden bist.
-
Abgesehen von viel Code um nichts, machste wieder den einen Generalfehler, daß Du nicht programmierst, um folgende Flüchtigkeitsfehler aufzudecken.
Radius & operator = ( int radius ) { Integer::Value = radius < 0 ? 0 : radius; }
verdeckt Fehler und macht sie nur schwerer findbar.
-
Fakt ist, dass ein Klasse, die eine Einschränkung ihrer Basis hat, natürlich nicht public erben darf.
Vererbung hat erstmal nichts mit Zugriffsmodifier zu tun. C++ kann auch ohne public/private funktionieren, genauso kann auch const entfernt werden, ohne das etwas kaputt geht.
So siehts aus: Allgemeines Konzept -> Umsetzung in einer Sprache. Aber was du machst: Eine Umsetzung in C++ erlaubt deine Idee und du erhebst sie zum allgemeinen Konzept. Leider "funktioniert" es nur unter C++. Doch nicht mehr so allgemein. Ausserdem sind schon sehr viele Probleme angesprochen worden, die vielleicht geloest werden koennen, aber im Vergleich zum traditionellen Vererbungsbegriff eher unelegant wirken.
Konkret: Kreise erben von Zahlen, Zahlen koennen in unmissverstaendlicher Weise addiert werden und ergeben wieder eine Zahl. Was ist die Addition von zwei Kreisen und ist es wieder ein Kreis? Da gibt es viele Interpretationen.
Wer scheiße programmiert, wird scheiße erhalten.
Genau darum geht es. Dein Konzept ist scheisse.
-
Geht es im Kern darum, ob ein Enkel von Eltern und Tanten erben darf
und einzig die Prämisse im Raum steht
ob er/sie das Radfahren jetzt vom Onkel oder Vater lernt ?Wenn man s rein logisch angeht
wäre der erste "Lehrer" wohl der Gewinner..
-
Erbt nun bei Deinem Entwurf Wurstbrot von Supermatrkt oder Supermarkt von Wurstbrot?
Ist ja irgendwie beides richtig.
class Wurstbrot:Supermarkt { //getVerkaufer wird ohne sinnlosen Schreibaufwand geerbt }
Aber auch
class Supermarkt:Wurstbrot { //getVerkaufer wird ohne sinnlosen Schreibaufwand geerbt }
Hmm.
-
volkard schrieb:
Erbt nun bei Deinem Entwurf Wurstbrot von Supermatrkt oder Supermarkt von Wurstbrot?
Das ist der Punkt ^^
Sowohl das Klima im Supermarkt ändert dein Brot,
genauso wie dein Brot zum Klima im Supermarkt beiträgt ^^Edit:
Ich denke spätestens wenn Quantencomputer auf den Consumer-Markt drängen,
wird sich da mit der Vererbung nochmal kräftig was tun..
Alles nur Humbug ?
Guckst Du hier http://www.dwavesys.com/en/dw_homepage.html
Abnehmer - Lockheed Martin ..
-
volkard schrieb:
Nur die Postleitzahl 0 ist nicht valide, alle anderen Postleitzahlen sind in Ordnung. Denn wir haben den Operator ! von Integer geerbt.
Nein. Nur ein Teil der PLZ sind valide, z.B. ist 00001 keine valide PLZ. Tatsächlich sind ein Großteil der möglichen PLZ nicht in Gebrauch und damit nicht valide. Abgesehen davon gibt es in anderen Ländern "Postcodes" die nicht nur auf Ziffern basieren.
volkard schrieb:
Ist es überhaupt wahr, zu sagen "Die Postleitzahl IST eine Zahl?"
Nein. Darum schrieb ich ja, dass es keinen Sinn macht, PLZ von Integer erben zu lassen.
-
Shade Of Mine schrieb:
Ich bin noch immer verwirrt.
Wie genau kann nun Kreis feststellen wann sich sein Radius geaendert hat?Das bezog sich nicht auf diese Frage. Bau Dir Events ein, mach, was immer Du unter C++ auch gemacht hast.
Da ändert sich nix.
Shade Of Mine schrieb:
Wenn C++ hier ungeeignet ist, koennen wir auch gerne in Scala oder Ruby modellieren.
Wir können das gerne, wobei ich das nur gerne könnte.
Meine Scala-Kenntnisse sind überschaubar (ich arbeite dran, wenn ich mal endlich mal wieder Zeit dafür habe) und meine Rubykenntnisse noch viel überschaubarer.
Das Ganze dreht sich ja auch nicht darum, das hier aufzublähen, sondern die Gleichwertigkeit zu demonstrieren. Dafür habe ich eben einen C++-Code mit reichlich Boilerplate reingepackt, in den kannst Du beim Zuweisungsoperator von Radius reinpacken, was immer Du magst. Beispielsweise jemanden informieren, dass sich der Radius geändert hat.
Bitte erzähl mir jetzt nicht, dass ich gefälligst <BeliebigeSpracheEinsetzen> lernen soll, damit ich mir angucken kann, wie man das richtig macht. Ich schaue mir regelmäßig neue Sprachen an, wenn ich Zeit dafür habe und jeder hat da seine persönliche Meinung, welche Sprache die richtige ist.
volkard schrieb:
Abgesehen von viel Code um nichts, machste wieder den einen Generalfehler, daß Du nicht programmierst, um folgende Flüchtigkeitsfehler aufzudecken.
Viel Code um nichts. Richtig. Boilerplate. Aber zu inlinen, generierbar (sowas machen Compiler), bzw. nur in C++ erforderlich, um Anweisungen zu forwarden: wenn der Compiler diese Forwards automatisch macht, indem er zum Beispiel direkt die zu rufende Funktion einsetzt, wird da auch tatsächlich wieder "nichts" draus. Nur mit C++ ist das eben nicht formulierbar.
Du hast vor meinem Posting einen anderes Posting gesetzt, dass ich jetzt erst gesehen habe:
volkard schrieb:
Was Xin braucht, ist wohl C++:
class Postleitzahl:mixin Integer{ promote relational;//<, <=, ==, >=, >, != promote std::hash(Integer);//sind ja gute Hashtable-Schlüssel. promote constructors, copy, assign;//Jo, die sind ok friend ostream& operator<<(ostream& out,Postleitzahl plz);//to be implemented }
Das ist in der Granularität durchaus gewünscht. Nur müssen die Standardfälle in Kurzform definiert werden können.
volkard schrieb:
Radius & operator = ( int radius ) { Integer::Value = radius < 0 ? 0 : radius; }
verdeckt Fehler und macht sie nur schwerer findbar.
Sorry, wenn ich um die Uhrzeit nicht mehr alles so optimal hinbekomme.
Radius & operator = ( Radius radius ) { Integer::Value = radius.Integer::Value < 0 ? 0 : radius.Integer::Value; }
Führt zu
Streckenlänge s( 10 ); Radius r(5); r = Radius( s );
knivil schrieb:
Eine Umsetzung in C++ erlaubt deine Idee und du erhebst sie zum allgemeinen Konzept. Leider "funktioniert" es nur unter C++. Doch nicht mehr so allgemein. Ausserdem sind schon sehr viele Probleme angesprochen worden, die vielleicht geloest koennen, aber im Vergleich zum traditionellen Vererbungsbegriff eher unelegant wirken.
In C++ sind wir hier an einer Stelle, die in C++ ziemlich unelegant ist. Beim SubtypeableOperator hingegen empfinde ich das auch in C++ elegant und angemessen. Nur in solchen Fällen nutze ich Mehrfachvererbung in C++.
knivil schrieb:
Wer scheiße programmiert, wird scheiße erhalten.
Genau darum geht es. Dein Konzept ist scheisse.
Für C++ sind wir an dieser in einem Bereich, den niemand als "schön" verkaufen will.
Alle bisher genannten Probleme sind mir bekannt und Lösungen sind in C++ nur teilweise überhaupt zu formulieren und wenn dann sieht das auch durchaus "scheiße" aus. Aber teilweise geht es in C++ und das ist zusammen zu führen, so dass nicht mehr zwischen Membern und Ableitung zu unterscheiden ist, sondern es nur noch eine Form Komposition gibt, die aber pro Element beschreibt, wie damit umgegangen werden soll. Das ganze hier ist ja nicht als Programmierempfehlung für C++ zu verstehen, sondern nur als Richtungszeiger, wohin man denken kann.
Ihr habt euch hier auf die gleichen Probleme gestürzt wie ich. Ihr mit dem Ziel, mir zu sagen, dass "mein" Konzept scheiße ist und ich mache das mit dem Ziel das Standardproblem umreißen zu können. Und für Standardprobleme muss eine Sprache dann eine Standardlösung anbieten. Wir arbeiten in die gleiche Richtung nur mit unterschiedlicher Motivation: Ihr sagt mir viele Probleme, ich versuche eine Abstraktion dafür zu finden und eine Lösung zu erarbeiten.
Ich sehe die Chance, dass das klappt, ich sehe da Potential, also probiere ich es aus.Zurück zur ursprünglichen Debatte: Beim SubtypeableOperator ist die Mehrfachvererbung, so wie sie in C++ formulierbar ist, hilfreich. Zum einen deswegen halte ich es für sinnvoll, sich mit Mehrfachvererbung auseinander zu setzen und zum anderen halte ich es für sinnvoll, um sich mit dem Konzept der Mehrfachvererbung vertraut zu machen, weil ich davon ausgehe, dass andere Sprachentwickler sich auch Gedanken zu dem Thema machen werden, weil Interfaces eigentlich auch nur ein "scheiß Konzept" sind und sich andere Entwickler auch um Lösungen bemühen.
Java baut zurück und nennt das Interfaces. Scala wirft Traits in die Arena. Es ist halt viel Ausprobieren und wo am Ende etwas interessantes rauskommt, kann man auch nicht in so einem Thread behandeln, sondern braucht entsprechende Software, um das im Verlauf der Entwicklung dieser Software zu beobachten, was sich wirklich als praktisch erweist, wo etwas nur im Beispiel praktisch aussieht, aber wieder entfernt werden sollte oder wo sich vielleicht Möglichkeiten ergeben, die weiter aufgebaut werden können.
Trotzdem ist dieser Thread für mich hilfreich, wenn man vielleicht mal von volkard, pVoid und ihrem Wurstbrot absieht, denn auch wenn ich noch nichts gelesen habe, was mir neu wäre, so zwingt es mich, die Sachen in Frage zu stellen und damit zu verifizieren.
Bisher denke ich weiterhin, dass es ein guter Versuch ist. Und wenn nicht, bleibt trotzdem Subtypable und Operator als Grund für Mehrfachvererbung.
-
Xin schrieb:
volkard schrieb:
Radius & operator = ( int radius ) { Integer::Value = radius < 0 ? 0 : radius; }
verdeckt Fehler und macht sie nur schwerer findbar.
Sorry, wenn ich um die Uhrzeit nicht mehr alles so optimal hinbekomme.
Radius & operator = ( Radius radius ) { Integer::Value = radius.Integer::Value < 0 ? 0 : radius.Integer::Value; }
Führt zu
Streckenlänge s( 10 ); Radius r(5); r = Radius( s );
Facepalm.
Das Überdecken den Programmierfehlers r-=1000, Du Nase. Das "< 0 ? 0" ist ärgeranziehend.Ganz so, wie übrigens Deine falsch angewendete Vererbung auch. Eines der Hauptprobleme scheinz zu sein, daß Du überhaupt kein Gefühl für defensives Programmieren zu haben scheinst. Nur Tipparbeit sparen zu wollen, ist einfach kein guter Ratgeber.
Schade, daß Du aufs umdrehen-Beispiel nicht eingehen magst.
-
Xin schrieb:
Shade Of Mine schrieb:
Ich bin noch immer verwirrt.
Wie genau kann nun Kreis feststellen wann sich sein Radius geaendert hat?Das bezog sich nicht auf diese Frage. Bau Dir Events ein, mach, was immer Du unter C++ auch gemacht hast.
Da ändert sich nix.
Aber OK, du würdest hier also ein Notification System einbauen. Das kann man ja wiederum erben.
Ich habe das ganze dann mal eben geschrieben:
http://ideone.com/hHs59fIst das so in etwa das was du dir vorstellst?
C++ wehrt sich da irgendwie mit Händen und Füßen dagegen...Gibt es eine Sprache wo das etwas besser geht, weil - ohne dass du das jetzt bitte falsch verstehst - in C++ ist das nicht möglich so zu programmieren. Ich muss konstant Code verdoppeln und muss höllisch auf die Scopes aufpassen weil da dauernd irgendein Parent reinpfuscht.
Mir ist egal welche Sprache. Such dir eine aus. Hauptsache es gibt Tutorials zum einlesen - dann gib mir ein paar Tage und wir können mit der Sprache weiter diskutieren.
Falls wir bei C++ bleiben, dann habe ich gleich eine Frage:
Kann man den op= irgendwie besser aufrufen als über die Qualifizierung des Ursprungstyps. ein
k.Radius::operator=() ging leider nicht.uU habe ich ja auch was falsch gemacht - deshalb, wenn möglich - kannst du meinen Code ausbessern?
Das Ganze dreht sich ja auch nicht darum, das hier aufzublähen, sondern die Gleichwertigkeit zu demonstrieren. Dafür habe ich eben einen C++-Code mit reichlich Boilerplate reingepackt, in den kannst Du beim Zuweisungsoperator von Radius reinpacken, was immer Du magst. Beispielsweise jemanden informieren, dass sich der Radius geändert hat.
Boilerplate ist mir egal. Boilerplate ist nur Syntax. Wichtig ist, dass wir korrekt modellieren können.
-
volkard schrieb:
Facepalm.
Das Überdecken den Programmierfehlers r-=1000, Du Nase. Das "< 0 ? 0" ist ärgeranziehend.Ich baue hier kein perfektes Framework für geometrische Objekte auf. Das hier sind kurzgehaltende Beispiele, um eine Richtung anzudeuten, keine Programme, die Du danach als ein CAD kompilieren kannst. Es geht um Unterscheidungen - mir jedenfalls - nicht darum in einem speziellen Fall die perfekte Implementierung für eine Unterscheidung hier abzuliefern.
Irgendwann muss so ein Posting auch mal fertig werden und falls dann etwas Unwichtiges nur irgendwie kompilierfähig gemacht wird, dann kannst Du Dir das sicherlich auch selbst kurz in Hübsch vorstellen.volkard schrieb:
Ganz so, wie übrigens Deine falsch angewendete Vererbung auch. Eines der Hauptprobleme scheinz zu sein, daß Du überhaupt kein Gefühl für defensives Programmieren zu haben scheinst. Nur Tipparbeit sparen zu wollen, ist einfach kein guter Ratgeber.
Schade, daß Du aufs umdrehen-Beispiel nicht eingehen magst.Weil es nichts mit Mehrfachvererbung zu tun hat, weil darauf bereits eingegangen wurde, weil der Fehler problemlos zu debuggen ist, weil die Hierarchie semantisch verifizierbar ist, wenn die Sprache das unterstützt, weil der Funktionsname schon scheiße gewählt ist, weil das Beispiel Schwachsinn ist, denn wer erlaubt, dass sich ein Kopf vier mal um 90 Grad umdrehen lässt, der tötet einen Menschen weil er eine Restriktion im Hals falsch implementiert (Hallo defensives Programmieren!) hat und nicht weil er vergessen hat den Menschen am richtigen Punkt umzudrehen, weil Du Fehler allgemein nicht grundsätzlich abfangen kannst und Du Deine Software erstmal mit einem Dummy testen musst, bevor Du einen Menschen damit fernsteuerst und das ganz normaler Entwicklungsalltag ist und Du den Fehler mit Membern genauso beschreiben kannst.
Die Tatsache, dass man auch fehlerhafte Programme formulieren kann, weil man etwas anderes wünscht, als man geschrieben hat ist als Argument einfach Schwachsinn.
Darum testet man Software im Idealfall und bringt dann erst Menschen damit um. (Sarkasmus-Schild-Hochhaltend)
@Shade: Dafür das mit Dir durchzugehen, möchte ich mir mehr Zeit nehmen, damit ich den Code auch mal durch den Compiler jagen kann.
Ich kann Dir nicht sagen, ob es dafür eine Sprache gibt, mir ist keine bekannt, sonst würde ich die ja verwenden und nicht selbst eine schreiben. ^^
Kann ich die Probleme sprachlich einkreisen, kann ich sie auch (hoffentlich) sprachlich lösen. Wenn nicht oder sich das Ganze im praktischen Einsatz nicht als gut bewährt... dann Arschkarte.Ich kann Dir allerdings nicht sagen, wann ich Ruhe dafür habe und die Zeit, Probleme in C++ zu formulieren, die ich so üblicherweise auch nicht in C++ formulieren würde.
Ich habe jetzt keine Zeit dafür und ehrlich gesagt auch keinen Plan, ob oder wann ich diese Woche überhaupt noch Zeit für irgendwas habe. Sehr wahrscheinlich eben nicht, um mich in Ruhe und idealerweise auch mal ausgeschlafen an irgendeinen Compiler zu setzen.Shade Of Mine schrieb:
Boilerplate ist mir egal. Boilerplate ist nur Syntax. Wichtig ist, dass wir korrekt modellieren können.
Gute Basis.
PS: Verdammt... bin zu neugierig... ich habe nochmal über den Code geguckt und fand das unten abgedruckte Ergebnis eigentlich doch so entsprechend meiner Erwartung.
Entsprechend hast Du C++ offenbar ja doch gebändigt bekommen, obwohl es sich gewehrt hat.Shade Of Mine schrieb:
Falls wir bei C++ bleiben, dann habe ich gleich eine Frage:
Kann man den op= irgendwie besser aufrufen als über die Qualifizierung des Ursprungstyps. ein
k.Radius::operator=() ging leider nicht.Warum nicht?
Hier werden vermutlich zwei Anpassungen gleichzeitig nötig sein, weswegen C++ streikt. Ich würde Radius::operator
Radius const & r ) definieren und weiterleiten.
Es reicht vermutlich reicht aber auch
k.Radius::operator=( Radius( 7 ) );
(Nicht ausprobiert, just an educated guess)
-
Xin schrieb:
Weil es nichts mit Mehrfachvererbung zu tun hat,
Irgendwie schon. Weil Vererbung bereits falsch ist, ist Mehrfachvererbung mehrfach falsch.
-
Ich scheitere gerade an der Funktion:
void verdoppleRadius(Radius& r) { //was ich gerne hätte //r=r+r; oder r*=2; oder dergleichen //geht aber leider nicht :( r.ChangeObservableArithmeticType::operator=(r.asPositiveInteger()+r.asPositiveInteger()); }
Das Problem ist, dass PositiveInteger protected von Integer erbt und mein "operator Integer()" scheinbar vom Compiler ignoriert wird.
Ich will jetzt operator+ für Integer verwenden um 2 PositiveInteger miteinander zu addieren. Aber das mag der Compiler nicht, da Integer eine inaccessible Base von PositiveInteger ist.
Wenn ich
r.ChangeObservableArithmeticType::operator=(r.asPositiveInteger().operator ::Integer()+r.asPositiveInteger().operator ::Integer());
verwende - dann mag er nicht weil der op= einen ChangeObservableArithmeticType<PositiveInteger> erwartet aber einen Integer bekommt. Und er kann nicht in einem Schritt aus Integer einen ChangeObservableArithmeticType<PositiveInteger> machen...
Ich müsste also eigentlich public von Integer erben. Aber dann kann ich keine Constraints für den Typ definieren. Jedenfalls hänge ich an der Stelle. Vielleicht fällt mir später ja noch eine Lösung ein...
PS:
Wenn ich in Radius einen Ctor definiere:Radius(ChangeObservableArithmeticType::BaseType value) : ChangeObservableArithmeticType(value) {}
Dann kann ich in der Tat
k.Radius::operator=(Radius(7));
schreiben.PPS:
eigentlich wollte ich Code verdopplung vermeiden... Oder meinst du es ist notwendig alle Operatoren mehrfach zu definieren? Das würde mein PositiveInteger/Integer Problem lösen indem ich alle Operatoren die Integer hat einfach für PositiveInteger neu definiere... Andererseits ist das ne Menge arbeit das Synchron zu halten.
-
Shade Of Mine schrieb:
Ich scheitere gerade an der Funktion:
void verdoppleRadius(Radius& r) { //was ich gerne hätte //r=r+r; oder r*=2; oder dergleichen //geht aber leider nicht :( r.ChangeObservableArithmeticType::operator=(r.asPositiveInteger()+r.asPositiveInteger()); }
Das Problem ist, dass PositiveInteger protected von Integer erbt und mein "operator Integer()" scheinbar vom Compiler ignoriert wird.
Ich will jetzt operator+ für Integer verwenden um 2 PositiveInteger miteinander zu addieren. Aber das mag der Compiler nicht, da Integer eine inaccessible Base von PositiveInteger ist.
Yepp, deswegen hatte ich in meinem Kreisgedöhns eine Funktion "Integer const & AsInteger() const", die die gleiche Funktion bietet.
Shade Of Mine schrieb:
Wenn ich
r.ChangeObservableArithmeticType::operator=(r.asPositiveInteger().operator ::Integer()+r.asPositiveInteger().operator ::Integer());
verwende - dann mag er nicht weil der op= einen ChangeObservableArithmeticType<PositiveInteger> erwartet aber einen Integer bekommt. Und er kann nicht in einem Schritt aus Integer einen ChangeObservableArithmeticType<PositiveInteger> machen...
In C++ musst Du die Konvertierungen schon klarstellen, da Templates hier sehr restriktiv sind und auf die Vererbung oder Konvertierungsmöglichkeiten der Template-Parameter nicht eingehen kann (und auch nicht implizit sollte, aber eben auch keine Möglichkeit gibt, es implizit zu erlauben).
Hier müsste das Verwandschaftsverhältnis von der Sprache erkannt oder wenigstens erlaubt werden (bzw. in C++ nochmals beschrieben werden).
Shade Of Mine schrieb:
PS:
Wenn ich in Radius einen Ctor definiere:Radius(ChangeObservableArithmeticType::BaseType value) : ChangeObservableArithmeticType(value) {}
Dann kann ich in der Tat
k.Radius::operator=(Radius(7));
schreiben.Hallo "Curiously Recurring Template Pattern"?
-
Ha, so jetzt funktioniert es besser:
http://ideone.com/Wk2LNBIch kann jetzt
void verdoppleRadius(Radius& r) { r=r+r; }
schreiben.
PS:
Diese asFoo() funktion mag ich nicht, weil die nicht implizit aufgerufen wird. Wenn ich
r.asPositiveInteger().asInteger() aufrufen muss, komm ich mir irgendwie doof vorHabe das Problem aber über Forward Makros gelöst.
-
Shade Of Mine schrieb:
Ha, so jetzt funktioniert es besser:
http://ideone.com/Wk2LNBIch kann jetzt
void verdoppleRadius(Radius& r) { r=r+r; }
schreiben.
Und wenn man sich den ganzen Quellcode anschaut, der dafür in C++ nötig ist, versteht man sehr gut, warum kein normaler Mensch sich auch nur Gedanken darüber macht, ob man darauf aufbauend vielleicht etwas Praktisches erreichen kann.
Ja, schon klar, ich kann mir die Schlussfolgerung schon selbst denken... :->Shade Of Mine schrieb:
PS:
Diese asFoo() funktion mag ich nicht, weil die nicht implizit aufgerufen wird. Wenn ich
r.asPositiveInteger().asInteger() aufrufen muss, komm ich mir irgendwie doof vorProtected wird hier global über alles gelegt. Eigentlich müsste Integer unterscheiden, ob es als Objekt existiert und Zuweisungen von Außen zulässt oder ob es als Basisklasse für PositiveInteger() existiert. Da PositiveInteger() eigentlich eine Einschränkung der Menge gültiger Werte von Integer ist, ist nur der Teil von Operationen vererbbar, der einen Wert aus der gültigen Menge (den positiven Zahlen) nicht in einen ungültigen Wert verwandelt.
Man kann also alle const-Methoden direkt vererben (was man in C++ über operator Integer CONST &() impliziet ausdrücken könnte, wenn C++ es erlauben würde), den Zuweisungsoperator hingegen muss man in PositiveInteger reimplementieren.
Die operation - wäre also durchaus legitim: PositiveInteger( 1000 ) - PositiveInteger( 2000 ) ergibt ein Integer( -1000 ). Das wiederum könnte man über PositiveInteger::operator=( Integer const & ) zuweisen und hier prüfen, ob man diese Zuweisung das Objekt nicht in eine fehlerhaften Zustand überführt. Integer::operator=( Integer const & ) ist ja für PositiveInteger nicht sichtbar.
Die Ableitungsformel wäre also quasi "const public mutable protected".
-
Ne, ich will das jetzt austesten - wenn es umständlich ist, dann ist es das halt. Das stört mich nicht.
Ich habe gerade aufgegeben PunktXY observable zu machen, weil das einfach zu kompliziert geworden wäre. Ich habe mit Radius ja schon ein observable Konstrukt.
Das Problem dass ich damit habe ist, dass jedes Implementationsdetail öffentlich ist. Es ist zB nicht möglich beim Ursprung des Kreises plötzlich auf double zu wechseln wenn ich vorher int verwendet habe. Oder zB auf __int64 statt __int32 oder sowas. Weil überall in meinem Clientcode eben direkt PunktXY verwendet wird. Und PunktXY kann ich ja nicht ändern, weil das von allen anderen Klassen auch verwendet wird.
Was cool ist, ist printKoordinaten. Das ist richtig cool. Aber das ist jetzt die einzige Situation wo ich was cooles gefunden habe.
Ich bin mir auch nicht ganz sicher über solche Sachen wie Radius=Laenge*PunktX/PunktY.
Mein Fazit: in C++ komme ich nichtmal zu der Stelle wo es interessant wird, weil die Sprache sich mit Händen und Füßen gegen diesen Ansatz wehrt.
Gibt es eine Sprache in der dein Ansatz verfolgbar ist? Du musst ja schon Erfahrung damit haben: hast du vielleicht Code wo du das Umgesetzt hast? Wie gesagt - Sprache ist mir egal. Aber in C++ kommen wir hier auf keinen Grünen Zweig.
-
Shade Of Mine schrieb:
Ne, ich will das jetzt austesten - wenn es umständlich ist, dann ist es das halt. Das stört mich nicht.
Blut geleckt? ^^
Shade Of Mine schrieb:
Das Problem dass ich damit habe ist, dass jedes Implementationsdetail öffentlich ist. Es ist zB nicht möglich beim Ursprung des Kreises plötzlich auf double zu wechseln wenn ich vorher int verwendet habe. Oder zB auf __int64 statt __int32 oder sowas. Weil überall in meinem Clientcode eben direkt PunktXY verwendet wird. Und PunktXY kann ich ja nicht ändern, weil das von allen anderen Klassen auch verwendet wird.
Hier kommen dann quasi Templates ins Spiel...
Shade Of Mine schrieb:
Was cool ist, ist printKoordinaten. Das ist richtig cool. Aber das ist jetzt die einzige Situation wo ich was cooles gefunden habe.
Immerhin.
Manchmal übersieht man aber Dinge, die nicht gefunden werden können, weil sie nicht da sind.
Ist Dir mal aufgefallen, dass Du Dir keine Membernamen ausdenkst?Das finde ich richtig cool.
Shade Of Mine schrieb:
Gibt es eine Sprache in der dein Ansatz verfolgbar ist? Du musst ja schon Erfahrung damit haben: hast du vielleicht Code wo du das Umgesetzt hast? Wie gesagt - Sprache ist mir egal. Aber in C++ kommen wir hier auf keinen Grünen Zweig.
Ich kann mich nur selbst zitieren:
Xin schrieb:
Ich kann Dir nicht sagen, ob es dafür eine Sprache gibt, mir ist keine bekannt, sonst würde ich die ja verwenden und nicht selbst eine schreiben. ^^
Wobei... würde ich wohl doch... ich habe ja auch ein paar andere verrückte Ideen und Spaß macht's auch noch. ^^
-
@Xin: gibt es vielleicht irgendwo ein Dokument oder irgendwas, was deine Sprache mal skizziert? Deine Ideen diesbezüglich interessieren mich wirklich (du hast ja Verschiedenes auch schon in anderen Threads angedeutet). Oder könntest du mal ein paar Grundgedanken andeuten? Was sind noch grundlegende Neuerungen gegenüber existierenden Sprachen? Das muss ja nicht ausformuliert sein, nur damit man mal einen Eindruck bekommt.
Und hast du dich mal mit funktionalen Sprachen beschäftigt? Offenbar betreibst du ja viele Gedanken in Richtung Sprachdesign und meines Erachtens haben funktionale Sprachen (z.B. Haskell) eine innewohnende Eleganz, die sowohl OOP als Konzept, als auch die mir bekannten imperativen und objektorientierten Sprachen nicht ansatzweise erreichen. Oder gibt es andere Gründe, warum deine Sprache objektorientiert/imperativ ist?
-
Ich habe jetzt probiert eine Klasse Auto zu schreiben und puh. Jetzt eck ich nur noch an.
Ich bekomme die Klasse Tank nicht so hin, dass sie von Fuellstand und Maximalstand erbt, aber diese Beiden Werte zueinander in beziehung setzt. So will ich, dass der Fuellstand nie unter 0 aber auch nie üeber Maximalstand geht.
Das ist aber alles doof, weil ja Auto ebenfalls zugriff auf Maximalstand und Fuellstand haben will. Auf herkömmliche Art ist das ganze ja trivial - aber hier artet das etwas aus.
Ich habe irgendwie das Gefühl dass das Open Closed Principle hier nicht so ganz passen will. Wenn ich Komponenten schreibe, dann sind die immer ziemlich genau auf meinen Usecase zugeschnitten. Ich muss zB Fuellstand von meinem ChangeObserver erben lassen noch bevor ich eine Klasse Tank habe. Was wenn ich später drauf komme ich will zB Geschwindigkeit ebenfalls Observen? Dann muss ich ja Geschwindigkeit ändern... Irgendwie muss da noch was besseres her.
Was auch total ärgerlich ist, ist dass die Werte die ich überall zuweise keinen Namen haben. Es ist immer Integer::value und nie PS oder kmh oder xCoord. Das macht den Code etwas doof zu warten.
Sobald ich nicht public erbe, habe ich Probleme. Solange ich alle Klassen immer public erben lassen läuft das ganze eigentlich relativ flüssig. Aber wenn ich Beschränkungen machen will, dann wird es tricky. Und Implementierungsdetails verstecken kann ich auch nicht. Auch Templates helfen mir da kaum weiter - weil ich vorher genau wissen muss was ich verstecken will und was nicht (ich kann nur ja nur wenige Details verstecken - über eine höhere Abstraktionsebene). Dadurch verliere ich aber wieder die "composability" also die Möglichkeit nach belieben die Komponenten zusammenzustöpseln.
Vielleicht habe ich heute Abend noch eine Erleuchtung aber bis jetzt sehe ich keinen Sinn.
Die ganze Zeit wünsche ich mir einfach nur Mixins - die lösen diese Probleme. Hast du dir schonmal Rubys Mixins oder zB JavaScripts prototype angesehen?