Performancemythen?



  • camper schrieb:

    Xin schrieb:

    .filmor schrieb:

    Jester schrieb:

    Ich bestreite den Faktor 5-10. Her mit den Sourcen, dann schaun wir weiter.

    Das hier höchstvermutlich.

    Treffer.

    hashmap (in C) vs. map (in C++) ? Das dürfte wohl kaum als äquivalent gelten... bei hinreichender Skrupellosigkeit ist sowieso alles beweisbar.

    C-Funktionalität gegen C++-Funktionalität.
    Was wird der Otto-Normal-Programmierer verwenden?
    Wie ist die Performance, wenn man C statt C++ nimmt und normal programmiert?

    Man kann auch von beiden Sprachen eine externe Lib aufrufen, die das Problem optimal löst. Das wäre äquivalent, aber langweilig.



  • Xin schrieb:

    C-Funktionalität gegen C++-Funktionalität.
    Was wird der Otto-Normal-Programmierer verwenden?
    Wie ist die Performance, wenn man C statt C++ nimmt und normal programmiert?

    die äquivalente C funktionalität wäre aber ein selbst geschriebener RB Baum, ansonsten musst du den test halt mit deinen std::tr1::hash_maps wiederholen.

    Und ein ottonormalnutzer wird sicher keine hashmap basteln, weil die auch ein *wenig* mathematisches verständnis erfordert.



  • lol, das Problem ist, dass dadurch Datenstrukturen verglichen werden und nicht die Sprache. Wenn man Mikrobench durchführt, müssen die Algo und Datenstrukturen ähnlich sein.



  • Xin schrieb:

    C-Funktionalität gegen C++-Funktionalität.
    Was wird der Otto-Normal-Programmierer verwenden?

    👎 den Vergleich kannst du knicken. C bietet dir auch keine Hashmap in der Standard Library. Also müsste nach deiner Aussage der Otto-Normal-Programmierer in C wohl gar nichts verwenden.

    Ansonsten gibt es unsorted_map in C++...

    Wie ist die Performance, wenn man C statt C++ nimmt und normal programmiert?

    Dafür gibt es die "Abstraction Penalty Benchmarks" von Stepanov und nach dem was Stroustrup im HOPL-III schreibt, ist bei aktuellen Implementierungen der Faktor bei 1.02

    Man kann auch von beiden Sprachen eine externe Lib aufrufen, die das Problem optimal löst. Das wäre äquivalent, aber langweilig.

    Ne, man kann auch den ganzen Tag rumsitzen und sich schlechte Benchmarks überlegen um jeden Standpunkt zu beweisen... 👎



  • Man kann auch von beiden Sprachen eine externe Lib aufrufen, die das Problem optimal löst. Das wäre äquivalent, aber langweilig.

    Geht es hier um Hobby oder um professionelle Arbeit?



  • Helium schrieb:

    Nein. Deine "Übersetzung" enthält einen IMO groben Fehler: Deinen Dispatcher kann bzw. muss ich an einer Stelle erweitern. Das ganze ist folglich umständlich um neue Typen zu erweitern, da vorhandener Code geändert werden muss. Bei Multimethoden kann ich die Methoden da definieren, wo ich will, also auch da, wo ich die neue Rakete hinzufüge.
    Das heißt ich muss beim Hinzufügen von neuen Typen nichts an alten Teilen ändern, sondern tatsächlich nur hinzufügen.

    Das hilft aber nicht dabei, dass wenn man vergißt die Multimethoden zu erweitern, dass es dann trotzdem knallt.
    Und ob man nun vergißt die Multimethoden zu erweitern oder eine Funktion zu erweitern, es knallt.

    Es knallt auch, wenn man vergißt Rakete beizubringen, dass sie mit alten Objekten kollidieren kann. Richtig programmieren muss man so oder so, wenn man etwas hinzufügt muss man zwangsläufig irgendwo sinnvoll erweitern.

    Der Unterschied ist, dass man nur die Klasse beschreiben muss und nicht über Dinge außerhalb der Klasse nachdenken muss und Implementierung durch Pure Virtual Funktionen voraussetzen kann, um eine gültige Implementierung vorauszusetzen.

    Danke für das IMO... das klingt anders als "Das ist Unfug".

    Nochmals der explizit Hinweis: Ich widerspreche nicht, dass Multimethoden eine Möglichkeit zur OOP-Programmierung darstellt. Ich sehe nicht, dass sie mächtiger wären als virtuelle Funktionen - das wird das C++ Kommitee davon abhalten, sie in C++ aufzunehmen. Das Kommitee ist ja recht konservativ und zurückhaltend, was das angeht.
    Da Klassen mit pure virtual Functions die Implementierung an klar definierter Stelle verlangen können, sehe ich virtuelle Funktionen hier im Vorteil.

    Ich weiß auch nicht, wieso Multimethoden hier meiner Definition von OOP widersprechen würden.

    otze schrieb:

    dies gilt aber nur, solange die funktion kommutativ ist. In seinem buch "Modernes C++ Design" hat Alexandrescou dazu ein gutes beispiel gebracht bei dem die zu dispatchende funktion eben nicht kommutativ ist. Es sind also immer n+n möglichkeiten, und auf genau diesen Wert kommen multimethods auch.

    Kommutativität ist natürlich bei dem obigen Beispiel vorausgesetzt. Bei Operatoren, die nicht kommutativ sind, kann man aber auch mal fragen...!? Ich gebe nicht kommutativen Operatoren ein Flag mit, einfach ein Bool, ob der Aufruf der erste ist (also lhs lhs ist) oder ich mich in einem Review befinde (also lhs ursprünglich rhs war).
    Die Komplexität ist im Worst-Case also ((n-1) + (n-1) + 1) und der Worst-Case ist nicht der Regelfall.

    Wir können hier jetzt jedes Detail des Beispiels durchgehen, aber was widerspricht hier eigentlich meiner OOP-Definition?



  • Was soll das für ein Vergleich sein? Auf jeden Fall keiner OOP gegen nicht OOP, sondern eher spezielle Lösung gegen allgemeine.
    In der C Lösung nimmt er ein Array als Hashtabelle und die hash Funktion gibt genau für die Arraygröße passende Werte zurück. Die Javalösung verwendet ne Hashtabelle mit beliebiger Größe und die hash Funktion gibt Werte im int Bereich zurück.



  • Nochmals der explizit Hinweis: Ich widerspreche nicht, dass Multimethoden eine Möglichkeit zur OOP-Programmierung darstellt. Ich sehe nicht, dass sie mächtiger wären als virtuelle Funktionen - das wird das C++ Kommitee davon abhalten, sie in C++ aufzunehmen. Das Kommitee ist ja recht konservativ und zurückhaltend, was das angeht.
    Da Klassen mit pure virtual Functions die Implementierung an klar definierter Stelle verlangen können, sehe ich virtuelle Funktionen hier im Vorteil.

    Alexandrescou hat darüber einiges geschrieben. Für Codewartbarkeit ist es wichtig, dass man nur an sowenig Stellen wie möglich Code ändern muss.

    Bei der double dispatch methode wären das der dispatcher selbst(mit templates sehr schnell erledigt, ohne templates etwas haariger) und die funktionen die durch ihn aufgerufen werden. dazu kommt dann die neue Klasse und das wars.

    Mit deiner methode würde folgendes passieren: Die neue Klasse muss eine singleDispatch funktion erhalten(+die jeweiligen teilfunktionen), dann muss in jeder anderen Klasse noch dieser neue zweig zusätzlich eingebaut werden, und schlussendlich braucht jede Klasse noch die vorwärtsdeklaration der neuen Klasse. das ist ein riesiger aufwand, vorallem wenns sich nichtmehr um 3 klassen sondern um 10,15 oder mehr handelt. Mal davon ab, dass es enorm fehleranfällig ist. vergess ich in einer Klasse das erweitern, knallt es noch lange nicht, erst wenn ich versuche das Objekt der neuen klasse mit dieser Klasse zu nutzen, und das kann dauern.

    Wenn ich den multidispatcher nicht erweiter, dann krieg ich sofort ne exception um die Ohren geworfen, weil er diesen neuen Typ nicht kennt. Und wenn ich die neue funktion vergesse, krieg ich nen compilezeit error, weil der multidispatcher versucht eine funktion aufzurufen, die es nicht gibt.

    Der grund, weshalb multimethoden wahrscheinlich nicht in den Standardkommen ist desweiteren nicht, das virtual mächtiger ist, sondern hat den einfachen grund, dass man multidispatching nur sehr selten braucht, im gegensazu zu vector, set,map,fstream,function, bind... .

    Ausserdem hat ein multidispatcher als implementation in der std lib die anforderung, dass es eine typelist oder ähnliches gibt, und da variadic templates erst mit dem nächsten standard kommen, hat ein multidispatcher davor keinen Sinn.



  • rüdiger schrieb:

    Dafür gibt es die "Abstraction Penalty Benchmarks" von Stepanov und nach dem was Stroustrup im HOPL-III schreibt, ist bei aktuellen Implementierungen der Faktor bei 1.02

    Ist doch super!
    Mit 1.02 bewegt man sich - imho - aber auch am Maximum. Es wird immer einen Faktor geben und was anderes habe ich nicht behauptet. Faktor 5-10 habe ich aus dem Buch übernommen und ich habe es oft genug woanders gelesen. Wenn der Benchmark euch nicht gefällt und ihr einen habt, der besser läuft, ist das toll. Der Faktor bleibt aber trotzdem.

    Aus dem Posting, wo ich den Faktor erstmals nannte (Seite 8):

    Xin schrieb:

    Die Zahlen sind alt, die Differenz sollte inzwischen kleiner sein, aber selbst würde ein Programm 10x langsamer laufen, hilft C++ deutlich, Programme übersichtlicher und damit fehlerfreier zu gestalten. Ein Programm, dass nach 10 Stunden zum Ziel kommt ist effizienter als ein Programm, das nach 1 Stunde ein falsches Ergebnis liefert.

    Da meine Betrachtung von C++ nicht so einseitig ist, dass es 5-10 mal langsamer sein muss, habt ihr jetzt etwas belegt, was ich sofort mit Angabe des Faktors auf Seite 8 einräumte: Die Zahlen sind alt, die Differenz ist kleiner und ein Faktor größer 1 existiert trotzdem.

    Ungeachtet davon:

    Artchi schrieb:

    Man kann auch von beiden Sprachen eine externe Lib aufrufen, die das Problem optimal löst. Das wäre äquivalent, aber langweilig.

    Geht es hier um Hobby oder um professionelle Arbeit?

    Gute Frage, sind Kerningham und Pike (welcher immerhin an der Entwicklung von zwei OS beteiligt war), Hobby- oder professionell anerkannte Entwickler?

    Wenn beide den Vergleich machen und die Codes nicht optimal hinbekommen, dann frage ich mich, ob es eine Rolle spielt, ob es sich um hobby- oder professioneller Entwickler besser machen kann. Wenn Kerningham und Pike hier schon nicht optimale Sourcen verwenden, dann weiß ich nicht, ob ein normaler Professioneller, der grade 70 Zeilen Code nicht auf Optimierungsmöglichkeiten durchsucht, es besser machen würde.
    Und wenn er es nicht besser macht, weil er auf andere Dinge wert legt (und das sind nicht wenige), dann haben wir sofort wieder einen Faktor von 5-10.

    Der Part der Diskussion ging um C++ und war - wie man ebenfalls auf Seite 8 nachlesen kann - nicht auf OOP gemünzt. Nur für den Fall, dass jemand glaubt, dass gut geschriebene C++-Programme belegen im Widerspruch zu meiner OOP-Definition stehen würden.



  • Du schriebst eben, ob Sinn macht zu antworten, ich antworte Dir nicht. Darum antworte ich Dir hier. Sinn hat es eigentlich nicht, weil auch hier alles schon genannt wurde.

    otze schrieb:

    Alexandrescou hat darüber einiges geschrieben. Für Codewartbarkeit ist es wichtig, dass man nur an sowenig Stellen wie möglich Code ändern muss.

    Dem stimme ich zu.

    otze schrieb:

    Bei der double dispatch methode wären das der dispatcher selbst(mit templates sehr schnell erledigt, ohne templates etwas haariger) und die funktionen die durch ihn aufgerufen werden. dazu kommt dann die neue Klasse und das wars.

    Schön, ob Du es jetzt ausschreibst oder einen Teil davon durch ein Template erzeugen läßt, Du darfst es nicht vergessen, sonst bäng!
    Templates helfen nicht dabei, Dinge nicht zu vergessen.

    otze schrieb:

    Mit deiner methode würde folgendes passieren: Die neue Klasse muss eine singleDispatch funktion erhalten(+die jeweiligen teilfunktionen), dann muss in jeder anderen Klasse noch dieser neue zweig zusätzlich eingebaut werden,

    Posting lesen, ich habe extra drauf hingewiesen, dass ich diesbezüglich erweitert habe, damit man nicht selbst denken muss und auch die Frage nach kommutativen Operatoren ist geklärt.
    Nochmal zum mitmeißeln: Es muss nicht jede Klasse erweitert werden.

    otze schrieb:

    Wenn ich den multidispatcher nicht erweiter, dann krieg ich sofort ne exception um die Ohren geworfen, weil er diesen neuen Typ nicht kennt.

    Super. Den Anwender wird's freuen.
    Eine pure virtual Function lässt den Compiler meckern.

    otze schrieb:

    Der grund, weshalb multimethoden wahrscheinlich nicht in den Standardkommen ist desweiteren nicht, das virtual mächtiger ist

    Ich sagte nicht, dass es mächtiger ist, ich sagte, dass sie dem Compiler die Möglichkeit geben, zu meckern.



  • Xin schrieb:

    ...Wenn Kerningham und Pike hier schon nicht optimale Sourcen verwenden, dann weiß ich nicht, ob ein normaler Professioneller, der grade 70 Zeilen Code nicht auf Optimierungsmöglichkeiten durchsucht, es besser machen würde.
    Und wenn er es nicht besser macht, weil er auf andere Dinge wert legt (und das sind nicht wenige), dann haben wir sofort wieder einen Faktor von 5-10.

    Der Part der Diskussion ging um C++ und war - wie man ebenfalls auf Seite 8 nachlesen kann - nicht auf OOP gemünzt. Nur für den Fall, dass jemand glaubt, dass gut geschriebene C++-Programme belegen im Widerspruch zu meiner OOP-Definition stehen würden.

    Wenn ich mir einige C Entwickler anschaue und das was sie verbrocken könnte es auch genau andersrum (Faktor 5-10 für C++) sein. Aber Xin, du kannst gerne so weiter diskutieren, das hat etwa den Nutzen wenn man gegen eine Felswand spricht.

    Wenn man Vergleiche zieht muss man auf beiden Seiten auch Gleichwertiges gegenüberstellen.

    Ist aber egal, den egal was einer sagt wirst du es dir eh so hinbiegen wie du willst, selbst wenn es der ursprünglichen Aussage zuwieder läuft.

    cu André



  • asc schrieb:

    Xin schrieb:

    ...Wenn Kerningham und Pike hier schon nicht optimale Sourcen verwenden, dann weiß ich nicht, ob ein normaler Professioneller, der grade 70 Zeilen Code nicht auf Optimierungsmöglichkeiten durchsucht, es besser machen würde.
    Und wenn er es nicht besser macht, weil er auf andere Dinge wert legt (und das sind nicht wenige), dann haben wir sofort wieder einen Faktor von 5-10.

    Der Part der Diskussion ging um C++ und war - wie man ebenfalls auf Seite 8 nachlesen kann - nicht auf OOP gemünzt. Nur für den Fall, dass jemand glaubt, dass gut geschriebene C++-Programme belegen im Widerspruch zu meiner OOP-Definition stehen würden.

    Wenn ich mir einige C Entwickler anschaue und das was sie verbrocken könnte es auch genau andersrum (Faktor 5-10 für C++) sein. Aber Xin, du kannst gerne so weiter diskutieren, das hat etwa den Nutzen wenn man gegen eine Felswand spricht.

    Eigentlich habe ich in dem Posting auf Seite 8 so ziemlich alles gesagt - es müsste halt nur mal einer bewußt lesen:

    Xin schrieb:

    Nutzt man OOP bei Funktionsrufen, wo keine Entscheidungen zu treffen sind, so verliert man Zeit. Nutzt man OOP bei Funktionen, die objektabhängig sind, spart man Zeit oder viel Aufwand und erhält übersichtlichen Code. Man verliert in dem Fall aber keine Zeit, weil die Entscheidung muss so oder so getroffen werden. Und in der Regel wird sie schlechter implementiert, als es C++ macht. In dem Fall ist OOP mit C++ schneller.
    Man muss OOP sinnvoll und bewußt einsetzen.



  • scrub schrieb:

    Xin schrieb:

    Die freundlichen Kommentare oder dass ich das heute schon hier sagte, wird man bis dahin vergessen haben und mich weiterhin als den komischen Kerl ansehen, der sich aus unerfindlichen Gründen nicht an die Massen anpasst. Mein Verständnis hilft mir allerdings im Job, was sich in guten Zeugnissen wiederfindet, was wichtiger ist, als dass man mich im C++-Forum respektiert.

    Manchmal hat die Masse Recht, manchmal haben sogar alle Recht. Wenn Du 2 + 2 = 11 behauptest und ich 2 + 2 = 4, können wir beide Recht haben.
    Nur, weil Du eine anscheinend isolierte Meinung vertrittst, hast Du noch lange nicht Recht.

    Xin schrieb:

    Seit x Seiten warte ich auf eine Erklärung, wie die "übliche" Definition von "OOP" begründet, dass ein Algorithmus, der sich nicht am Objekt orientiert, "objektorientiert" genannt wird.

    Ganz einfach, es ist völlig wurscht, ob sich irgendwas an Objekten orientiert- der Ansatzpunkt für die "übliche" Definition ist viel einfach: Es gibt Objekte und sie werden verwendet. Das reicht bereits- kein virtual, kein sontnochwas. Keine Algorithmen, die sich an irgendwas orientieren- ich als Programmierer denke in Objekten.
    Für einen genialen Kopf wie Dich zu einfach?

    hmm also wenn der Programmierer an OOP gedacht hatte, waehrend er ein Algorithmus geschriebene hat, dann ist dieser automatisch OOP. Cool. 🕶

    Phoemuex schrieb:

    1. Die Definition, die du für OOP benutzt, ist nicht die gängige. Du nimmst einen Teil dessen, was allgemein als OOP verstanden wird (virtuelle Methoden, bzw. Polymorphie, virtuelle Methoden sind ja praktisch nur ein Implementierungsdeteil, um Polymorphie zu erreichen) und definierst das als das einzig und allein von OOP bezeichnete. Das ist aber im üblichen Sprachgebrauch nicht so. Dort ist es nämlich so, dass der Begriff OOP sehr viele verschiedene Dinge wie Kapselung, Polymorphie, Typsicherheit und vor allem die Zusammenlegung von Daten und Funktionen zu einem Datentyp bezeichnet. D.h. es existieren nicht getrennt Daten und Funktionen, sondern man schreibt eine Klasse, die sowohl die Daten als auch die Methoden, d.h. die Funktionalität der Objekte der Klasse bestimmt.

    Wieso vor allem die die Zusammenlegung von Daten und Funktionen zu einem Datentyp? An dieser Zusammenlegung ist nun wirklich nichts besonderes. Genauso wie an der Typsicherheit und der Kapselung. Es geht auch ohne, es geht auch mit. Gibt dazu genuegend Sprachen.

    otze schrieb:

    falsch. Wenn du vererbung verwendest, musst du jede Klasse verändern, wenn du Rakete hinzufügst. das ist double dispatching, und die OOP bietet dafür keine Lösung. Ausser natürlich, für die 3 Objekte reicht derselbe CollideWith algorithmus. Aber wenn man annimmt, dass Asteroid ein kreis, raumschiff ein quadrat und rocket ein Strich ist, dann brauchst du für jede kombination eine eigene methode. Und anstatt dann an einer Stelle einfach die neuen funktionen hinzuzufügen, musste es dann in jeder Klasse machen. dazu kommt, dass du dich ab dann noch damit rumschlagen kannst, dass in Raumschiff Rakete noch nicht definiert ist und du dann nochmal irgendwo ne vorwärtsdeklaration brauchst(in C++ natürlich). Ohja, nicht zu vergessen, dass du dann noch das Problem hast, dass jede Klasse erstmal rauskriegen muss, welchen genauen typ nun das übergebene objekt hat, damit dann die endgültige methode aufgerufen werden kann.

    Ich wuerde einfach den Kreis, das Quadrat und den Strich abstrahieren und ein Interface fuer vergleiche anbieten lassen.

    In Java funktioniert es doch auch, da implementiert man einfach das Comparable-Interface und schon kann jeder beliebiger Algorithmus meine Objekte sortieren, egal ob es Kreise, Quadrate oder Striche sind.



  • Xin schrieb:

    Schön, ob Du es jetzt ausschreibst oder einen Teil davon durch ein Template erzeugen läßt, Du darfst es nicht vergessen, sonst bäng!
    Templates helfen nicht dabei, Dinge nicht zu vergessen.

    nein, aber es ist ein unterschied, ob ich einmal oder 10x vergessen kann. Vorallem wenn es bei 10x nicht auffällt.

    Posting lesen, ich habe extra drauf hingewiesen, dass ich diesbezüglich erweitert habe, damit man nicht selbst denken muss und auch die Frage nach kommutativen Operatoren ist geklärt.
    Nochmal zum mitmeißeln: Es muss nicht jede Klasse erweitert werden.

    doch, es muss. wenn a.foo(b) ein anderes ergebnis liefert oder eine berechnung braucht als b.foo(a) dann muss jede Klasse erweitert werden. Und selbst wenns nicht alle sind, dann wird es nur noch komplizierter: welche methoden muss ich denn dann immer hinzufügen oder umbauen? Ist es nun ein fehler wenn eine bestimmte methode in einer Klasse fehlt oder nicht?

    otze schrieb:

    Wenn ich den multidispatcher nicht erweiter, dann krieg ich sofort ne exception um die Ohren geworfen, weil er diesen neuen Typ nicht kennt.

    Super. Den Anwender wird's freuen.
    Eine pure virtual Function lässt den Compiler meckern.

    ja, wenn es eine gibt. aber schau dir das mal an, denn das passiert bei der Lösung über die wir bisher geredet haben:

    class Bar;
    class Foo: public Object
    {
        public:
            bool collide(const Object* o)const
            {
                  if(typeid(o)==typeid(Bar)
                  {
                      //collison mit Bar berechnen
                  }
                  throw UnknownType();
            }
    };
    
    bool test_collision(const Object* o1,const Object* o2)
    {
        return o1->collide(o2);
    }
    
    class FuBa:public Object{...};
    
    int main()
    {
        Object* test1=new Foo;
        Object* test2=new FuBa;
        test_collision(test1,test2);//hier soll der compiler meckern? ich glaube nicht, xin!
    }
    

    oder willst du jetzt sogar für jede neue Klasse das Interface ändern?

    class Object
    {
        public:
           virtual bool collide(const Rocket*)=0;
           virtual bool collide(const Asteroid*)=0;
           virtual bool collide(const Starship*)=0;
    };
    

    ++Klassen_zum_ändern;
    Wobei ich mich natürlich frage wie du das zusammen mit: "Es muss nicht jede Klasse erweitert werden" laufen soll.

    otze schrieb:

    Der grund, weshalb multimethoden wahrscheinlich nicht in den Standardkommen ist desweiteren nicht, das virtual mächtiger ist

    Ich sagte nicht, dass es mächtiger ist, ich sagte, dass sie dem Compiler die Möglichkeit geben, zu meckern.

    nein, hast du nicht!

    siehe hier.

    Ich sehe nicht, dass sie mächtiger wären als virtuelle Funktionen - das wird das C++ Kommitee davon abhalten, sie in C++ aufzunehmen.



  • DEvent schrieb:

    hmm also wenn der Programmierer an OOP gedacht hatte, waehrend er ein Algorithmus geschriebene hat, dann ist dieser automatisch OOP. Cool. 🕶

    Ja, war doch garnicht so schwierig. Wobei es natürlich nicht um Algorithmen ging, und der Benutzer nicht an OOP denkt, sondern in Objekten (sie also als primäres Strukturierungsmittel einsetzt). Natürlich denkt man auch nicht nur daran, sondern verwendet sie tatsächlich so, so dass sich diese Denkweise auch im resultierenden Code niederschlägt.

    @Xin: Dir muß doch aber schon klar sein, dass zwischen einem Faktor > 1 (tatsächlich wohl 1.02) und der Angabe 5-10 wirklich Welten liegen. Du mußt auch mal an das denken was mit solchen Threads passiert... ein Anfänger liest es. Der liest boah, C ist 5-10 mal so schnell wie C++. Unter heutzutage schneller versteht man dann sowas wie naja, so Faktor 3-5. Das was dadurch entsteht sind: Performancemythen. Zumal ja inzwischen klar ist, dass schon in 2000 Äpfel mit Birnen verglichen wurden.

    Ich hatte es so verstanden, dass hier Performance-Mythen ausgemerzt werden sollen. Oder sollen wir hier lieber welche erzählen? -- Ist sicher auch nett.



  • otze schrieb:

    Posting lesen, ich habe extra drauf hingewiesen, dass ich diesbezüglich erweitert habe, damit man nicht selbst denken muss und auch die Frage nach kommutativen Operatoren ist geklärt.
    Nochmal zum mitmeißeln: Es muss nicht jede Klasse erweitert werden.

    doch, es muss. wenn a.foo(b) ein anderes ergebnis liefert oder eine berechnung braucht als b.foo(a) dann muss jede Klasse erweitert werden.

    Würdest Du bitte das Posting lesen. Ich bin aus dem Alter raus, um im Niveau "Das ist mein Sandschäufelchen" zu diskutieren, meine Güte...

    otze schrieb:

    otze schrieb:

    Wenn ich den multidispatcher nicht erweiter, dann krieg ich sofort ne exception um die Ohren geworfen, weil er diesen neuen Typ nicht kennt.

    Super. Den Anwender wird's freuen.
    Eine pure virtual Function lässt den Compiler meckern.

    ja, wenn es eine gibt.

    Wie, wenn es eine gibt?!
    Auf welchem Level willst Du hier diskutieren!?

    Wenn ich den Compiler sage, dass er mir daran erinnern soll, eine Variante für jedes Objekt anzulegen, dann gibt es eine pure virtual function. Entweder sag ich's meinem Compiler - und es gibt sie - oder es gibt sie nicht, weil ich zu blöd dafür bin.
    Wenn ich zu blöd dafür bin, die Möglichkeiten zu programmieren auch zu nutzen, dann brauche ich mich nicht wundern, wenn's knallt.
    Zu blöd zu sein, ist eine Technik, die seit vielen Jahrzehnten erfolgreich von vielen Programmieren angewandt wird - das ist nichts Neues, was uns in dieser Diskussion weiterbringt.

    otze schrieb:

    aber schau dir das mal an, denn das passiert bei der Lösung über die wir bisher geredet haben:

    [...Sourcecode...]
    
    class Object
    {
      vortual bool collide(const Object* o)const = 0;
    }
    

    Hast Du collide in Bar nicht definiert, meckert er, weil die Stelle, die Du markiert hast sonst nicht möglich wäre.
    Das ganze wird nicht kompiliert, weil der Programmierer zu blöd war und es jetzt korrigieren kann. Bei einer Multimethode läuft's bis die Exception kommt. Kommt die beim Kunden, ruft der Kunde beim Chef vom Programmierer an und das ist dann nicht nur blöd vom Programmierer, das ist auch noch blöd für den Programmierer.
    Als Programmierer bevorzuge ich virtual. Ich bevorzuge meine Blödheit zu korrigieren, bevor ich sie öffentlich mache.

    Ansonsten weise ich vorsichtig auf die Verwendung von Referenzen hin, wobei ich die Nutzung von const in einem Beispielcode schon löblich finde.

    otze schrieb:

    oder willst du jetzt sogar für jede neue Klasse das Interface ändern?

    class Object
    {
        public:
           virtual bool collide(const Rocket*)=0;
           virtual bool collide(const Asteroid*)=0;
           virtual bool collide(const Starship*)=0;
    };
    

    Du hast absolut keine Vorstellung, was OOP ist, richtig?
    Vielliecht eine vage Vermutung, aber selbst mit dem Standard-Unsinn, kann ich mir die Frage hier nicht mehr erklären.

    Komm, Du darfst das Schäufelchen haben...

    otze schrieb:

    otze schrieb:

    Der grund, weshalb multimethoden wahrscheinlich nicht in den Standardkommen ist desweiteren nicht, das virtual mächtiger ist

    Ich sagte nicht, dass es mächtiger ist, ich sagte, dass sie dem Compiler die Möglichkeit geben, zu meckern.

    nein, hast du nicht!

    siehe hier.

    Ich sehe nicht, dass sie mächtiger wären als virtuelle Funktionen - das wird das C++ Kommitee davon abhalten, sie in C++ aufzunehmen.

    Du beschwertest Dich, dass ich Dich nicht ausreichend beachten würde. Nach dem Beweis mangelndem logischen Verständnisses, solltest Du dankbar sein, überhaupt beachtet worden zu sein. Fehlt ja nur noch, dass Du in Großbuchstaben schreibst... <kopfschüttel>

    !(v > m) und !(m > v) ist kein logischer Widerspruch. Es ist sogar eine logische Aussage: v = m.

    Und ich fügte ja extra noch in meinem Posting an, dass Multimethoden OOP sind, damit keiner auf die Idee kommt, derartig unsinnige Schlussfolgerungen zu ziehen.

    Warum das bei Dir jetzt nicht klappte, wäre eine gute Möglichkeit Schlussfolgern zu üben.
    Ich hoffe, das war jetzt nicht arrogant.

    Unpassend zum aktuellen Verlauf der Diskussion: Ich hatte auf Seite 11 eine Frage gestellt, die meine Definition von OOP zum Kippen bringen könnte. Hat die jetzt schon jemand beantwortet und wenn ja wer und wo. Ich habe bisher noch nix gesehen, wäre aber interessiert.



  • interface Collide
    {
        boolean isCollide(Object b);
    }
    
    abstract class FliegendesObjekt implements Collide
    {
        public boolean isCollide(Object b)
        {
            return this.collideUnknow(b);
        }
    
        protected boolean collideUnknow(Object unknow)
        {
            return unknow.isCollide(this);
        }
    }
    
    // Raumschiff ist ein Quader.
    class Raumschiff extends FliegendesObjekt
    {
        public boolean isCollide(Object b)
        {
            if ( b instanceof Raumschiff )
            {
                Raumschiff right = (Raumschiff)b;
                // vergleiche this mit right
            }
            else if ( b instanceof Rocket )
            {
                Rocket right = (Rocket)b;
                // vergleiche this mit right
            }
            else return super.isCollide(b);
        }
    }
    
    // Rocket ist ein Strich.
    class Rocket extends FliegendesObjekt
    {
        public boolean isCollide(Object b)
        {
            if ( b instanceof Rocket )
            {
                Rocket right = (Rocket)b;
                // vergleiche this mit right
            }
            else if ( b instanceof Raumschiff )
            {
                Raumschiff right = (Raumschiff)b;
                // vergleiche this mit right
            }
            else return super.isCollide(b);
        }
    }
    
    // in 50 Jahren
    abstract class NeuesFliegendesObjekt extends FliegendesObjekt
    {
        protected boolean collideUnknow(Object unknow)
        {
            throw new UnsupportedException();
        }
    }
    
    // EnterpriseSchiff ist eine Kugel
    class EnterpriseSchiff extends NeuesFliegendesObjekt
    {
        public boolean isCollide(Object b)
        {
            if ( b instanceof Rocket )
            {
                Rocket right = (Rocket)b;
                // vergleiche this mit right
            }
            else if ( b instanceof Raumschiff )
            {
                Raumschiff right = (Raumschiff)b;
                // vergleiche this mit right
            }
            else if ( b instanceof EnterpriseSchiff )
            {
                EnterpriseSchiff right = (EnterpriseSchiff)b;
                // vergleiche this mit right
            }
            else return super.isCollide(b);
        }
    }
    

    Wie waehrs damit? Es haette den Vorteil, dass ich weitere Objekt hinzufuegen kann, ohne den ebstehenden Code aendern zu muessen.



  • Jester schrieb:

    DEvent schrieb:

    hmm also wenn der Programmierer an OOP gedacht hatte, waehrend er ein Algorithmus geschriebene hat, dann ist dieser automatisch OOP. Cool. 🕶

    Ja, war doch garnicht so schwierig. Wobei es natürlich nicht um Algorithmen ging, und der Benutzer nicht an OOP denkt, sondern in Objekten (sie also als primäres Strukturierungsmittel einsetzt). Natürlich denkt man auch nicht nur daran, sondern verwendet sie tatsächlich so, so dass sich diese Denkweise auch im resultierenden Code niederschlägt.

    Ja wie nun? Dankt man nur daran, oder macht man es auch so?



  • otze schrieb:

    Nun musst du aber auch anerkennen, dass die Gegenseite ausserhalb dem Verweis auf Standarddefinition einen schlechten Stand hat. Unsere Definition ist die eines Objektes aus dem normalen Sprachgebrauch und das Übertragen dieser Objekte und ihren abhängigkeiten auf die Ebene des Programmcodes ist nunmal nicht formal eindeutig definierbar. Das fängt schon damit an, dass der Begriff "Objekt" im allgemeinen Sprachgebrauch nicht eindeutig definiert ist:

    Ja, eure Definition basiert auf einem undefiniertem Begriff. Aber das ist schlecht. Sehr schlecht sogar. Denn von einem wissenschaftstheoretischen Standpunkt aus ist sie damit völlig unwissenschaftlich und völlig nutzlos, da völlig beliebig und völlig willkürlich. Du bezeichnest deine Argumentation als wissenschaftlich. Doch legt man wissenschaftliche Standards an ist eure Defintion wie auch manche Argumentation hier die reinste Katastrophe, der wissenschaftliche Worst-Case, pseudowissenschaftliches Vorgehen wie es leibt und lebt. "Schwammig" war lediglich die höfliche Floskel ohne Wissenschaftstheorie explizit in den Mund zu nehmen.
    Der Aufschrei ist jetzt natürlich obligatorisch, deswegen sag ich es gleich vorweg: die Begründung findet sich in meinem vorigen Beitrag. Was ich dort anführe ist nichts anderes als Wissenschaftstheorie.

    Eine wissenschaftliche Argumentation wäre entweder den Kern Xins Definition direkt anzugreifen oder alternativ eine eigene, wohldefinierte, wissenschaftliche Definition anzubieten. Ersteres unterbleibt, da, wie du selbst sagst, Xins Definition Teil deines eigenen Verständnisses von OOP ist. Zweiteres dagegen unterbleibt, da du mit schwammigen Begriffen und Konzepten arbeitest.

    Solange er aber auf diese Fälle nicht eingeht, zb warum statische Polymorphie kein OOP ist, können wir auch nicht weiter argumentieren.

    Ich zitiere mal:

    Xin schrieb:

    Shade Of Mine schrieb:

    Wenn du sagst OOP ist eine Technik die mit anderen Techniken verknüpft werden kann - was genau ist dann OOP? Datahiding kein Bestandteil der OOP? Polymorphie aber schon? Schwer zu trennen das ganze.

    Eigentlich nicht. Das Überschreiben von virtuellen Funktionen ist erforderlich, sonst könnte man nicht objektabhängig unterschiedliche Funktionen rufen. Objektorientierte Abläufe sind ist ja genau der Hintergrund, weshalb man virtuelle Funktionen überschreibt.
    Das Überschreiben von statischen Funktionen oder das Überladen beliebiger Methoden ist dafür nicht erforderlich.

    Xin schrieb:

    Shade Of Mine schrieb:

    In C++ und Java sieht man eben nur einen kleinen Teil der OOP. Wobei du halt auch dort Teile der OOP die sich nicht miteinander schneiden ignorierst. zB statische Polymorphie - aber wo trennt man da?

    Überladene Funktionen sind Funktionen gleichen Namens aber unterschiedlicher Signatur. Sie sind damit vom Compiler problemlos zu unterscheiden. Statische Funktionen sind grundsätzlich nicht objektorientiert, sie sind eben statisch. Und sie bleiben statisch, wenn sie in einem anderen Namespace liegen. Ich sehe da eine ganz klare Grenze, die absolut keine Frage läßt: nicht OOP.

    Das sind, bedenkt man Xins Verständnis eines Objekts und der Orientierung (was er beides bereits mehrmals wiederholt hat), schlüssige und einwandfreie Antworten, weshalb statische Polymorphie keine OOP ausmacht.
    Es fragt sich also wer hier wessen Aussagen ignoriert ...

    asc schrieb:

    minhen schrieb:

    Eine Sprache ist also dann objektorientiert, wenn sie die drei Konzepte ... direkt unterstützt. Unterstützung bedeutet, dass entsprechende Hilfsmittel in der Sprache verfügbar sind... Direkt kann nur bedeuten, dass diese Hilfsmittel unmittelbarer Bestandteil der Sprache sein müssen. Folglich macht weder die Möglichkeit Objekt-Orientierung selbst zu bauen noch eine externe, objektorientierte Library eine Sprache objektorientiert.

    Die logische Konsequenz ist, dass man keine objekt-orientierte Sprache benötigt um objekt-orientiert zu programmieren.

    Also irgendwie wiedersprichst du dir hierbei. Wenn ich deinen ersten Abschnitt betrachte würde mir als logische Konsequenz nur bleiben zu sagen: Um OOP zu betreiben bedarf es einer OO-Sprache.

    Nein. OO ist nach Stroustrup die eine, OOP die andere Sache. Mein vorletzter Satz räumt dabei implizit die mögliche Existenz von OOP in Nicht-OO-Sprachen ein. Eine konkrete Existenzaussage wird nicht getroffen, es wird aber sehr wohl die Möglichkeit eingeräumt. Daraus folgt natürlich, dass OOP auch ohne OO-Sprache möglich ist.

    Jester schrieb:

    minhen schrieb:

    Darüber hinaus hat Xin sogar erklärt weshalb er "Standard-Referenzen" nicht einfach so akzeptiert - und zwar mit Grundregeln der Logik.

    Das ist schlicht nicht wahr. Aber das kann ja jeder selbst nachlesen.

    Mir lügen zu untestellen, nur weil du die entsprechende Aussage von Xin ignorierst, vergessen oder nicht verstanden hast, ist nicht nur ausgesprochen arrogant sondern auch dreist.

    Aber ich will ja nicht so sein:

    Xin schrieb:

    Mir bedeutet Logik etwas. Daran halte ich mich. Solange Du nicht mehr zu bieten hast als "Ich stimme nicht zu" und in Deinen Quellen nicht das "Warum" zitieren kannst, bedeutet mir Dein Wort genausowenig wie die Links.

    Um das zu verstehen muss man natürlich Logik und Argumentation kennen. Wenn man Xin also etwas vorwerfen kann, dann, dass er "zuviel" Wissen voraussetzt. Zum Thema Logik und Argumentation:
    Die Wahrheit einer Aussage ist davon logisch unabhängig wer sie tätigt.
    Die Wahrheit einer Aussage ist davon logisch unabhängig wieviele sie für wahr oder falsch halten.
    Das sind Grundregeln der Logik in der Argumentation und auf diese beruft sich Xin hier ziemlich eindeutig.



  • Xin, du zeigst grad herrliche sturheit, und eine enorme fähigkeit das problem zu verkennen. Ich werde deine beleidigungen ignorieren, und einfach weitermachen.

    Würdest Du bitte das Posting lesen. Ich bin aus dem Alter raus, um im Niveau "Das ist mein Sandschäufelchen" zu diskutieren, meine Güte...

    Ja, ich habs gelesen. Ich weis nicht, was es mit Sandschäufelchen zu tun hat, aber ok. Fakt ist, du brauchst im zweifel 2 algorithmen. Wenn du sie nun in 1 funktion propfst ist das zwar sehr zweifelhaft, aber irgendwie kann man das sicher zurechtbiegen. Wichtig ist aber in dem Zusammenhang, dass für einen leser des codes nicht ersichtlich ist, ob ein bestimmter algo nun in collide fehlt, weil er vergessen wurde, oder ob er fehlt weil er in einer anderen Klasse drin steckt. Er muss also in jedem Fall beide Klassen anschauen um diese Frage zu beantworten. bei multimethoden steht das alles direkt untereinander in einer einzelnen Datei.

    class Object
    {
      vortual bool collide(const Object* o)const = 0;
    }
    

    Hast Du collide in Bar nicht definiert, meckert er, weil die Stelle, die Du markiert hast sonst nicht möglich wäre.

    Darum geht es aber nicht. Wenns collide nicht gibt knallts, das ist klar.
    Aber du musst dran denken, dass du Collide erweitern musst, darum und um nichts anderes, und kein pure virtual wird dich davor retten. Auch der Compiler wird dir nicht sagen, dass ein if zweig fehlt für den fall, dass du Rocket neu deklariert hast und Asteroid::collide noch keinen test für rocket besitzt(oder Rocket kein Test für Asteroide, oder irgendeine der beiden Klassen ein collide für beide Fälle). Für genau diesen Fall brauchst auch du eine exception. Dein Nachteil ist, dass du nicht sicher sein kannst, wann die exception geworfen wird, denn dieser Fall dass Asteroide und Rocket kollidieren muss erstmal auftreten. bei multimethods kann diese exception aber garnicht auftreten.
    Schau dir nochmal den von mir geschriebenen Code an, und du wirst das Problem selbst erkennen.

    Ansonsten weise ich vorsichtig auf die Verwendung von Referenzen hin, wobei ich die Nutzung von const in einem Beispielcode schon löblich finde.

    nö, muss ich nicht. referenzen sind in einer polymorphen umgebung meistens hinderlich und für container brauchst du eh pointer. Mal davon ab brauchst du mir wohl nicht zu erklären, wie man C++ programmiert, danke.

    otze schrieb:

    oder willst du jetzt sogar für jede neue Klasse das Interface ändern?

    class Object
    {
        public:
           virtual bool collide(const Rocket*)=0;
           virtual bool collide(const Asteroid*)=0;
           virtual bool collide(const Starship*)=0;
    };
    

    Du hast absolut keine Vorstellung, was OOP ist, richtig?
    Vielliecht eine vage Vermutung, aber selbst mit dem Standard-Unsinn, kann ich mir die Frage hier nicht mehr erklären.

    Komm, Du darfst das Schäufelchen haben...

    http://de.wikipedia.org/wiki/Sarkasmus

    Dass du mir btw sone Designkatastrophe zutraust, spricht Bände 😉

    @DEvent

    Wie waehrs damit? Es haette den Vorteil, dass ich weitere Objekt hinzufuegen kann, ohne den ebstehenden Code aendern zu muessen.

    wir haben darüber shcon gesprochen, oder das ist ATM Xins position. Aber deine Implementation hat den Nachteil, dass sie bei nicht kommutativen funktionen nicht funktioniert. dafür brauchst du dann einen weiteren parameter der angibt, welches Objekt nun das aufrufende ist, und musst daran dann wieder unterscheiden. Auf diese Weise funktioniert es dann, aber ist fehleranfällig. Was ist, wenn ein Programmierer eine kollision vergisst oder ein vorhandenes Objekt das kollidieren kann nicht kennt und diese kollision dann auftritt?
    In dem Fall kommts bei dir zu einer endlosschleife, weil er andauernd die Parameter versucht zu tauschen um eine passende funktion zu finden(mit parameter kannste das testen, aber dann musst du eine exception werfen, und eben die will Xin ja nicht haben).

    Bei multimethods, zumindest wie sie in C++ implementiert werden können, gibts zur compilezeit den Fehler.


Anmelden zum Antworten