Eigene Klassenbibliothek



  • Nexus schrieb:

    Dir ist aber bewusst, dass man in C++ freie Funktionen schreiben kann, um Funktionalität bestehender Klassen zu erweitern? Dass man 5 Klassen für sortierbare, zufällig füllbare, mittelwert-berechenbare, selbst-erweiternde und nichtskönnende Container schreibt, ist absoluter Unsinn.

    Schau dir vielleicht mal die STL-Algorithmen an. Dann wird dir bewusst, warum die STL derart mächtig ist, obwohl die einzelnen Container relativ wenige Operationen anbieten.

    Ohne den Code jetzt schönreden zu wollen, aber wenn das Zeugs gewachsen ist kann ich das schon nachvollziehen. Zuerst kam die Anforderung, prä-standard eine Containerklasse zu bauen: Zack, fertig. Danach kam die Änderung, dass der Container sortierbar sein soll: Memberfunktion hinzugefügt, fertig. Und so nimmt das Unheil seinen Lauf, man erweitert und spezialisiert ohne klares Konzept und hinterher hat man X Klassen, die alle Ähnliches tun, aber doch unterschiedlich sind. Und wenn das Zeugs erst ein mal im Produktivcode eingesetzt wird tut man sich schwer damit, das Interface zu ändern.

    Vor 20 Jahren hätte ich mir vielleicht überlegt, das einzusetzen, aber heute mit der STL und boost: Nein, danke.



  • Nexus schrieb:

    Dir ist aber bewusst, dass man in C++ freie Funktionen schreiben kann, um Funktionalität bestehender Klassen zu erweitern? Dass man 5 Klassen für sortierbare, zufällig füllbare, mittelwert-berechenbare, selbst-erweiternde und nichtskönnende Container schreibt, ist absoluter Unsinn.

    Schau dir vielleicht mal die STL-Algorithmen an. Dann wird dir bewusst, warum die STL derart mächtig ist, obwohl die einzelnen Container relativ wenige Operationen anbieten.

    Was ist besser?

    class ARRAY_OF_DOUBLES : public ARRAY<double>
    {
    	public:
    	double sum( void ) const;
    	double average( void ) const
    	{
    		return sum() / (double)getNumElements();
    	}
    };
    

    oder

    double sum( ARRAY<double> &array );
    double average( ARRAY<double> &array ) const;
    

    OK letzteres könnte man auch über templates realisieren, um dann nicht nur doubles zu summieren sondern auch ints oder Äpfel. Aber solange das nicht notwendig ist, ist das egal. Mir gefällt ersteres dabei besser.

    Die STL muß halt viele Bedürfnisse erfüllen können. Klar ist die dadurch viel mächtiger wie meine Bibliothek.

    mfg Martin



  • mgaeckler schrieb:

    Was ist besser?

    class ARRAY_OF_DOUBLES : public ARRAY<double>
    {
    	public:
    	double sum( void ) const;
    	double average( void ) const
    	{
    		return sum() / (double)getNumElements();
    	}
    };
    

    oder

    double sum( ARRAY<double> &array );
    double average( ARRAY<double> &array ) const;
    

    OK letzteres könnte man auch über templates realisieren, um dann nicht nur doubles zu summieren sondern auch ints oder Äpfel. Aber solange das nicht notwendig ist, ist das egal. Mir gefällt ersteres dabei besser.

    Es ist ganz klar das zweite besser.
    z.B. schonmal deswegen, weil du damit keine Probleme bekommst wenn du mal ein ARRAY<double> statt eines ARRAY_OF_DOUBLES übergeben bekommst, und dann sum oder average drauf machen willst.



  • DocShoe schrieb:

    Ohne den Code jetzt schönreden zu wollen, aber wenn das Zeugs gewachsen ist kann ich das schon nachvollziehen.

    Das war aber nicht die Frage, die Frage war ob Interesse an der Library bestehen könnte.
    Und die Antwort darauf ist wohl nicht abhängig davon wie und warum die Library gewachsen ist.



  • mgaeckler schrieb:

    double sum( ARRAY<double> &array );
    double average( ARRAY<double> &array ) const;
    

    Wenn überhaupt dann mit const reference. Wie kommt das, dass Du eine zig Jahre an einer Klassenbibliothek arbeitest und noch nicht mal const correctness verstehst? Ich würde so eine Klassenbibliothek nicht weiter anschauen, wenn der Autor so wenig C++-Know-How zeigt. Entschuldige die scharfen Worte aber manchmal ist es besser direkt zu sein.

    Und übrigens: Statt einen konkreten Containertyp zu übergeben, solltes Du entweder einen Container über Template definieren oder gleich Iteratoren übergeben. Dann wird es generisch. Es schadet ja nicht, wenn die sum Funktion mehr kann, als für den aktuellen Anwendungsfall notwendig ist. Insbesondere wenn die sum Funktio bestandteil einer Bibliothek sein soll.



  • DocShoe schrieb:

    Ohne den Code jetzt schönreden zu wollen, aber wenn das Zeugs gewachsen ist kann ich das schon nachvollziehen.

    Nachzuvollziehen, wie sowas vor zwei Jahrzehnten entstanden ist, ist das eine, aber diese Bibliothek im Jahre 2014 noch zu verteidigen braucht doch einiges an Mut 😉

    mgaeckler schrieb:

    Mir gefällt ersteres dabei besser.

    Warum? Wegen der Syntax?

    D.h. du schränkst die Berechnung des Mittelwertes auf Klassen ein, die genau dafür konzipiert wurden, und machst alle anderen inkompatibel? Wie mit Java-Interfaces?
    Und wenn du nun das Maximum berechnen willst, leitest du eine neue Klasse ab? Und für das Produkt der Elemente ebenfalls?

    Edit: hustbaer, habe erst jetzt gesehen dass du das korrigiert hast. Darum Quote geändert.



  • Nexus schrieb:

    Edit: Sorry, habe erst jetzt gesehen dass du das korrigiert hast.

    Ja, ich meinte immer die "ohne Ableitung" Variante, hatte das erst nur verwechselt.



  • tntnet schrieb:

    Wenn überhaupt dann mit const reference. Wie kommt das, dass Du eine zig Jahre an einer Klassenbibliothek arbeitest und noch nicht mal const correctness verstehst?

    Wie kommst Du darauf, daß ich das nicht verstehe?

    Der Index-operator ist leider nicht const. Das ist suboptiomal und sollte sicherlich mal geändert werden. Bin bis heute nur nicht dazu gekommen.

    <Nachtrag>
    Hab vorhin nicht genau geschaut, dachte daß sum den Indexoperator benutzt und daher selber nicht const sein kann. Daher erwartete meine zweite Variante kein const reference. sum ist aber konst, weil es für den Zugriff auf die Elemente nicht den Index.operator benutzt. Dann hätte ich natürlich eine const variante benutzen können (gar müssen).
    </Nachtrag>

    tntnet schrieb:

    Ich würde so eine Klassenbibliothek nicht weiter anschauen, wenn der Autor so wenig C++-Know-How zeigt. Entschuldige die scharfen Worte aber manchmal ist es besser direkt zu sein.

    Ich kann damit leben. Viele Designentscheidungen, die ich vor 20 Jahren getroffen habe, würde ich heute sicherlich nicht nochmal machen. Der doofe Indexoperator gehört sicherlich dazu. Wie ich schon geschrieben habe, nervt der mich auch schon eine ganze Weile. Der Leidensdruck war aber bisher noch nicht groß genug. Die meisten Anwendungen, die diesen Container verwenden, benutzen auch createElement und addElement, um neue Eintrage einzufügen.

    tntnet schrieb:

    Und übrigens: Statt einen konkreten Containertyp zu übergeben, solltes Du entweder einen Container über Template definieren oder gleich Iteratoren übergeben. Dann wird es generisch. Es schadet ja nicht, wenn die sum Funktion mehr kann, als für den aktuellen Anwendungsfall notwendig ist. Insbesondere wenn die sum Funktio bestandteil einer Bibliothek sein soll.

    Designziel der Bibliothek war ja auch nie eine eierlegende Wollmichsau bereitzustellen.



  • Nexus schrieb:

    DocShoe schrieb:

    Ohne den Code jetzt schönreden zu wollen, aber wenn das Zeugs gewachsen ist kann ich das schon nachvollziehen.

    Nachzuvollziehen, wie sowas vor zwei Jahrzehnten entstanden ist, ist das eine, aber diese Bibliothek im Jahre 2014 noch zu verteidigen braucht doch einiges an Mut 😉

    Wer verteidigt das denn? Daß hier einige Designentscheidungen doof waren und sind, habe ich nie abgestritten. Ganz im Gegenteil, das sind Punkte, die mich auch nerven.

    Nexus schrieb:

    mgaeckler schrieb:

    Mir gefällt ersteres dabei besser.

    Warum? Wegen der Syntax?

    Ja.

    Nexus schrieb:

    D.h. du schränkst die Berechnung des Mittelwertes auf Klassen ein, die genau dafür konzipiert wurden, und machst alle anderen inkompatibel? Wie mit Java-Interfaces?
    Und wenn du nun das Maximum berechnen willst, leitest du eine neue Klasse ab? Und für das Produkt der Elemente ebenfalls?

    Nein, denn dann kann ich einfach eine neue Memberfunktionen einführen.



  • mgaeckler schrieb:

    Nexus schrieb:

    Warum? Wegen der Syntax?

    Ja.

    D.h. um array.sum() statt sum(array) zu schreiben, bist du bereit, die ganze Palette an Nachteilen in Kauf zu nehmen, ohne einen einzigen echten Vorteil?
    Was sind für dich Kriterien für guten Code?
    Wenn ich nun die Summe einer Liste berechnen will, diese aber keine sum -Methode anbietet, kann ich also nicht einheitlich sum(container) schreiben?

    mgaeckler schrieb:

    Nein, denn dann kann ich einfach eine neue Memberfunktionen einführen.

    Erweiterbarkeit heisst also, dass man den Bibliotheksentwickler persönlich benachrichtigt, wenn man etwas erweitern will?
    Was machst du, wenn ich den Mittelwert von float s berechnen will?
    Oder wenn ich ein ARRAY<double> habe, muss ich das erst in ein ARRAY_OF_DOUBLES umkopieren, bevor ich den Mittelwert berechnen kann?

    Ich hoffe, dich mit den Fragen etwas zum Nachdenken anzuregen 😉



  • Es ging um Summe und Durchschnitt.
    Dazu werden Summe und Anzahl als Attribute gehalten.
    Also darum, neben der ARRAY<TYP> auch eine ARRAY_WITH_SUM<TYP> anzubieten. Könnte ein Wrapper um ARRAY<TYP> sein.



  • hustbaer schrieb:

    DocShoe schrieb:

    Ohne den Code jetzt schönreden zu wollen, aber wenn das Zeugs gewachsen ist kann ich das schon nachvollziehen.

    Das war aber nicht die Frage, die Frage war ob Interesse an der Library bestehen könnte.
    Und die Antwort darauf ist wohl nicht abhängig davon wie und warum die Library gewachsen ist.

    Nexus schrieb:

    DocShoe schrieb:

    Ohne den Code jetzt schönreden zu wollen, aber wenn das Zeugs gewachsen ist kann ich das schon nachvollziehen.

    Nachzuvollziehen, wie sowas vor zwei Jahrzehnten entstanden ist, ist das eine, aber diese Bibliothek im Jahre 2014 noch zu verteidigen braucht doch einiges an Mut 😉

    Nein, es besteht auch die Bitte um Kritik. Und wenn etwas kritisiert wird sollte man sich auch rechtfertigen dürfen, warum man das damals so gelöst hat. Einfach lapidar zu sagen "wirf alles weg und stell deinen kompletten Client Code auf STL konforme Lösungen um" kann´s ja wohl auch nicht sein. Technisch ist das sicherlich ein vernünftiger Vorschlag, aber da keiner von uns weiß, wieviel Client Code angefasst werden muss, ist er praktisch vielleicht nicht sinnvoll.

    Ansonsten gehe ich mit euch d'accord (zumindest mit Nexus & hustbaer).



  • DocShoe schrieb:

    Nein, es besteht auch die Bitte um Kritik. Und wenn etwas kritisiert wird sollte man sich auch rechtfertigen dürfen, warum man das damals so gelöst hat.

    Ganz ursprünglich stand die Frage im Raum, ob Interesse an dieser Lib besteht. Und soviel Verständnis ich auch für "historisch gewachsenen" Code habe, ist der Anspruch an eine veröffentlichte Lib doch ein ganz anderer als an eine zur Eigennutzung erstellte.



  • DocShoe schrieb:

    Nein, es besteht auch die Bitte um Kritik. Und wenn etwas kritisiert wird sollte man sich auch rechtfertigen dürfen, warum man das damals so gelöst hat. Einfach lapidar zu sagen "wirf alles weg und stell deinen kompletten Client Code auf STL konforme Lösungen um" kann´s ja wohl auch nicht sein. Technisch ist das sicherlich ein vernünftiger Vorschlag, aber da keiner von uns weiß, wieviel Client Code angefasst werden muss, ist er praktisch vielleicht nicht sinnvoll.

    Ansonsten gehe ich mit euch d'accord (zumindest mit Nexus & hustbaer).

    Du hast sicher recht, dass es für den Autor nicht sinnvoll ist, seinen kompletten Client Code anzupassen. Die Library besteht aber aus einem haufen nicht mehr zeitgemässer Designentscheidungen und daher macht es keinen Sinn, sie in dieser Form zu veröffentlichen. Warum sollte man jetzt anfangen eine Bibliothek zu verwenden, wo schon der Autor selbst sagt, dass dort viele störende Sachen zu finden sind.

    Und noch was: man könnte natürlich neben einem non-const operator[] auch einen const operator[] anbieten. Oder eine andere const Zugriffsmethode, so dass man zur Summen- oder Durchschnittsberechnung keinen lesenden Zugriff benötigt. So sieht das eben einfach unprofessionell aus.



  • Nexus schrieb:

    mgaeckler schrieb:

    Nexus schrieb:

    Warum? Wegen der Syntax?

    Ja.

    D.h. um array.sum() statt sum(array) zu schreiben, bist du bereit, die ganze Palette an Nachteilen in Kauf zu nehmen, ohne einen einzigen echten Vorteil?
    Was sind für dich Kriterien für guten Code?
    Wenn ich nun die Summe einer Liste berechnen will, diese aber keine sum -Methode anbietet, kann ich also nicht einheitlich sum(container) schreiben?

    Ich habe diese Funktion genau einmal gebraucht und würde sie, wenn ich danach suche, wahrscheinlich auch nicht so schnell finden. Wenn man das öfters braucht, sind andere Lösungen z.B. mit templates sicherlich besser.

    Nexus schrieb:

    mgaeckler schrieb:

    Nein, denn dann kann ich einfach eine neue Memberfunktionen einführen.

    Erweiterbarkeit heisst also, dass man den Bibliotheksentwickler persönlich benachrichtigt, wenn man etwas erweitern will?
    Was machst du, wenn ich den Mittelwert von float s berechnen will?
    Oder wenn ich ein ARRAY<double> habe, muss ich das erst in ein ARRAY_OF_DOUBLES umkopieren, bevor ich den Mittelwert berechnen kann?

    Für den Nutzer, der die Bibliothek nicht selbst weriterentwickelt, ist das sicherlich keine gute Lösung. Korrekt. Bedenke, bisher war Bibliotheks-Entwickler und -nutzer genau eine Person. Es war auch nicht geplant, diese Lib zu veröffentlichen, weshalb die hier angebrachten Überlegungnen bisher keine Rolle spielten.

    Nexus schrieb:

    Ich hoffe, dich mit den Fragen etwas zum Nachdenken anzuregen 😉

    Klar, deshalb habe ich dieses Dokument ja auch schon mal vorab veröffentlicht. Ein paar Sachen der Containerbibliothek werde ich wohl vorher ändern, bevor das ganze rausgeht. Der const index operator ist sicherlich das erste, was gemacht werden muß, da mich die jetztige Lösung schon lange nervt. Nach der vernichtenden (aber auch berechtigten) Kritik hier, ist das erst recht erforderlich.

    Die Containerklassen, will ich aber eh nicht so herausstellen, da hierfür der Standard normalerweise ausreichen sollte.

    Ich dachte halt eher an das Webzeugs, daß das interessant für andere sein könnte. Da hierüber gar nicht diskutiert wird, nehme ich an, daß das niemand braucht. Dann ist allerdings die Frage, ob der Aufwand für andere Änderungen (wie z.B. ARRAY_OF_DOUBLES durch template funktionen zu ersetzen) nicht eingespart werden kann und die Bibliothek nicht zu veröffentlichen.

    mfg Martin



  • tntnet schrieb:

    Und noch was: man könnte natürlich neben einem non-const operator[] auch einen const operator[] anbieten. Oder eine andere const Zugriffsmethode, so dass man zur Summen- oder Durchschnittsberechnung keinen lesenden Zugriff benötigt. So sieht das eben einfach unprofessionell aus.

    So was ähnliches gibt es schon hab's aber vergessen und sum war daher const, was ich vorhin übersehen habe. 8-(

    Ich werde auf jeden Fall einen Index-operator einführen der const sein wird und beim Überlauf eine Exception wirft und den bisherigen wahrscheinlich entfernen.

    Ich habe grundsätzlich kein Problem damit, falsche Entschedungen zu korrigieren. Kommt halt darauf an, wie lange es dauert, bis der Leidensdruck groß genug ist.

    mfg Martin



  • mgaeckler schrieb:

    ...
    Bedenke, bisher war Bibliotheks-Entwickler und -nutzer genau eine Person.
    ...

    Aha... in dem Fall würde ich mir tatsächlich überlegen, ob ein Code Refactoring nicht doch sinnvoll ist.



  • daddy_felix schrieb:

    Heute gibt es aber den Standard und heutige Programme sollten diesen auch nutzen. Warum sollte jemand bspw. Interese an deinem STRING haben, wenn er doch std::string verwenden kann?

    Ich habe mir die String-Klasse der Lib nicht angesehen, aber ich verwendet selbst eine eigene String-Klasse, die (vereinfacht ausgedrückt) ebenso auf einem selbst geschriebenen Array-Template basiert. Die meisten Funktionen zur Stringverarbeitung liegen in der Array-Klasse, warum sollte ich etwas wie "substr" nicht auch in einem Int-Array nutzen können?
    Ich bin auch kein Fan davon, dass sich der Objektorientierte Ansatz (obj.func()) und der generische Ansatz (func<T>( obj )) laufend in die Quere kommen und man erst überlegen muss, ob obj jetzt den Namensraum der Funktion func() definiert und ich func() per IDE vorgeschlagen bekomme oder ob ich func<>() erstmal finden oder halt auswendig wissen muss, ob es ein func<>() für mein obj überhaupt gibt.
    Es gibt hier kein Lösung, die nicht auch ein 'aber' besitzt.

    std::string ist in meinen Augen manchmal auch eher etwas umständlich zu verwenden. Es hat den Vorteil, dass man standardkonform ist, aber konform ist nicht immer Komfort. Arbeitet man viel mit Strings, relativiert und amortisiert sich der Mehraufwand einer eigenen Implementation.

    Mir scheint, dass es einiges an Kritikpunkten an der Lib gibt. Nichtsdestotrotz finde ich es durchaus interessant auch mal in Implementationen zu gucken, die nicht std sind. Nicht alle guten Ideen schaffen es in std und manchmal ist es auch gut, wenn man mal was anderes sieht als std, schließlich hat man auch nicht immer std-Probleme zu lösen.

    @mgaeckler: Du wirst mit einer solchen Lib nicht unbedingt viele Freunde gewinnen und ich glaube auch nicht wirklich, dass sie außerhalb Deiner Software viele Anwender finden wird. Entweder man nimmt spezielle, selbstgeschriebene Container, die man auch speziell für seine Lösung braucht, oder man hat kein spezielles Problem und sollte std nehmen.
    Dinge wie Const-Correctness würde ich auch als Mindestvoraussetzung für eine Lib ansehen. Grundsätzlich spricht aber nichts dagegen, die Lib auch mal zur 'Inspiration' zu veröffentlichen, selbst wenn Const-Correctness nicht implementiert ist.
    Es schadet nicht, wenn jemand sich Quelltext ansieht und daraus lernen kann. Man kann durchaus sehen, wie Du Container aufbaust spezialierst. Aber zum Lernen gehört zähle ich auch die Erkenntnis, dass es Dinge gibt, die man in den eigen Implementierung verbessern kann. Wenn Dinge nur perfekt wären, wenn sie std sind, dürfte die meiste Software nicht veröffentlicht werden.
    Bevor die Lib also wirklich auch eine Referenz für Deine Programmierkünste darstellen würde, solltest Du einige Dinge noch überarbeiten - ansonsten würde ich mich durchaus gerne inspirieren lassen, also mich durchaus freuen, wenn Du die Lib veröffentlichst.



  • DocShoe schrieb:

    mgaeckler schrieb:

    ...
    Bedenke, bisher war Bibliotheks-Entwickler und -nutzer genau eine Person.
    ...

    Aha... in dem Fall würde ich mir tatsächlich überlegen, ob ein Code Refactoring nicht doch sinnvoll ist.

    Es ist schon beschlossene Sache, daß die schlimmsten Designentscheidungen erst mal korrigiert werden, bevor ich die Bibliothek veröffentliche.

    An dieser Stelle möchte ich mich bei allen bedanken, für die Kritik. Vieles habe ich zwar schon vorher auch gesehen, ich hätte jetzt aber nicht gedacht, daß die Reaktionen so heftig ausfallen. Dann müsst Ihr halt noch 'ne Weile warten. 🙂

    mfg MArtin



  • Was mich wundert, ist, warum man eine 20 Jahre alte Library noch für neue Projekte verwendet.
    Ich hätte da schon längst auf std::vector/string/... umgestellt.

    Alte Projekte die weitergepflegt werden müssen muss man deswegen ja nicht anfassen. Zumindest nicht, so lange sich der "Pflegeaufwand" für diese alten Projekte in Grenzen hält.

    Und die Dinge die auch trotz Standard-Library noch nützlich sind, wie vielleicht der XML Parser, kann man entweder durch fertige Libraries ersetzen (z.B. TinyXML). Oder, wenn man sich nix fertiges findet mit dem man sich anfreunden kann, auf die Standardklassen (std::string, ...) umstellen, so dass keine Abhängigkeiten zu den alten, obsolet gewordenen STRING, ARRAY etc. Klassen mehr bestehn.

    Ich meine, wie soll man jemals lernen modernes C++ zu schreiben, wenn man immer noch alten Code weiterverwendet der voll von schlechten Designentscheidungen ist? Solchen Code zu verwenden/schreiben muss einem Schmerzen bereiten, sonst entwickelt man sich nie weiter.

    Achja, nochwas: Was die sum/average Memberfunktionen angeht: die einzige Berechtigung diese als Member auszuführen ist mMn. wenn man sie als Member performanter implementieren kann -- und das dann auch tut. Wobei die offensichtliche Möglichkeit die Summe + Anzahl immer mitzuführen bei double s eine ganz schlechte Idee ist (NaNs, Rundungsfehler etc.).


Anmelden zum Antworten