Performancemythen?



  • scrub schrieb:

    Xin schrieb:

    Für wau() und miau() braucht man kein OOP. Abstrahiert man das Problem, hat es allerdings Sinn eine abstrakte Form von wau() und miau() virtuell zu gestalten.

    Bereits an dem Punkt scheiden sich beide Erklärungsvarianten: Gemäß den mir bekannten Definitionen ist es bereits objektorientiert, wenn ich eine Klasse "Katze" schreibe, der ich bestimmte Eigenschaften (Rasse, Geschlecht) und Funktionen (Fell abziehen, toasten) zuordne.

    Das ist exakt die Frage, die ich hustbaer gestellt habe.
    Wenn Du eine Klasse als Namespace nutzt, kannst Du eigentlich auch die ungarische Notation verwenden und gleich C verwenden:

    katze_miau( struct Katze * );
    

    Du gewinnst nichts. Es ist wahrscheinlich, dass das Programm in der C-Variante sogar schneller wird.

    scrub schrieb:

    Es ist hingegen nicht erforderlich, "Katze" von "Tier" abzuleiten oder ähnliches.
    Ein ähnlicher Gedankengang, prinzipiell gesehen, steckt übrigens hinter Entgegnungen anderer wie "schon die Voraussetzungen sind falsch".

    Ich stimme ich, dass hier ein ähnlicher Gedankengang vorliegt und ich hoffe, das auch Jesper Deine Argumentation über die Deine letzten Postings liest und kommentiert.

    Wo liegt für Dich denn der Sinn objektorientiert zu arbeiten, wenn es das Programm dadurch eventuell langsamer wird und Du nur einen einzigen Datentyp hast, an dem Du Dich orientieren kannst?

    Weiterhin haben schon einige Leute nach meinem Reply auf hustbaers Posting geschrieben, aber keiner hat bisher meine Frage zu eurer Vorstellung beantwortet.



  • Xin schrieb:

    tier.Tier::Funktion( typ Parameter )
    

    Das unterscheidet sich von

    tier_Funktion( Tier * tier, typ Parameter )
    

    nicht. Die Methode heißt Tier::Funktion( Tier *, typ ). Wo ist der Unterschied zu "tier_Funktion( Tier *, typ )?

    Der Unterschied ist ganz einfach, und genau das habe ich doch schon (implizit) gesagt: Die erste Funktion ist ganz eindeutig mit dem Objekt verbunden. Im zweiten Fall gibt es jedoch "irgendwo" "irgendeine" Funktion, die man selbst, ohne, daß man es im Quelltext vorher sieht, mit dem Tier in Verbindung bringen muß.
    Und um das nochmal ganz klar zu sagen: Bereits diese Zuordnung ("mit Objekten der Klasse 'Katze' kann die Funktion 'Fell abziehen' durchgeführt werden") ist Objektorientierung. Im Sinne der Definitionen ... und so weiter.
    Desweiteren würde ich mich im Fall 1 einfach darauf verlassen (dürfen), daß die Funktion des Tiers keinen Unfug anstellt. In Fall 2 mag die Funktion möglicherweise durch ihren Namen andeuten, was sie machen soll- aber darauf verlassen würde ich mich nicht.

    Im Übrigen kann ich weder Java noch C#.



  • Shade Of Mine schrieb:

    Xin schrieb:

    Ich sehe diese Diskussion ähnlich, ich bezweifle dass jemand eine nachvollziehbare Begründung finden wird, warum ein Algorithmus, der sich eben nicht am Objekt orientiert, weil virtual fehlt, als objektorientiert zu bezeichnen wäre.

    Erklär mir mal kurz ob du folgendes System als OO betrachtest - es ist teil einer Ajax Library die ich verwende.

    Es gibt Objekte vom Typ "XHR" diese beinhaltet grundlegende Fähigkeiten um mit anderen Servern über HTTP zu kommunizieren. Darunter die funktion "call" um eine Remote Funktion aufzurufen.

    Dann gibt es Objekte vom Typ "FooXHR" der die gleichen Methoden beinhaltet wie "XHR". Darunter auch eine "call" Funktion die aber etwas komplexer ist und Daten per JSON codiert und decodiert um komplexe Funktionsaufrufe zu ermöglichen - die Signatur von FooXHR::call und XHR::call ist gleich.

    Es gibt auch Objekte vom Typ BarXHR, wo die call Funktion die Daten mit etwas komplett anderen codiert. Und wenn ich will kann ich weitere Objekte erstellen die wieder die Daten komplett anders codieren.

    Ich denke das würde man als OO Design ansehen, oder?

    Das kommt drauf an, ob die Objekte von einander abhängig sind. Wenn sie von einander abhängig sind und über eine standardisierte Schnittstellenklasse verfügen, über die man die Funktionen erreichen kann, spricht das für OOP, da die Schnittstelle ja abhängig vom Objekttyp die Funktionen aufruf:
    Wenn bla vom Typ "Schnittstelle XHR" ist und bla.Snafu() die Funktion FooXHR.Snafu() aufruft, weil das Objekt auf das bla referenziert ein FooXHR-Objekt ist, dann ist das OOP.

    Wenn es nur drei unabhängige Datentypen sind, die zufälligerweise die gleichen Funktionsnamen haben und die dadurch austauschbar werden, dann hat das nichts mit OOP zu tun. Das geht eher in Richtung Template, womit nicht das C++-Template gleichzusetzen ist.

    Shade Of Mine schrieb:

    Das lustige dabei ist aber: es ist in JavaScript geschrieben: keine Klassen, kein Virtual.

    Das ist schade, ich würde es in OOP umschreiben, es wäre prädestiniert dafür.

    Shade Of Mine schrieb:

    Ein anderes Beispiel sind C++ Templates. Statische Polymorphie 😉

    Beispiel wofür?

    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.

    Shade Of Mine schrieb:

    Ich persönlich mag folgende Definition am liebsten:
    Objektorientierung ist, sich an Objekten zu orientieren.

    *lach* 😉 Die Definition ist auf den ersten Blick gar nicht mal übel.

    Sie macht aber bei genauerem Hinsehen keinen Sinn, weil alles, was nicht void ist, ein Objekt ist. Würde man sich nicht an irgendwelchen Daten orientieren, bräuchte man auch man auch keine Programme zu schreiben.



  • scrub schrieb:

    Xin schrieb:

    tier.Tier::Funktion( typ Parameter )
    

    Das unterscheidet sich von

    tier_Funktion( Tier * tier, typ Parameter )
    

    nicht. Die Methode heißt Tier::Funktion( Tier *, typ ). Wo ist der Unterschied zu "tier_Funktion( Tier *, typ )?

    Der Unterschied ist ganz einfach, und genau das habe ich doch schon (implizit) gesagt: Die erste Funktion ist ganz eindeutig mit dem Objekt verbunden. Im zweiten Fall gibt es jedoch "irgendwo" "irgendeine" Funktion, die man selbst, ohne, daß man es im Quelltext vorher sieht, mit dem Tier in Verbindung bringen muß.
    Und um das nochmal ganz klar zu sagen: Bereits diese Zuordnung ("mit Objekten der Klasse 'Katze' kann die Funktion 'Fell abziehen' durchgeführt werden") ist Objektorientierung. Im Sinne der Definitionen ... und so weiter.

    katze_fellabziehen( Katze * ) - hier ist die Zuordnung zur Katze eindeutig.
    Weiterhin ist das exakt die Signatur, die Katze::FellAbziehen( void ) im Objektfile erhalten wird.
    Es ändert sich nichts, unabhängig davon, was Du persönlich für Dich als vertrauenswürdiger oder übersichtlicher empfindest, verwurstet der Compiler beides identisch.

    scrub schrieb:

    Desweiteren würde ich mich im Fall 1 einfach darauf verlassen (dürfen), daß die Funktion des Tiers keinen Unfug anstellt. In Fall 2 mag die Funktion möglicherweise durch ihren Namen andeuten, was sie machen soll- aber darauf verlassen würde ich mich nicht.

    Darauf kannst Du Dich ebenso verlassen, wie bei bei einer Methode.
    Solange Du es nicht selbst geschrieben hast, musst Du Dich darauf verlassen, dass die Funktion ihrer Dokumentation entsprichst. Das gilt ebenso für Methoden.
    Wenn Du die Zuordnung selbst machst, musst Du Dich darauf verlassen, dass Du weißt, was Du tust und wie Du Dein Programm aufbaust - unabhängig ob Funktion oder Methode. 😉

    So, reicht langsam für heute - ich geh ins Bett.



  • Xin, das ist die beste definition von OOP die ich jemals gehoert habe.

    Klassenbasiert ist alles, was mit Datenstrukturen zu tun haben, die ausschließlich auf den aktuell verwendeten Datentyp - eben die Klasse - fixiert sind und Daten eben klassifizieren. Du könntest Dir in dem Zusammenhang kurz Gedanken machen, warum das Schlüsselwort in allen gängigen Sprachen "class" heißt und nicht "object".
    Katzen gehören zur Klasse der Tiere, welche zur Klasse der Lebewesen gehören. Bis hierhin gibt es noch nichtmal ein Objekt, keine existierende Katze, kein existirendes Tier, lediglich die Feststellung, dass derartige Objekte - sollten sie irgendwann existieren - irgendwie klassifiziert werden und dass zwischen Katzen und Tieren eine gerichtete Verbindung besteht.
    Beim Zugriff auf die Objekte orientiert sich die Sprache an der Klasse, die man zur Zeit betrachtet. Ein Tier ist eine andere Klasse als eine Katze und Tiere machen alles wie Tiere und Katzen machen alles wie Katzen. Katzen sind Tiere und eine Objekt, das als Tier aufgefordert wird etwas zu tun, interessiert sich nicht die Bohne, dass Katzen das lieber anders machen würden.
    Alles statisch, eben nicht objektorientiert, aber eben mit 'class'es klassifiziert.

    Objektorientiert wird das ganze in dem Moment, wo es eben nicht mehr um die Klasse, sondern um die Klasseninstanz - das Objekt - geht. Eine Katze ist eine Instanz der Klasse Tier und genauso eine Instanz der Klasse Lebewesen. Da jedoch nicht mehr alleine auf die Klassifizierung Wert gelegt wird, sondern man sich am wirklichen Typ der Datenstruktur - des Objektes - orientiert, verhält sich ein Objekt Katze der Klasse Tier wie eine Katze, genauso wie ein Objekt Katze der Klasse Lebewesen sich wie eine Katze verhält.
    Man arbeitet objektorientiert und damit sich das von klassenorientierter Programmierung unterscheidet, nehme man in C++ das Schlüsselwort "virtual".

    Um etwas zu klassifizieren kann man in C++ "class" nehmen. Es geht in C aber genauso gut mit "struct".
    Nur weil man der Sprache mitteilen kann, dass Funktionen einer Datenstruktur zugehörig ist, wird daraus kein OOP.
    Eine "class" ist eine Struktur mit einem eigenen Namensraum und beim Aufruf von Methoden steht das erste Argument links vom Methodennamen. Mehr ist das nicht und solange da kein virtual drin steht, ist es problemlos und ohne Aufwand in C abzubilden, weil man keine OOP Unterstützung benötigt.

    Der Link http://paulgraham.com/reesoo.html ist zwar schoen, aber da stimme ich Xin zu, dass vieles davon nicht zu OOP gehoert, bzw. OOP auch ohne diese Techniken funktioniert.

    Zu der Konstante: Es spielt keine Rolle ob ein Algorithmus k langsamer ist als ein anderer. Vielleicht vor 20 Jahren, aber doch nicht heute. Lernt man im ersten Semester bei Komplexistaetslehre (oder halt ein aehnliches Fach).

    Sprache         250MHz R1000         400 MHz Pentium II      Athlon 64 3200 
    C               0,36s                 0,30s                  0,054s 
    C++/STL/deque   2,60s (*7,22)        11,20s (*37,33)         0,395s (*7,31) 
    C++/STL/list    1,70s (*4,72)         1,50s (* 5,00)         0,247s (*4,57)
    

    Hast du auch die deque und list mit all ihren Moeglichkeiten in C nachgebildet?

    Ehm ja... die O-Notation ist ein theoretisches Werkzeug. Und man kann damit toll Algorithmen vergleichen (sogar ohne sie konkret zu implementieren). Und dass man dabei die Konstanten plattklopfen kann ist echt praktisch. Aber gerade die Konstanten sind in der Realität eben doch von Bedeutung. Die kann man da nicht einfach unter den Tisch fallen lassen. Die O-Notation hilft nicht irgendwas schneller oder langsamer zu machen.

    Bitte? Ob ein Algo also O(n) ist oder O(n^2) spielt also keine Rolle, aber hauptsache man vergisst die Konstanten nicht? Das sind diese typischen "ich hacke alles in Asm, weil da der Flaschenhals ist"-Leute die hier in RudP nach Hackertipps fragen.

    Es ging hier aber in keiner Weise um Komplexität, sondern um konkrete Laufzeit: "Faktor 5-10 langsamer" macht aus 5s Laufzeit eben 25-50s Laufzeit.
    Und dann kommt DEvent und behauptet, das wäre vollkommen bedeutungslos, indem er plötzlich Komplexität ins Spiel bringt.

    Sorry, habe ein Fehler gemacht. Ich meinte natuerlich nicht um Faktor k groesser, sondern um eine Konstante k groesser.
    Also nicht

    O(k * n) = O(n)
    O(k * n^p) = O(n^p)
    O(k * p^n) = O(p^n)
    usw.

    Das ist natuerlich falsch.
    Sondern:
    O(k + n) = O(n)
    O(k + n^p) = O(n^p)
    O(k + p^n) = O(p^n)
    usw.

    Prozedural: man hat bestimmte Funktionen/Prozeduren die man aufruft um bestimmte Dinge zu erledigen. Diesen gibt man bestimmte Parameter mit.
    Als "Auswahlkriterium" welcher Code wirklich ausgeführt wird dient der Name der Prozedur und sonst nix (ggf. noch die Signatur, wenn man Features wie Overloading verwendet).

    OO: man schickt eine Nachricht an ein Objekt. Diese Nachricht besteht aus einem "Verb" + ggf. zusätzlichen Parametern.
    Als "Auswahlkriterium" welcher Code wirklich ausgeführt wird dient das "Verb" der Nachricht + das Objekt an welches man die Nachricht geschickt hat.

    Genau das versucht ja Xin uns zu vermitteln.

    Wenn man diese Definition von OO(P) verwendet heisst das noch lange nicht dass man hier irgendwelche abstrakten Klassen, Polymorphie oder virtuelle Aufrufe braucht. Wenn ein Programm so entworfen ist dass "die Auswahl des auszuführenden Codes" immer zur Compile-Zeit erfolgen kann (ohne natürlich den "falschen" Code auszuwählen), dann ist das kein Grund warum das Programm nichtmehr "OO" wäre. Logischerweise kann man viele Dinge damit nicht machen, oder muss sie zumindest ganz anders machen als wenn man z.B. virtuelle Aufrufe verwenden würde.

    Genau das ist eben keine OOP. Weil sich die Klassen eben nur als ein Namespace verhaelt. Dem Compiler ist es total egal, ob da ein Class steht oder nicht. Tausche einfach das Class durch namespace aus, es ist das gleiche. Ebenso koentest du einfach das class durch ein Namens-Praefix austauschen.

    Jetzt sag ich Dir mal, was ich zuallermeist gehört habe und was (nicht deshalb!) sich auch logisch anhört:
    Objektorientiert ist, wenn man statt einem Haufen Daten und einem anderen Haufen Funktionen ganz klar bestimmten Daten(-typen) bestimmte Funktionen zuordnet, man also bereits im Quelltext genau sehen kann, daß miau() zur Katzenklasse und wau() zur Hundeklasse gehört- statt sich jedesmal selbst die passende Funktion rauszuschen, die man gerade braucht.
    Die Begrifflichkeiten virtueller Funktionen und der restliche Krempel, dies alles kam in diesem Erklärungen des Themas OO _nie_ vor, kein einziges Mal. Ich lese davon in Deinen Beiträgen zum ersten Mal.
    Und bevor Du jetzt wieder lospapmpst: Ich habe nicht behauptet, daß Du Unfug redest. Aber Deine Argumentationsbasis ist aus meiner Sicht relativ schmal.

    Das ist echt komische Definition. Nach dieses Definition muesste das auch OOP sein:

    namespace katze
    {
        void miau();
    }
    namespace hund
    {
        void wau();
    }
    

    Das kommt drauf an, ob die Objekte von einander abhängig sind. Wenn sie von einander abhängig sind und über eine standardisierte Schnittstellenklasse verfügen, über die man die Funktionen erreichen kann, spricht das für OOP, da die Schnittstelle ja abhängig vom Objekttyp die Funktionen aufruf:
    Wenn bla vom Typ "Schnittstelle XHR" ist und bla.Snafu() die Funktion FooXHR.Snafu() aufruft, weil das Objekt auf das bla referenziert ein FooXHR-Objekt ist, dann ist das OOP.

    Polymorphie ist ein heikles Thema in JS. Es ist moeglich eine Schnittstelle zu definieren und dann erst wenn man den Typen des Objektes kennt, zu entscheiden welche Methode aufgerufen wird.

    function Basisklasse(eigenschaft)
    {
        this.eigenschaft = eigenschaft;
        this.macheWas = basisklasseMacheWas;
    }
    
    function basisklasseMacheWas()
    {
        alert(this.eigenschaft);
    }
    
    function Katze(eigenschaft)
    {
        this.constructor(eigenschaft);
        this.macheWas = new function()
            {
                alert("katze hat: " + this.eigenschaft);
            }
    }
    Katze.prototype = new Basisklasse();
    
    katze = new Katze("Beine");
    

    Man kann aber nicht mehr von dem Objekt katze die Methode Basisklasse#machWas() aufrufen. Oder kann man? Hab ueberhaupt nichts in dieser Richtung gefunden.



  • Xin schrieb:

    Shade Of Mine schrieb:

    Das lustige dabei ist aber: es ist in JavaScript geschrieben: keine Klassen, kein Virtual.

    Das ist schade, ich würde es in OOP umschreiben, es wäre prädestiniert dafür.

    Aber warum ist es nicht OO? Das ist die essentielle Frage.
    Ich habe keine Klassen - also keine Ableitung. Aber dennoch ist FooXHR im übertragenen Sinn eine Subklasse von XHR. Es beinhaltet nämlich alle Methoden die XHR auch beinhaltet - bis auf call, welches im übertragenen Sinn überschrieben wurde und somit im übertragenen Sinn so etwas wie Polymorphie bietet.

    Lediglich dass ich die Tools wie Klasse und virtual nicht habe. Objekte vom Typ FooXHR sind einfach klone des Prototyps von XHR.

    In C++ würde man es mit Vererbung und virtuellen Funktionen machen - aber diese Features habe ich in JavaScript nicht - aber dennoch kann ich etwa die selbe Funktionalität bieten. Prototype basierte Sprachen haben eben einen Fokus auf Objekte - es gibt keine Klassen sondern nur Objekte.

    Warum ist das alles jetzt nicht OO? JavaScript bietet keine Klassen und ohne Klassen kein virtual. Dennoch ist Javascript Code sehr an Objekten orientiert.

    Shade Of Mine schrieb:

    Ein anderes Beispiel sind C++ Templates. Statische Polymorphie 😉

    Beispiel wofür?

    Dass es nicht nur Laufzeit Polymorphie gibt wie du scheinbar denkst. Standard Beispiel ist wohl:

    class Shape {
    public:
      virtual void draw()=0;
    };
    
    class Circle : public Shape{
    public:
      void draw();
    };
    
    class Triangle : public Shape{
    public:
      void draw();
    };
    
    void foo(Shape* s) {
      s->draw();
    }
    

    Das ist ein Standard Beispiel für Polymorphie, oder?
    Nun, das ganze ohne virtual und ohne vererbung:

    class Triangle {
    public:
      void draw();
    };
    
    class Circle {
    public:
      void draw();
    };
    
    template<typename Shape>
    void foo(Shape s) {
      s.draw();
    }
    

    Selbe Funktionalität, selber Inhalt - nur eben statisch gelöst.

    Shade Of Mine schrieb:

    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.

    Ziemlich auf Java/C++ fixiert von der Idee her. Wie gesagt: es gibt OO Sprachen die keine Klassen bieten. Wie kann ich ohne Klasse eine virtuelle Funktion haben? Oder sind Klassen ebenfalls für OOP nötig?

    Sie macht aber bei genauerem Hinsehen keinen Sinn, weil alles, was nicht void ist, ein Objekt ist. Würde man sich nicht an irgendwelchen Daten orientieren, bräuchte man auch man auch keine Programme zu schreiben.

    Selbst wenn alles ein Objekt wäre - meine Definition verlangt dass man sich an diesen Objekten orientiert, sprich das Objekt selber ins Zentrum schieben.

    In normalen prozedualen Code hat man natürlich auch Variablen die du vielleicht Objekte nenen willst, aber sie bestimmen nicht das Programmverhalten. Ich denke in einem OOD geht es nur darum in Objekten zu denken. Deshalb ist FILE* aus C für mich ein OOD. Und auch JavaScript ist in meinen Augen eine OO Sprache. Denn ich fixiere mich bei der Programmierung auf die Objekte - anders als zB in altem C wo man eher auf Daten und Funktionen fixiert ist.

    Ich denke es ist ein Fehler ein Feature zu nehmen und zu sagen: das ist OO. Der denn ich kenne kein einziges OO Feature ohne dem es nicht auch geht. Ich brauche keine virtuellen Funktionen um OO zu programmieren. Lisp zum Beispiel bietet keine virtuellen Funktionen an. Man hat dort stattdessen Multimethods - die aber einen ähnlichen Zweck erfüllen. Dennoch gilt Lisp als eine der ersten Objektorientierten Sprachen.

    In meinen Augen ist OOP eine Denkweise und es gibt nahezu unendlich viele Tools die es mir erleichtern dieser Denkweise im Code Ausdruck zu verschaffen. Dynamische Polymorphie ist ein Teil davon - virtual erlaubt es mir dem Objekt das Verhalten festlegen zu lassen. Die Idee ist: Ich sage object.gib_laut() und das Objekt weiß ob es jetzt bellen oder miauen soll. Ob das ganze nun über Prototypen, laufzeit polymorphie mit virtual, statische Polymorphie mit Templates, Multimethods oder funktionszeiger gelöst wurde tut der Denkweise, bzw dem was ich damit im Code Aussage nichts zur Sache.

    Denn im Prinzip sind virtual Funktionen in C++ auch nichts anderes als wenn man Funktionszeiger in C nehmen würde. Lediglich der Compiler übernimmt einem die Arbeit und bietet gewissen Komfort in der Benutzung an. Aber im Prinzip kann man das Shape Beispiel in C genauso schreiben:

    struct Shape {
      void (*draw)(Shape*);
      void* extended;
    };
    Shape create_circle() {
      Shape s;
      s.draw=circle_draw;
      s.extended=bla;
      return s;
    }
    
    Shape create_triangle() {
      Shape s;
      s.draw=triangle_draw;
      s.extended=bla;
      return s;
    }
    
    void foo(Shape s) {
      s.draw(&s);
    }
    

    Denn viel anderes macht der C++ compiler aus dem Code auch nicht. Wo setzt man nun mit der Definition an? Alles was der Compiler macht ist Magie und ich darf es nicht händisch machen damit es OO ist?

    Und was ist mit anderen Features? Warum ist virtual besser als Multimethods bzw warum ist es mehr OO? Warum brauche ich Vererbung und warum ist der Prototype Ansatz weniger OO als der Vererbungsansatz?

    Es gibt mehr Sprachen als C++ und Java. Und genauso gibt es mehrere Möglichkeiten ein Problem zu lösen. Wenn nur C++ und Java OO sind - was sind dann Lisp, JavaScript, Self,...

    Bereits in C++ und Java hat man enorme Unterschiede in der OO-Denkweise. In Java hat man zum Beispiel ein Interface Comparable für Klassen die Vergleiche zulassen. In C++ hat man die exakt selbe Funktionalität mit globalen operatoren. Ist der Comparable Ansatz jetzt mehr OO als der operator== Ansatz?



  • Das trifft es ganz gut:
    http://www.heise.de/ix/artikel/2001/04/194/

    Spricht man von der Existenz polymorpher Typen, so trifft dies in Bezug auf JavaScript nicht ganz den Punkt: Da es keine Typisierung gibt, sind alle Instanzen in gewisser Weise polymorph. Zudem ist späte Bindung unter JavaScript Standard, da stets erst zur Laufzeit ermittelt wird, an welches Objekt eine Methode gebunden wird. Das Problem liegt bei JavaScript an einer anderen Stelle: Die Sprache ist in Bezug auf Polymorphie eher zu wenig restriktiv; deshalb können durchaus Botschaften an einzelne Objekte geschickt werden, die in der Klassenhierarchie beziehungsweise Prototypenkette in keinerlei Relation stehen. Einzige Bedingung: die Instanzen bieten jene Methode an. Somit ist semantische Substituierbarkeit in diesem Kontext nur gegeben, wenn der Programmierer besondere Sorgfalt beim Einsatz von Polymorphie walten lässt und sie nicht wahllos einsetzt.

    Achja und es gibt sehr wohl Vererbung in Javascript.

    Das ist ein Standard Beispiel für Polymorphie, oder?
    Nun, das ganze ohne virtual und ohne vererbung:

    class Triangle { 
    public: 
    void draw(); 
    }; 
    
    class Circle { 
    public: 
    void draw(); 
    }; 
    
    template<typename Shape> 
    void foo(Shape s) { 
    s.draw(); 
    }
    

    Selbe Funktionalität, selber Inhalt - nur eben statisch gelöst.

    Eben nicht die selbe Funktionalitaet. Du kannst nicht, waehrend das Programm laeuft, den Typen austauschen. Du kannst es einmal vom Compiler uebersetzen und dann ist es in Stein gemeiselt.



  • DEvent schrieb:

    Achja und es gibt sehr wohl Vererbung in Javascript.

    erklär mal bitte wie

    Eben nicht die selbe Funktionalitaet. Du kannst nicht, waehrend das Programm laeuft, den Typen austauschen. Du kannst es einmal vom Compiler uebersetzen und dann ist es in Stein gemeiselt.

    Genauso kann man aber auch sagen dass Objekte in C++ nicht die selbe Funktionalität bieten wie in Java. Es fehlt zB Reflection. Ich kann in C++ zB nicht ohne Probleme eine neue Klasse laden.

    Die Frage ist: wo setzt man die Trennstriche?
    Ebenso die Polymorphie in JavaScript - klar muss der Programmierer darauf achten keine Interfacefehler zu machen - selbes gilt aber auch für C++. Die Frage ist hier: bedeutet OO dass man dem Programmierer verbietet diverse Möglichkeiten zu nutzen?

    Aber bitte, erklär mir mal warum JavaScript nicht OO ist und warum Lisp nicht OO ist. Warum ist dynamische Polymorphie essentiell für OO und statische Polymorphie nicht? Warum sind Klassen ein sinnvollerer OO Ansatz als Prototypes?

    Wäre schön wenn du mir das erklären könntest.



  • Klar ist es das Hauptziel der OOP, dass man Vererbung und Laufzeit-Polymorphie verwendet. Aber Code der nur Datenkapselung enthält ist auch OOP, weil sich das auch an den Objekten orientiert. Datenkapselung ist halt "Anfänger OOP" und Laufzeit-Polymorphie mehr "Experten OOP".

    Xin schrieb:

    Cpt. Nukem schrieb:

    Aber was macht OOP in der Praxis aus? Viel Prozent der Zeit gehen für sowas drauf? 30, 3, 0.3 oder noch weniger? Gibts dazu eine verlässliche Quelle?

    Man geht davon aus, dass ein C++ Programm 5-10mal langsamer läuft als ein entsprechndes C Programm.
    Das ist aber sehr programmabhängig, die Zahlen sind also bestenfalls wage Anhaltspunkte, ich habe sie aber schon in verschiedenen Büchern zu dem Thema gesehen. Es liegt auch nicht vorrangig an OOP, sondern an der Tatsache, dass C++ Compiler aufwendiger sind als C-Compiler, entsprechend auch die Optimierung aufwendiger wird.

    Und ohne Compiler unterschied? Wieviel machen diese paar Befehle mehr für nen virtuellen Methodenaufruf aus, im Vergleich zum restlichen Programm?



  • Cpt. Nukem schrieb:

    Und ohne Compiler unterschied? Wieviel machen diese paar Befehle mehr für nen virtuellen Methodenaufruf aus, im Vergleich zum restlichen Programm?

    0, wenn der compiler smart genug waere es auf die qualitaet von c zu optimieren, gebe es keinen unterschied.



  • Xin schrieb:

    tier.Tier::Funktion( typ Parameter )
    

    Das unterscheidet sich von

    tier_Funktion( Tier * tier, typ Parameter )
    

    nicht. Die Methode heißt Tier::Funktion( Tier *, typ ). Wo ist der Unterschied zu "tier_Funktion( Tier *, typ )?

    gibt keinen. die letztere Funktion würde man in C für genau diesen Fall nutzen. Class und alles was dazugehört ist nur ein syntaxgimmik. Der Compiler macht am Ende eh dasselbe draus(siehe Comeau, das zum Thema geschwindigkeit btw). Was am Ende zählt ist nur die Denkweise.
    OOP ist für mich ein Programmierstil, bei dem sich Objekte gegenseitig Informationen zuschieben und diese dann verarbeiten. Wie die einzelnen Objekte im jeweiligen Fall implementiert sind ist wurscht, idealerweise sind sie eh komplett austauschbar. Was ich nun als Objekt bezeichne ist von Sprache zu Sprache unterschiedlich.

    In C ist zb FILE ein gutes Objekt. man kann es öffnen, schließen, daten mit ihm ein und auslesen...

    In C++ könnte deine Tier Funktion so aussehen:

    template<class Tier,class Typ>
    tier_function(Tier,Typ){...}
    

    das ist das C++ argument gegen den overhead von virtuellen funktionen: statische polymorphie. Die Fälle in denen man Polymorphie wirklich braucht sind sehr gering. In vielen Sprachen braucht man sie aber um Objekte "zusammenstecken" zu können, also Das Klasse Foo Objekte mit dem Interface Bar nutzt um die Drecksarbeit zu erledigen.
    Ein Beispiel dafür was ich Meine ist hier: http://de.wikipedia.org/wiki/Bridge_(Entwurfsmuster)#UML-Diagramm.
    In C++ bei verwendeter statischer Polymorphie werden diese Abstrakten Interfaces nutzlos(in dem Fall vom link oben der "implementierer"), um genauer zu sein sie werden durch eine Interface absprache ersetzt. "Ich benutz methode Foo, also muss diese vom Objekt bereitgestellt werden". Mit dem nächsten Standard werden die Concepts kommen, die statische version des Abstrakten Interfaces.

    Ist dies nun weniger Polymorphie, nur weil ich den zeitpunkt änder, wann die Objekte zusammengesteckt werden? Ob ich nun zur Laufzeit eine sortiere Liste mit einer arraykern erstelle oder schon zur Compilezeit macht keinen großen Unterschied(ausser es ist zu einem dieser zeitpunkte erforderlich)



  • Das ist aber ein sehr eingeschränkter Blick auf die Objektorientierung 😉 Wenn du wirklich so wenig Unterschiede zwischen Compilierzeit und Laufzeit siehst, kannst du gleich zur Template Metaprogrammierung wechseln - das erzeugt extrem kompakte und schnelle Progamme (daß man da zur Laufzeit nichts mehr beeinflussen kann, stört ja niemanden :D).

    Der Vorteil der dynamischen Polymorphie ist ja, daß du zur Laufzeit entscheiden kannst, was für ein Objekt tatsächlich betroffen ist - du hast einen Zeiger auf ein Fahrzeug und rufst dessen Methode starte_motor() auf, dann findet der Compiler selber die richtige Methode, je nachdem ob der Zeiger auf einen PKW, ein Motorboot oder einen Jumbo-Jet zeigt. Rein statisch müsstest du dich beim Compilieren festlegen, mit was für einem Fahrzeugtyp du dich beschäftigen willst - und wenn du feststellst, daß du doch nicht mit PKWs, sondern mit Jumbo-Jets arbeiten willst, mußt du das Programm neu compilieren (vom nötigen Aufwand, um PKWs und Jets gemischt nutzen zu können, will ich gar nicht reden).

    Und um das ganze mal zusammenzufassen:
    Virtuelle Methoden sind langsamer als "reguläre" Methoden, aber flexibler - und wenn du diese Flexibilität brauchst, sind sie allemal schneller als jeder Versuch, sie von Hand nachzubauen.

    (PS: Sorry, wenn ich bereits formulierte Erkenntnisse wiederhole - ich hab' möglicherweise etwas den Anschluß verloren)



  • CStoll schrieb:

    Das ist aber ein sehr eingeschränkter Blick auf die Objektorientierung 😉 Wenn du wirklich so wenig Unterschiede zwischen Compilierzeit und Laufzeit siehst, kannst du gleich zur Template Metaprogrammierung wechseln - das erzeugt extrem kompakte und schnelle Progamme (daß man da zur Laufzeit nichts mehr beeinflussen kann, stört ja niemanden :D).

    es generiert eher aufgeblaehte programme.



  • CStoll schrieb:

    Und um das ganze mal zusammenzufassen:
    Virtuelle Methoden sind langsamer als "reguläre" Methoden, aber flexibler - und wenn du diese Flexibilität brauchst, sind sie allemal schneller als jeder Versuch, sie von Hand nachzubauen.

    Ich hab ja geschrieben: " wenn man sie wirklich braucht" und danach ein beispiel genannt, wobei sie häufig genutzt wird, ohne dass man sie wirklich braucht und gefragt, ob der C++ weg der Statischen Polymorphie in dem Fall weniger OOP ist.
    Entschuldige, wenn ich nicht ganz eindeutig war 😉



  • Wenn du es so siehst, macht es Sinn. Aber das Bridge-Pattern ist nicht wirklich ideal als Gegenbeispiel für dynamische Polymorphie 😉 (will sagen: es hängt von den Randbedingungen ab, ob du sowas statisch aufbauen kannst oder nicht)



  • DEvent schrieb:

    Ehm ja... die O-Notation ist ein theoretisches Werkzeug. Und man kann damit toll Algorithmen vergleichen (sogar ohne sie konkret zu implementieren). Und dass man dabei die Konstanten plattklopfen kann ist echt praktisch. Aber gerade die Konstanten sind in der Realität eben doch von Bedeutung. Die kann man da nicht einfach unter den Tisch fallen lassen. Die O-Notation hilft nicht irgendwas schneller oder langsamer zu machen.

    Bitte? Ob ein Algo also O(n) ist oder O(n^2) spielt also keine Rolle, aber hauptsache man vergisst die Konstanten nicht? Das sind diese typischen "ich hacke alles in Asm, weil da der Flaschenhals ist"-Leute die hier in RudP nach Hackertipps fragen.

    Liebes Kind DEvent. Bitte sei doch ruhig wenn sich Diplominformatiker über Dinge unterhalten von denen Du offensichtlich keine Ahnung hast. -- Danke!

    Zur Erinnerung zitiere ich auch noch den restlichen Unsinn den Du verzapft hast:

    DEvent schrieb:

    O(k * n) = O(n)
    O(k * n^p) = O(n^p)
    O(k * p^n) = O(p^n)
    usw.

    Das ist natuerlich falsch.
    Sondern:
    O(k + n) = O(n)
    O(k + n^p) = O(n^p)
    O(k + p^n) = O(p^n)
    usw.

    Autsch 🙄



  • Jester schrieb:

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

    Arroganz++



  • Shade Of Mine schrieb:

    Warum sind Klassen ein sinnvollerer OO Ansatz als Prototypes?

    Stell ihm erstmal die Frage, ob er Prototyp-Basierte OO kennt.

    --------

    Für mich ist der Unterschied zwischen OO und nicht OO hauptsächlich der Denkansatz.
    Habe ich Funktionen, die ich mit Objekten füttere oder sage ich den Objekten, was sie machen sollen. Einmal werden die Objekte an die Funktionen geschickt, einmal die Nachricht, was zu tun ist, an das Objekt.



  • DEvent schrieb:

    Zu der Konstante: Es spielt keine Rolle ob ein Algorithmus k langsamer ist als ein anderer. Vielleicht vor 20 Jahren, aber doch nicht heute. Lernt man im ersten Semester bei Komplexistaetslehre (oder halt ein aehnliches Fach).

    Dann stelle ich dir mal eine Frage die du mir sicher beantworten kannst, da du das ja offensichtlich im Studium gelernt hast, ich aber nicht. Mit welchem Sortieralgorithmus kann ich 4000000, 4000, 40 und 4 Werte jeweils (im Mittel) am schnellsten sortieren? Quicksort oder Bubblesort? Den radix-sort lassen wir mal weg, wäre doch etwas zu komplex jetzt...



  • DEvent schrieb:

    Xin, das ist die beste definition von OOP die ich jemals gehoert habe.

    Häh? Wow...ich bin total perplex, sowas erwartete ich in diesem Thread überhaupt nicht mehr, ich freue mich ja schon über ein "es mag schlüssig sein".

    Allerdings kannst Du nun davon ausgehen, dass eine andere Meinung als die Masse zu haben, bedeutet, dass die Masse dich für bekloppt erklärt.

    Jester schrieb:

    Liebes Kind DEvent. Bitte sei doch ruhig wenn sich Diplominformatiker über Dinge unterhalten von denen Du offensichtlich keine Ahnung hast. -- Danke!

    Devent, tröste Dich, die Wissenden stehen über den Dingen.
    Jester ist auf mein Posting von gestern nicht mehr eingegangen, das bedeutet natürlich, dass er mich ignoriert und auf gar keinen Fall, dass ich den "üblichen" wunden Punkt getroffen habe.
    Wie sieht's aus, Jester? Weißt Du, warum OOP objektorientiert heißt?

    DEvent schrieb:

    Sprache         250MHz R1000         400 MHz Pentium II      Athlon 64 3200 
    C               0,36s                 0,30s                  0,054s 
    C++/STL/deque   2,60s (*7,22)        11,20s (*37,33)         0,395s (*7,31) 
    C++/STL/list    1,70s (*4,72)         1,50s (* 5,00)         0,247s (*4,57)
    

    Hast du auch die deque und list mit all ihren Moeglichkeiten in C nachgebildet?

    Unwahrscheinlich, da man deque und list lediglich austauschte. Ich habe die Sourcen aus dem Buch genommen.
    Ich habe das Programm nicht abgeschrieben. Andererseits wird hier auch mit Austauschbarkeit argumentiert, von daher habe ich hier keine Skrupel, das auch zu nutzen.

    Einen Faktor von 4,5 kann man mit ein wenig Trickserei aber auch nicht mehr kleinhauen. Dafür muss man viel optimieren und kommt an Schluss bei C an, dann gilt aber der Vergleich OOP gegen Nicht-OOP auch nichts mehr.

    Ich fänds super, wenn Du nicht nur "quote" schreiben würdest, sondern auch, von wem Du quotest.

    Shade Of Mine schrieb:

    DEvent schrieb:

    Achja und es gibt sehr wohl Vererbung in Javascript.

    erklär mal bitte wie

    Genauso, wie in C. Wenn Du JavaScript lernen möchtest, würde ich Dir raten Tutorials zu suchen und das nicht auch noch hier rein zu packen.

    Cpt. Nukem schrieb:

    Datenkapselung ist halt "Anfänger OOP" und Laufzeit-Polymorphie mehr "Experten OOP".

    Willkommen in meiner Zitatesammlung. Der war gut.
    Sollte ich nochmals C++ unterrichten, bist Du (anonymisiert) dabei. 🙂

    Cpt. Nukem schrieb:

    Xin schrieb:

    [...Faktor 5-10...]Es liegt auch nicht vorrangig an OOP, sondern an der Tatsache, dass C++ Compiler aufwendiger sind als C-Compiler, entsprechend auch die Optimierung aufwendiger wird.

    Und ohne Compiler unterschied? Wieviel machen diese paar Befehle mehr für nen virtuellen Methodenaufruf aus, im Vergleich zum restlichen Programm?

    Habe ich auch schon geschrieben. Ein virtueller Funktionsaufruf kostet genau 2x Dereferenzieren und einmal addieren. Viele Funktionsaufrufe enthalten dann "return Zahl", was einem "Move" und eventuell einer Addition entspricht. Das allein macht bei derartigen Dingen bereits ein Verhältnis 5:2 aus.
    Dazu kommt der Aufwand, überhaupt eine Funktion aufzurufen, wo ein C-Programmierer sich sagt, für ein "return Zahl;" rufe ich keine Funktion auf. Bei der Methode bedeutet das zusätlich Stack aufbauen, Stack beschreiben, CPU-Pipe verlassen (bei alten CPUs sehr teuer, heutige Pipes handeln Funktionsaufrufe mit), Pipe wieder aufbauen, Stack auslesen, die Addition ausführen, mit "move" Zahl auf den Stack kopieren, CPU-Pipe verlassen und wieder aufbauen, Stack auslesen (Zahl aus Stack zum Ziel kopieren), Stack abbauen und endlich weiter im Programm.
    Der C-Programmierer nimmt sich die Variable aus dem aus dem Objekt, die er entsprechend dafür aufbaut. Das ist das Move und die Addition, die beiden preiswertesten Anweisungen, die hier auftauchen.
    Bevor das C++ Programm weiß, wohin es überhaupt springen soll, ist der C-Programmierer schon weiter im Programm.

    otze schrieb:

    Xin schrieb:

    Wo ist der Unterschied zu "tier_Funktion( Tier *, typ )?

    gibt keinen. die letztere Funktion würde man in C für genau diesen Fall nutzen.

    Mir erzählt doch hier jeder, dass die eine OOP ist und die andere nicht. Du bestätigst mich jetzt darin, dass es hier keinen Unterschied gibt? Sehe ich das richtig?

    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. Keiner meldet sich und sagt dazu was. otze bestätigt mich, DEvent meint, ich hätte die beste Definition, gebracht, die er je gehört hat.
    Fällt irgendjemanden auf, dass die "übliche" Definition von "OOP" hakt?

    Aber, otze, es ist gut, dass Du es wenigstens nicht als Paradigma bezeichnestest, wenn Du es schon als Programmierstil bezeichnest:

    otze schrieb:

    OOP ist für mich ein Programmierstil, bei dem sich Objekte gegenseitig Informationen zuschieben und diese dann verarbeiten.

    "Für Dich"? Hier sind C++ Experten, in diesem Forum steckt soviel Know-How, hier darf jeder eine eigene Vorstellung von OOP haben. 😉

    Oder hier:

    Hellium schrieb:

    Für mich ist der Unterschied zwischen OO und nicht OO hauptsächlich der Denkansatz.
    Habe ich Funktionen, die ich mit Objekten füttere oder sage ich den Objekten, was sie machen sollen. Einmal werden die Objekte an die Funktionen geschickt, einmal die Nachricht, was zu tun ist, an das Objekt.

    "Für mich..."?
    Der Denkansatz wird hier aber mehr betont. Der ist in C genauso umzusetzen, wie in C++ und wird sogar identisch kompiliert. Der Unterschied ist zwischen OO und nicht OO ist also, dass beides identisch ist.
    Ist ja im Prinzip ähnlich zu otze, hier wird nur geschickt und nicht geschoben.

    Rexx (prozedural) verschickt echte Nachrichten über das OS, darin steht, was getan werden soll. Das sind in der Regel ASCII-Texte und Rexx-kompatible Objekte - laufende Programme - lesen sich das durch und machen das dann.
    C++ ruft objektorientiert Methoden. (benutzt man Fachwörter sind es nämlich Methoden, keine bösen Funktionen)
    Nach Deiner Definition ist Rexx objektorientiert und C++ nicht.

    Vielleicht ist C++ stilvolle Rexx-Programmierung?
    Oder ist Rexx Anfänger OOP und C++ kein Experten OOP?

    Ich könnte auch weiter ein paar Seiten zurück gehen, da finde ich sicherlich auch noch schöne Meinungen.
    Je länger der Thread wird, desto mehr Meinungen kommen ja zusammen.
    Ich bitte zu entschuldigen, dass ich hier die Vorstellungen von OOP so respektlos kombiniere, aber... scnr.

    Fällt irgendjemanden auf, wieviele unterschiedliche Definitionen (Zitat) *die* (/Zitat) "übliche" Definition "bereichert" - oder wie es Mr.N sagte - "schwammig" macht. Und schwammig ist hier sehr höflich, weil die ganzen unterschiedlichen Meinungen, die hier als die "übliche" ankommen überhaupt nicht zusammen passen, weil jeder unter OOP was anderes versteht.
    Soviele mögliche Meinungen, aber keiner konnte meine bisher kleine Frage an hustbaer bisher beantworten?

    In den letzten Postings klammert man sich an Nachrichten. Bemerkt denn niemand, dass "Nachrichten" ein theoretischer Ansatz zur OOP ist und überhaupt nichts mit der Realität zu tun hat, die in C++, C#, Java stattfindet?
    Da hat man was zu erzählen in der Vorlesung - um mehr geht es hier nicht. Fachwissen. Jede neue Technik bracht neue Vokabeln, damit man sich von anderen Techniken abgrenzen kann. Und in dem Fall grenzt man sich von Dingen ab, von denen man sich nicht abgrenzen müsste. Die Inforamtik ist voll von sinnlosen Fachbegriffen. Wenn ich Projektbeschreibungen durchgehe, suche ich im Internet Übersetzungen für belanglose Techniken, die sich aber furchtbar wichtig anhören.
    Für unseren JS-Freund zum Beispiel "AJAX". Stinknormales JS gepaart einem Funktionsaufruf, um Informationen nachträglich anzufordern. Die Existenz einer Funktion zu kennen, macht einem zum AJAX Experten, als reiner JavaScript Entwickler kann man vielleicht OOP in JS, aber gegen eine AJAX-Experten kann man damit nicht mitziehen.
    Methoden sind Funktionen. Nachrichten sind Funktionsaufrufe.
    Und wer's nicht weiß, ist kein Fachmann, weil der unter Nachricht und Methode in einem anderem Kontext versteht.

    Rexx schreibt Nachrichten, verpackt die und schickt die durch die Weltgeschichte, wo ein anderes Objekt sie annimmt, auspackt, liest und dann handelt. Rexx war eine Supersprache. Programmiert irgendwer hier Algorithmen in Rexx?
    Apples Version davon heißt AppleScript. Microsofts Version ist VBA.
    Wenn nicht, warum nicht? Weil Rexx aus einen aktuellen P4 zu einem 486er macht, wenn man damit ernsthaft programmiert.

    DEvent - dem Student, dessen Job es ist, sein Wissen in Frage zu stellen - ist offenbar gelungen, sein "Wissen" in Frage zu stellen. Ich habe mal eine Umfrage zum Thema Programmiersprachen gemacht und fragte auch nach der Berufsgruppe. Diplom-Informatiker war auffälligst die Gruppe, die ihre Konzepte und Werkzeuge überhaupt nicht in Frage stellten. Zitat: "Habe ich mir ehrlich gesagt nie Gedanken drum gemacht."
    Im Gegenteil, jede Möglichkeit etwas anders zu sehen, wurde absolut abgelehnt.
    Mit Projektleitern, Mathematikern, Physikern usw. hatte ich durch die Umfrage teils interessante und inspirierende Diskussionen.


Anmelden zum Antworten