Performancemythen?



  • 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.

    Ich weiß auch nicht was Dich an der Definition so begeistert. Klar okay, sie ist einfach. Ich würde sagen, sie ist sogar so stupide trivial, dass sie sich für garnichts eignet. Das ist natürlich prima und eine wichtige Voraussetzung für eine gute Defintion. 🙄

    Aber was bringt mir diese Definition? Es geht doch darum eine ganze Menge von Techniken zu einer gemeinsamen Methodik zusammenzufassen. "Wenn virtual benutzt wird isses OOP, sonst nicht" ist zwar prima, wenn ich algorithmisch entscheiden möchte, ob ein gegebener Source OO ist. Aber das ist eigentlich nicht das was man sich von dieser Definition erhofft.

    Abgesehen davon, dass er sich ja nicht am Objekt, sondern am Typen des Objekts orientiert. Müßte es da nicht streng genommen OTOP also Objekt-Typ orientierte Programmierung heißen?

    Ich verrat's jetzt einfach mal: OOP heißt Objekt-orientierte Programmierung, weil man sich an Objekten orientiert: Sie stellen die zentrale Abstraktionsmöglichkeit bereit, Systeme werden dadurch beschrieben, welche Objekte es gibt, welches Verhalten diese modellieren und wie diese miteinander interagieren. Objekte tauchen gleichermaßen in der Modellierung wie in der Implementierung auf. Und weil sie eben bei dieser Methode so häufig vorkommen und so zentral sind heißt sie Objektorientiert.



  • Xin schrieb:

    Helium schrieb:

    Xin schrieb:

    Beschreibe den Ablauf von 'dynamisch dispatched' mal ganz detailiert.

    Meinst du den technischen Ablauf? Der ist doch von Sprache zu Sprache extrem verschieden. In statisch typisierten Sprachen habe ich ganz ander Optimierungsmöglichkeiten, z.B. mit virtuellen Methodentabellen, als z.B. in dynamisch typisierten Sprachen. Wenn ich Multimethoden unterstütze kann ich wieder anders vorgehen, jenachdem, wieviel Typinformation mir zur Compilezeit zur verfügung steht. ...

    Bei objektorientiertem Problemstellungen ist der Punkt ja eben, dass die exakte Typ-Information eben nicht zur Compilezeit zur Verfügung steht. Darum OOP, weil Multimethoden eben nicht reichen.

    Multimethoden dispatchen auch erst zur Laufzeit, da dort auch erst zur Laufzeit die Typ-Information vorhanden ist und nicht zur Compilezeit. Darum geht es doch gerade bei Multimethoden.

    Beispiel:

    (defmethod collide-with ((x asteroid) (y asteroid))
      ;; deal with asteroid hitting asteroid
    )
    (defmethod collide-with ((x asteroid) (y spaceship))
      ;; deal with asteroid hitting spaceship
    )
    (defmethod collide-with ((x spaceship) (y asteroid))
      ;; deal with spaceship hitting asteroid
    )
    (defmethod collide-with ((x spaceship) (y spaceship))
      ;; deal with spaceship hitting spaceship
    )
    

    Zur Compile-Zeit habe ich keine Typinformationen. Erst zur Laufzeit kann entschieden werden, welche der Methoden denn jetzt aufgerufen werden kann und zwar wird anhand beider Argumente dispatched.



  • Okay, hier sind Antworten für alle in einem Posting.

    Jester schrieb:

    Falls Du damit die Frage meinst warum OOP so heißt wie's heißt? Scrub hat's Dir schon gesagt. Aber Du wiederholst nur das was Du die ganze Zeit schon redest und vermutlich hat er ja auch noch bei Dir abgeschrieben. 🙄

    Nein, ich frage, warum Objekte, die nicht über virtuelle Klassen verfügen, also von statisch bearbeitet, "objekt orientiert" genannt werden, obwohl sich kein Algorithmus am Objekt orientiert.

    .filmor schrieb:

    Jester schrieb:

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

    Das hier höchstvermutlich.

    Treffer.

    asc schrieb:

    Ich würde garnicht erst versuchen mit Xin zu diskutieren, ich habe das einmal erlebt. Er hat seine Meinung und nur die gilt.

    Das hier möchte ich gerne kommentieren, denn das wird mir häufig nachgesagt.
    Es ist problemlos möglich, meine Meinung zu kippen, ich beschrieb ja auch schon, dass man nur eine Frage sinnvoll beantworten muss, um das zu erreichen.
    Der Punkt ist, dass ich mich damit seit ein paar Jahren beschäftige und in diesem Thread noch nichts gelesen habe, meine in meiner Meinung nicht berücksichtig ist. Alles auf diesen Seiten ist mir bekannt und damit auch Grund, warum ich eine andere Meinung vertrete als die Mehrzahl hier.
    Wäre ich mir mit meiner Meinung nicht so sicher, würde ich in meine Aussagen Relativierungen einbauen wie "Ich finde..." oder "Meiner Meinung nach...", um zu kennzeichnen, dass ich auch andere Ansichten akzeptiere.
    Ich heuchle auch keine Fachkompetenz, um etwas zu schreiben. Wenn ich keine Ahnung habe - zum Beispiel in diesem Thread von LISP - sage ich das und lasse mich nicht auf eine Diskussion ein. Wenn ich diskutiere, bin ich mir sehr sicher, den richtigen Standpunkt zu vertreten, weil ich ihn auf alle Eventualitäten abgeklopft habe, die mir eingefallen sind.
    Hierbei handelt es sich um eine Definition, eine Vokabel der Informatik. Hier akzeptiere ich nur eine Ansicht und wie minhen später gut zusammenfasst, hat eine große schwammige Definition nicht den Wert um eine kleine aber scharfe Definition zu ersetzen.

    asc schrieb:

    Nachtrag: Ein Hoch auf Bjarne Stroustrup, und seinen einfachen und kleinen Satz: "That said, object-oriented programming is a style of programming originating with Simula (about 40 years ago!) relying of encapsulation, inheritance, and polymorphism."
    Wofür Xin aber wiederum durchaus nützlich ist, ist für Lektürenreferenzen. Ich kann zwar bislang keiner seiner Textinterpretationen zustimmen, aber Interessantes und Neues gibt es dort immer zu finden. Und als Leseratte lehne ich nie Lektüretips nie ab.

    Vollkommen richtig. Und vermutlich meint er damit "plain classes", die er abseits dazu aufführt und vermutlich nimmt er grade deswegen ein Beispiel, dass die Verwendung von virtual aufzeigt, um OOP vorzuführen.
    Ich weiß nicht, wie Du oder der Rest Texte interpretiert, aber derzeit hört sich das so an, als würde man interpretieren mit ignorieren verwechseln. ^^

    michba schrieb:

    hui schrieb:

    Jester schrieb:

    ...sei doch ruhig wenn sich Diplominformatiker über Dinge unterhalten ...

    Arroganz++

    Obwohl es wahrscheinlich sowieso nichts bringt, darauf zu antworten: das ist für mich keine Arroganz von Jester, sondern nur die berechtigte Reaktion auf DEvents Arroganz:

    DEvent ist nicht arrogant, sondern Unwissend. Statt zu erläutern darauf rumzureiten ist für mich (Relativierung - siehe oben) arrogant. Von daher erscheint mir DEvent hier eine korrekte Antwort auf Jesters Äußerung gegeben zu haben. Ich habe Jesters Aussage da als massiv unhöflich gegenüber DEvent empfunden.

    hustbaer schrieb:

    @Xin:
    Ich möchte hier genau auf eines antworten, nämlich hierraus (sonst wird mir das zu langwierig):

    Xin schrieb:

    Benutzt man kein virtual, wird die Nachricht nicht an das Objekt geschickt, sondern an die Klasse, die auf das Objekt zeigt.

    Wo ist der Unterschied ob ich an einer bestimmten Stelle in einem Programm eine Nachricht an ein Objekt schickt oder "an seine Klasse", wenn die Klasse an der Stelle garantiert genau bekannt ist?

    Schau Dir diesen Code an, der nicht objektorientiert arbeitet:

    #include <iostream>
    
    class Tier 
    { 
      public: 
        void GibLaut() { std::cout << "Hallo!"; }   // Hier fehlt virtual, um objektorientierung zu verwenden
    }; 
    
    class Katze : public Tier 
    { 
      public: 
        void GibLaut() { std::cout << "Miau"; } 
    };
    
    int main( void )
    {
      class Tier * tier  = new Katze(); 
      tier->GibLaut();  
    }
    

    hustbaer schrieb:

    Einen Unterschied kann es IMO nur dann geben wenn man ganz auf Klassen verzichtet (denn dann KANN die Klasse des Objektes ja nicht bekannt sein, da es sie ja garnicht gibt).

    Man kann für OOP problemlos auf Klassen verzichten, allerdings verzichtet man dann auch auf die Unterstützung zu OOP von C++, da sich virtual nunmal auf Klassen bezieht.

    minhen schrieb:

    [...] Xin hat eine präzise Definition vorgebracht und diese schlüssig begründet. Seine Definition ist minimal und damit sehr aussagekräftig. Damit erfüllt sie bereits eines der wichtigsten Brauchbarkeits-Kriterien. [...]

    Dein Posting fasst sehr gut meine (wiederholten) Aussagen der letzten 12 oder mehr Seiten zusammen. Ich freue mich, dass sie wenigstens einer gelesen und verstanden hat. Das erscheint mir mit jeder weiteren Seite dieses Threads als etwas besonderes.
    Ebenfalls freut mich, dass Du Dich dem Pulk hier freiwillig entgegenstellst und sie damit ebenfalls anregst, ihre Definitionen zu verschärfen. 👍

    scrub_ schrieb:

    Xin legt einfach willkürlich fest, daß es "der Algorithmus" zu sein habe, der "sich am Objekt" orientiert.
    Übersetzt man OOP wörtlich, steht da aber als letztes "Programmierung", nicht "Algorithmus".

    Programmierung bedeutet Algorithmen zu formulieren. Man programmiert, damit sich Algorithmen um Daten (==Objekte) kümmern.

    Und eine Wiederholung dazu, da das ganze schon erklärt wurde: Würde man OOP daran ausrichten, dass sich der Programmierer an Objekten orientiert, ist absolut alles objektorientiert, was mit Objekten ("irgendein Ding", z.B. char, int, double..., aber eben nicht void) arbeitet. Dazu gehören Assembler, C, Bash-Programmierung, usw.
    Eine OOP-Unterstützung der Frage ist, ist wenn sich der Programmierer an Daten orientiert, in definitiv allen Sprachen gegeben.

    Darum ist meine Festlegung nicht willkürlich, sondern zielgerichtet.

    asc schrieb:

    minhen schrieb:

    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.

    Falsch, es gibt keine OO-Sprachen, es gibt Sprachen, die OO unterstützen (z.B. C++) und es gibt Sprachen, die OO fordern (z.B. Java) und es gibt Sprachen, die das OO nicht unterstützen (z.B. C).
    Und in allen Sprachen kann man strukturiert, wie auch objektorientiert programmieren.

    Jester bekommt mehr Antworten, weil er die grundlegensten Fragen stellt:

    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.

    Ich weiß auch nicht was Dich an der Definition so begeistert. Klar okay, sie ist einfach. Ich würde sagen, sie ist sogar so stupide trivial, dass sie sich für garnichts eignet. Das ist natürlich prima und eine wichtige Voraussetzung für eine gute Defintion. 🙄

    Nicht stupide, eindeutig. Sie trennt OOP von anderen Techniken, wie Klassen ("plain classes") oder Templates.

    Jester schrieb:

    Aber was bringt mir diese Definition? Es geht doch darum eine ganze Menge von Techniken zu einer gemeinsamen Methodik zusammenzufassen.

    Im Gegenteil, es geht darum, Techniken auseinander zu halten und exakt benennen zu können. Wenn Du Techniken zusammenfassen möchtest, kannst Du sagen "in C++ Techniken". Das beinhaltet OOP, "plain classes", DataHiding, RTTI, Templates und vieles mehr.

    Jester schrieb:

    "Wenn virtual benutzt wird isses OOP, sonst nicht" ist zwar prima, wenn ich algorithmisch entscheiden möchte, ob ein gegebener Source OO ist. Aber das ist eigentlich nicht das was man sich von dieser Definition erhofft.

    Ich weiß nicht, was Du Dir von einer Definition erhoffst. Ihr sagt selbst, dass eure Definition schwammig ist, also bringt sie nichts. In einem anderen Posting hier beginnt die Diskussion mit "Du musst mir erst noch erklären, was Du unter eine OOP-Sprache verstehst...". Das ist doch keine Definition, das ein einzig großes Mißverständnis.

    OOP ist nicht willkürlich definiert, man kann damit sagen, ob ein Programm OOP verwendet oder nicht. Genauso kannst Du sagen, ob Listen oder Arrays verwendet werden. Würde man das ebenso schwammig definieren, wären Arrays auch Listen, weil in beiden Fällen werden mehrere Objekte gespeichert.

    Nach eurer Definition sind Arrays eine objektorientierte Technik, weil der Programmierer sich an Objekten orientiert, wenn der Arrays erzeugt, die Objekte speichern. Die Definition von OOP macht doch keinen Sinn, wenn sie so schwammig ist, dass man alles in sie hineininterpretieren kann.

    Jester schrieb:

    Abgesehen davon, dass er sich ja nicht am Objekt, sondern am Typen des Objekts orientiert. Müßte es da nicht streng genommen OTOP also Objekt-Typ orientierte Programmierung heißen?

    Ich halte das tatsächlich für eine sinnvolle Verbesserung und werde das zur Verdeutlichung benutzen, um die Bedeutung von OOP zu erklären.



  • Helium schrieb:

    Xin schrieb:

    Helium schrieb:

    Xin schrieb:

    Beschreibe den Ablauf von 'dynamisch dispatched' mal ganz detailiert.

    Meinst du den technischen Ablauf? Der ist doch von Sprache zu Sprache extrem verschieden. In statisch typisierten Sprachen habe ich ganz ander Optimierungsmöglichkeiten, z.B. mit virtuellen Methodentabellen, als z.B. in dynamisch typisierten Sprachen. Wenn ich Multimethoden unterstütze kann ich wieder anders vorgehen, jenachdem, wieviel Typinformation mir zur Compilezeit zur verfügung steht. ...

    Bei objektorientiertem Problemstellungen ist der Punkt ja eben, dass die exakte Typ-Information eben nicht zur Compilezeit zur Verfügung steht. Darum OOP, weil Multimethoden eben nicht reichen.

    Multimethoden dispatchen auch erst zur Laufzeit, da dort auch erst zur Laufzeit die Typ-Information vorhanden ist und nicht zur Compilezeit. Darum geht es doch gerade bei Multimethoden.

    Korrekt. Aber das ist doch nur bedingt objektorientiert, da die möglichen Objekttypen zur Compilezeit bekannt sein müsen.
    Diese Technik hat man mit virtuellen Funktionen (Edit: "OOP" entfernt) ja eben entfernen wollen, schließlich wurden so in C die Fehler produziert.

    Helium schrieb:

    (defmethod collide-with ((x asteroid) (y asteroid))
      ;; deal with asteroid hitting asteroid
    )
    (defmethod collide-with ((x asteroid) (y spaceship))
      ;; deal with asteroid hitting spaceship
    )
    (defmethod collide-with ((x spaceship) (y asteroid))
      ;; deal with spaceship hitting asteroid
    )
    (defmethod collide-with ((x spaceship) (y spaceship))
      ;; deal with spaceship hitting spaceship
    )
    

    entspricht:

    void collide_with( SpielObjekt & lhs, SpielObjekt & rhs )
    {
      if( typeid( lhs ) == typeid( asteroid ) && typeid( rhs ) == typeid( asteroid )
        ;; deal with asteroid hitting asteroid
    
      if( typeid( lhs ) == typeid( asteroid ) && typeid( rhs ) == typeid( spaceship )
        ;; deal with asteroid hitting spaceship
    
      if( typeid( lhs ) == typeid( spaceship ) && typeid( rhs ) == typeid( asteroid )
        ;; deal with spaceship hitting asteroid
    
      if( typeid( lhs ) == typeid( spaceship ) && typeid( rhs ) == typeid( spaceship )
        ;; deal with spaceship hitting spaceship
    }
    

    Sobald man Raketen hinzufügt, muss collide_with verändert werden und collide-with kann auch nicht mehr auflösen.
    Löst man das ganze mit OOP, also virtuellen Funktionen auf, ergibt sich an collide_with keine Änderung.

    Erkennst Du nun den Unterschied?

    EDIT: Ich möchte noch hinzufügen, dass Multimethoden sich natürlich am Objekt orientieren => sie sind objekt orientiert. Sie stellen allerdings eine begrenzte Technik dar, die - weil die Typen zur Compilezeit bekannt sein müssen. Sie ist also davon abhängig, dass die Anzahl der möglichen Typen sich nicht verändert.
    In einer Library sind sie nicht verwendbar.

    Über eine virtuelle Funktion lässt sich eine das ganze Problem besser lösen:

    void collide_with( SpielObjekt & lhs, SpielObjekt & rhs )
    {
      lhs.collide_width( rhs );
    }
    

    Asteriod kann mit Asteriod kollidieren. Kollidiert er mit etwas anderem, lässt er sich mit dem anderen kollidieren.
    Spaceship kann mit Asteriod und Spaceship kollidieren, sonst kollidiert es mit dem anderen.

    Erweitert man das Programm nun mit Raketen, so beschreibt man in Rakete, wie eine Rakete mit Asteroiden, Spaceships und Raketen kollidiert. Ansonsten sind nirgendwo Änderungen im Code erforderlich, weil der Code sich vollkommen am Objekt orientieren kann, ohne vom Typ des Objektes abhängig zu sein.

    Einfache OOP-Techniken, wie diese, haben in C viele Fehler verursacht, weil an einzelnen Stellen vergessen wurde, den Code zu erweitern.



  • Xin schrieb:

    Sobald man Raketen hinzufügt, muss collide_with verändert werden und collide-with kann auch nicht mehr auflösen.
    Löst man das ganze mit OOP, also virtuellen Funktionen auf, ergibt sich an collide_with keine Änderung.

    Erkennst Du nun den Unterschied?

    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.

    Das Ergebnis ist dann, dass du nichtmehr eine dispatch funktion hast, sondern für jede Klasse eine(nämlich singledispatch):

    class Asteroid;
    class SpaceShip;
    Class Rocket:public Object
    {
        public:
            virtual bool collide(const Object* o)const
            {
                 if(typeid(o)==typeid(Asteroid))
                 {
                      //collide with asteroid
                 }
                 if(typedid(o)==typeid(SpaceShip)
                 {
                     //collide with SpaceShip
                 }
                 if(typedid(o)==typeid(Rocket)
                 {
                     //collide with Rocket
                 }
            }
    };
    //selbes für Asteroid und Spaceship
    ...
    
    bool collideWith(const Object* o1,const Object* o2)
    {
        return o1->collide(o2);
    }
    

    und wenn du jetzt einen Typ hinzufügst, kann keine dieser Dispatchfunktionen mehr auflösen, du musst also nicht nur die neuen Funktionen hinzufügen, nein du musst auch noch alle dispatchfunktionen anpassen(mit C++ und statischer Polymorphie ist das übrigens nur ein ",Typename" in der Typliste, dann ist der komplette doubleDispatcher wieder up to date ;)).

    Erkennst du den unterschied?

    Aber wozu mach ich mir die Mühe? mir antwortest du ja eh net 🙄



  • Xin schrieb:

    asc schrieb:

    Nachtrag: Ein Hoch auf Bjarne Stroustrup, und seinen einfachen und kleinen Satz: "That said, object-oriented programming is a style of programming originating with Simula (about 40 years ago!) relying of encapsulation, inheritance, and polymorphism."
    Wofür Xin aber wiederum durchaus nützlich ist, ist für Lektürenreferenzen. Ich kann zwar bislang keiner seiner Textinterpretationen zustimmen, aber Interessantes und Neues gibt es dort immer zu finden. Und als Leseratte lehne ich nie Lektüretips nie ab.

    Vollkommen richtig. Und vermutlich meint er damit "plain classes", die er abseits dazu aufführt und vermutlich nimmt er grade deswegen ein Beispiel, dass die Verwendung von virtual aufzeigt, um OOP vorzuführen.
    Ich weiß nicht, wie Du oder der Rest Texte interpretiert, aber derzeit hört sich das so an, als würde man interpretieren mit ignorieren verwechseln. ^^

    Stimmt, du ignorierst auch alle Sätze die Bjarne Stroustrup zwischen dem Kommentierten und den Beispiel schreibt, ebenso wie ein Teil des Kommentars als solchen (z.B. encapsulation, inheritance), wenn du OO nur und ausschließlich auf virtuell begründest.

    In the context of C++ (and many other languages with their roots in Simula), it means programming using class hierarchies and virtual functions to allow manipulation of objects of a variety of types through well-defined interfaces and to allow a program to be extended incrementally through derivation...

    Aber im Zweifel kann jeder den bereits geposteten Link folgen und seine eigenen Interpretationen von Bjarne Stroustrup's Ansichten machen (hier nochmal: http://www.research.att.com/~bs/bs_faq.html#oop).

    Mir ist ehrlich gesagt egal wie du die Begriffe Interpretation und Ignorieren verwendest, für meine Interpretation versuche ich jedenfalls möglichst den Gesamtkontekt heranzuziehen und nicht alles das was mir nicht passt zu Ingorieren. Ich habe in meinen Leben mich schon ab und zu eines besseren belehren lassen, aber ich bezweifel das du andere Ansichten auch nur in Betracht ziehst. Mir fällt da nur "Was nicht passt wird passend gemacht" oder "Brecheisenmentalität" ein.

    cu André



  • otze schrieb:

    Xin schrieb:

    Sobald man Raketen hinzufügt, muss collide_with verändert werden und collide-with kann auch nicht mehr auflösen.
    Löst man das ganze mit OOP, also virtuellen Funktionen auf, ergibt sich an collide_with keine Änderung.

    Erkennst Du nun den Unterschied?

    falsch. Wenn du vererbung verwendest, musst du jede Klasse verändern, wenn du Rakete hinzufügst.

    Sorry, ich habe die Frage vorausgesehen und war grade damit beschäftigt, das Posting entsprechend zu erweitern.

    otze schrieb:

    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.

    Das Problem verstehe ich grade nicht - das ist in C++ schließlich kein Problem und es werden weniger Abfragen benötigt als mit Multimethoden, da hier nicht die Kombination aus 2 Parametern gesucht werden muss (n*n) Möglichkeiten, sondern der erste Parameter den zweiten sucht (n) Möglichkeiten und im Zweifelsfall die Suche mit dem zweiten Parameter wiederholt werden muss (n+n) Möglichkeiten.
    Die Komplexität nimmt also ab. (Natürlich lässt sich an Multimethoden da auch was optimieren...)

    otze schrieb:

    Aber wozu mach ich mir die Mühe? mir antwortest du ja eh net 🙄

    Habe ich Dich bisher nicht ausreichend beachtet? Sorry. 😉

    asc schrieb:

    Xin schrieb:

    asc schrieb:

    Nachtrag: Ein Hoch auf Bjarne Stroustrup, und seinen einfachen und kleinen Satz: "That said, object-oriented programming is a style of programming originating with Simula (about 40 years ago!) relying of encapsulation, inheritance, and polymorphism."
    Wofür Xin aber wiederum durchaus nützlich ist, ist für Lektürenreferenzen. Ich kann zwar bislang keiner seiner Textinterpretationen zustimmen, aber Interessantes und Neues gibt es dort immer zu finden. Und als Leseratte lehne ich nie Lektüretips nie ab.

    Vollkommen richtig. Und vermutlich meint er damit "plain classes", die er abseits dazu aufführt und vermutlich nimmt er grade deswegen ein Beispiel, dass die Verwendung von virtual aufzeigt, um OOP vorzuführen.
    Ich weiß nicht, wie Du oder der Rest Texte interpretiert, aber derzeit hört sich das so an, als würde man interpretieren mit ignorieren verwechseln. ^^

    Stimmt, du ignorierst auch alle Sätze die Bjarne Stroustrup zwischen dem Kommentierten und den Beispiel schreibt, ebenso wie ein Teil des Kommentars als solchen (z.B. encapsulation, inheritance), wenn du OO nur und ausschließlich auf virtuell begründest.

    Lies doch mal die Postings...

    Eine Klasse, die virtuelle Funktionen besitzt, aber keine Basisklasse, macht keinen Sinn, richtig?
    Wenn ich also für virtual die Fahne schwenke, dann setzt das Vererbung voraus, den sonst gäbe es keine unterschiedlichen, aber verwandten Objekttypen, an denen man sich orientieren müsste. Man könnte direkt alles statisch machen und auf OOP verzichten.

    Auf die Notwendigkeit von Vererbung habe ich bereits mehrfach hingewiesen. ^^
    Das die Daten klassifiziert und damit zusammengefasst werden müssen... muss darauf wirklich noch hingewiesen werden? Und wenn ja, auch das ist bereits geschehen.

    asc schrieb:

    [...]für meine Interpretation versuche ich jedenfalls möglichst den Gesamtkontekt heranzuziehen und nicht alles das was mir nicht passt zu Ingorieren. Ich habe in meinen Leben mich schon ab und zu eines besseren belehren lassen, aber ich bezweifel das du andere Ansichten auch nur in Betracht ziehst. Mir fällt da nur "Was nicht passt wird passend gemacht" oder "Brecheisenmentalität" ein.

    Mir fällt nur auf, dass Du Teile meiner Postings ignorierst, sonst wäre die vorherige Frage nicht möglich gewesen.
    Wenn Du Dich also in Deinem Leben belehren lassen möchtest, dann solltest Du weniger ignorieren.



  • Xin schrieb:

    Programmierung bedeutet Algorithmen zu formulieren. Man programmiert, damit sich Algorithmen um Daten (==Objekte) kümmern.

    Ok, wir merken uns: Objekte fallen vom Himmel, denn Klassen werden nicht programmiert.

    Xin schrieb:

    Würde man OOP daran ausrichten, dass sich der Programmierer an Objekten orientiert, ist absolut alles objektorientiert, was mit Objekten ("irgendein Ding", z.B. char, int, double..., aber eben nicht void) arbeitet.

    Seit wann sind Zahlen Objekte? Ganz primitiv und einfältig: Katzen habe ich schonmal angefaßt, Zahlen nicht. Wenn die Sonne nicht so weit weg und so warm wäre, könnte ich die auch anfassen.
    Ich behaupte mal, ohne es zu beweisen: Zahlen kannst Du nicht anfassen- was ein Widerspruch zur Aussage steht, sie seien Objekte.

    Xin schrieb:

    Nach eurer Definition sind Arrays eine objektorientierte Technik, weil der Programmierer sich an Objekten orientiert, wenn der Arrays erzeugt, die Objekte speichern. Die Definition von OOP macht doch keinen Sinn, wenn sie so schwammig ist, dass man alles in sie hineininterpretieren kann.

    Deine Interpretation ist einfach mutwillig falsch. Von objektorientierter Technik hat niemand geredet. Und außerdem ist es natürlich im Sinne "meiner" Definition objektorientiere Programmierung, einen Array von Objekten anzulegen- aber das hängt nicht am Array.



  • 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.



  • Xin schrieb:

    Korrekt. Aber das ist doch nur bedingt objektorientiert, da die möglichen Objekttypen zur Compilezeit bekannt sein müsen.
    Diese Technik hat man mit virtuellen Funktionen (Edit: "OOP" entfernt) ja eben entfernen wollen, schließlich wurden so in C die Fehler produziert.

    Helium schrieb:

    (defmethod collide-with ((x asteroid) (y asteroid))
      ;; deal with asteroid hitting asteroid
    )
    (defmethod collide-with ((x asteroid) (y spaceship))
      ;; deal with asteroid hitting spaceship
    )
    (defmethod collide-with ((x spaceship) (y asteroid))
      ;; deal with spaceship hitting asteroid
    )
    (defmethod collide-with ((x spaceship) (y spaceship))
      ;; deal with spaceship hitting spaceship
    )
    

    entspricht:

    void collide_with( SpielObjekt & lhs, SpielObjekt & rhs )
    {
      if( typeid( lhs ) == typeid( asteroid ) && typeid( rhs ) == typeid( asteroid )
        ;; deal with asteroid hitting asteroid
    
      if( typeid( lhs ) == typeid( asteroid ) && typeid( rhs ) == typeid( spaceship )
        ;; deal with asteroid hitting spaceship
    
      if( typeid( lhs ) == typeid( spaceship ) && typeid( rhs ) == typeid( asteroid )
        ;; deal with spaceship hitting asteroid
    
      if( typeid( lhs ) == typeid( spaceship ) && typeid( rhs ) == typeid( spaceship )
        ;; deal with spaceship hitting spaceship
    }
    

    Sobald man Raketen hinzufügt, muss collide_with verändert werden und collide-with kann auch nicht mehr auflösen.
    Löst man das ganze mit OOP, also virtuellen Funktionen auf, ergibt sich an collide_with keine Änderung.

    Erkennst Du nun den Unterschied?

    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.



  • otze schrieb:

    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.

    Das Problem verstehe ich grade nicht - das ist in C++ schließlich kein Problem und es werden weniger Abfragen benötigt als mit Multimethoden, da hier nicht die Kombination aus 2 Parametern gesucht werden muss (n*n) Möglichkeiten, sondern der erste Parameter den zweiten sucht (n) Möglichkeiten und im Zweifelsfall die Suche mit dem zweiten Parameter wiederholt werden muss (n+n) Möglichkeiten.
    Die Komplexität nimmt also ab. (Natürlich lässt sich an Multimethoden da auch was optimieren...)

    Es sind auch bei Multimethods immer n+n möglichkeiten:

    void multimethod(const Foo* a,const Foo* b)
    {
        if(typeid(a)==typeid(Bar))
        {
             if(typeid(b)==typeid(Bar)
             {
                 callBarBar(a,b)
             }
             if(typeid(b)==typeid(FuBa)
             {
                 callBarFuBa(a,b)
             }
             ...
        }
        if(typeid(a)==typeid(FuBa))
        {
             if(typeid(b)==typeid(Bar)
             {
                 callFuBaBar(a,b)
             }
             if(typeid(b)==typeid(FuBa)
             {
                 callFuBaFuBa(a,b)
             }
             ...
        }
        ...
    };
    


  • 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.


Anmelden zum Antworten