C++ / Delphi



  • Dann will ich mal die Diskussion wieder anheizen *g*. Da ich sowohl mit Delphi als auch mit C++ mehrere Jahre meine Brötchen verdient habe, bilde ich mir ein, dass ich meinen Senf dazugeben kann.
    Die Äußerungen von kartoffelsack gefallen mir prinzipiell ganz gut, auch wenn ich in einzelnen Punkten nicht ganz zustimmen kann.
    Was meinst Du mit der „automatische Destruktion von Objekten“? Meinst Du damit, dass am Ende des Scopes ein Objekt automatisch freigegeben wird, wenn dieses nicht dynamisch angefordert wurde oder gibt es in C++ etwas, was mir all die Jahre verborgen geblieben ist?
    In Delphi kann man sich das try finally sparen, wenn man sich die Mühe macht mit Interfaces zu arbeiten. Man muss einfach im Einzelfall entscheiden, ob sich der Aufwand lohnt.
    Weiterhin gibt es in Object Pascal nicht nur „class“ sondern auch „object“. Das ist ein Überbleibsel aus Turbo Pascal 5.5-Zeiten. Derartige Klasen verhalten sich ähnlich wie C++-Klassen. Man kann also nicht nur dynamisch eine Instanz erzeugen, sondern auch eine, die autom. am Anfang der Methode erzeugt und am Schluss wieder freigegeben wird. „object“ wird aber normalerweise von Delphi-Programmierern nicht verwendet.
    Bei Delphi für .NET ist dann auch zwangsweise Garbage Collection mit dabei.

    Es stimmt, dass Delphi zu den Templates nichts vergleichbares hat. Ich persönlich mag Templates aber nicht besonders.
    Template-Code lässt sich IMHO sehr schwer lesen.
    Durch Templatecode zu debuggen ist ein Drama. Ich weiß meistens nicht einmal in welcher Klasse ich mich gerade befinde. Wenn man bei Parametern mit STL-Klassen arbeitet muss man sich immer erst durch etliche Zeilen STL-Code quälen, bevor man in der Methode landet, die man eigentlich debuggen will.
    Und was ich am meisten an den Templates hasse, ist dass sie die Übersetzungszeit endgültig in den Keller abgehen lassen.
    Die Typsicherheit von Templates bekomme ich bei Delphi dadurch, dass ich das von Hand mache, was bei Templates vom Compiler erledigt wird. Ich kopiere den ganzen Code einer speziell geschriebenen Klasse und lasse durch suchen/ersetzen den Typ einsetzen. Das kostet mich zwar etwas Zeit beim Tippen, die bekomme ich aber wieder um ein vielfaches zurück, dadurch, dass sich der Code besser lesen, debuggen und viel schneller übersetzen lässt.

    Es wurde hier geäußert, dass sich C++ bei großen Projekten besser eignen würde als Delphi. Ich bin genau anderer Meinung. C++ hat gegenüber ObjectPascal etliche Vorteile, aber unter dem Strich steht bei mir ObjectPascal klar vor C++. Mit Delphi lassen sich große Projekte viel schneller entwickeln als z.B. mit dem C++Builder.
    Bei großen Projekten arbeiten immer etliche Entwickler zusammen. Somit treffen auch mehrere Programmierstile aufeinander. Da C++ viel mehr Freiraum lässt, wie man es programmiert, steigt das Risiko, dass der eine Code produziert in dem sich der andere nur schwer zurecht findet.
    Ich habe momentan das Problem, dass ich jemanden einarbeiten muss, der aus der VB-Ecke kommt. In unserem Projekt wird aber fast alles verwendet, was C++ so hergibt. Es wäre sicherlich deutlich leichter für den Neuen sich in ein entspr. Delphi-Projekt einzuarbeiten.
    Bei C++-Compilern darf man nach Fehlern suchen, die ein Delphi-Programmierer nie zu sehen bekommt. Einer meiner Lieblinge ist „unresolved external“. Bei Delphi gibt es zwar auch eine Fehlermeldung, die in eine ähnliche Kerbe schlägt. Aber selbst die haben bestimmt die meisten Delphiprogrammierer noch nie zu sehen bekommen.
    Was aber am meisten Zeit kostet ist der langsame C++-Compiler. Wenn ich unser Projekt komplett übersetzen lassen muss, dann kann ich zwei Stunden (P4 mit 1,5GHz) lang etwas anderes tun. Ich habe eine Unit (C++Builder) die sage und schreibe alleine über drei Minuten zum übersetzen braucht. Mal schnell etwas ausprobieren kann man da komplett vergessen. Ich habe etliche Stunden/Tage nur damit verbracht, mir zu überlegen, wie ich den Code umstrukturiere, damit die Übersetzungszeiten besser werden. Zu allem Überfluss kommen mit dem VisiBroker (CORBA) noch Headerdateien dazu, die ich nicht in die vorcompilierten Headerdateien mit aufnehmen kann, da diese sonst gar nicht erzeugt werden.
    Als ich vor etlichen Jahren ein ähnlich großes Projekt mit Delphi umgesetzt habe, hat selbst das komplette erzeugen nur knapp über eine Minute (Pentium II 350 MHz) gedauert.

    Es macht keinen Spaß ständig auf den C++-Compiler warten zu müssen.

    Die Diskussionen über Schleifen, begin/end, oder über den Sinn/Unsinn dass alle Klassen von TObject abgeleitet sein müssen, ist in meinem Augen Kleinkram, der nicht wirklich Einfluss darauf haben sollte, für welche Sprache/Entwicklungsumgebung man sich entscheidet.



  • Was meinst Du mit der ?automatische Destruktion von Objekten?? Meinst Du damit, dass am Ende des Scopes ein Objekt automatisch freigegeben wird, wenn dieses nicht dynamisch angefordert wurde oder gibt es in C++ etwas, was mir all die Jahre verborgen geblieben ist?

    Damit mein ich, dass man alles, was unbedingt getan werden muss in einen Destruktor reinpackt und damit sicherstellt, dass es ausgeführt wird - bei einer Exception genauso wie im normalen Programmfluss.
    Anwendungsbeispiel: SmartPointer. Wenn die letzte Referenz eines Pointers die Gültigkeit verliert, wird der Speicher freigegeben.
    Dieses Prizip (Resource Aquiration is initialisation = RAII) kann man aber auf alle Arten von Resourcen Anwenden, wodurch es einer Garbage-Collection überlegen ist.

    Der C++Builder ist übrigens ganz besonders übel in sachen Compile-Zeit. Bei anderen Compilern is das nicht so extrem. Leider haben die andere Nachteile 😞 🙄



  • Original erstellt von Eisenherz:
    Mal schnell etwas ausprobieren kann man da komplett vergessen.

    Das hat mit ernsthaftem Programmieren sowieso nichts zu tun.

    Original erstellt von kartoffelsack:
    Dieses Prizip (Resource Aquiration is initialisation = RAII) kann man aber auf alle Arten von Resourcen Anwenden, wodurch es einer Garbage-Collection überlegen ist.

    Für sinnlose Definitionen von 'alle' vielleicht ... RAII funktioniert bei Ressourcen nicht, wo beim Schließen Fehler auftreten können.

    Und wie kann ein Programmierstil einer Technik überlegen sein (oder umgekehrt) und was spricht dagegen, es zu kombinieren? WIMRE machen es einige ADA-Umgebungen genau so.

    Manche Sprachen haben andere interessante Ansätze bezüglich des Ressourcenmanagement entwickelt, z.B. Lisp oder Ruby. Andere Sprachen bieten hier nichts brauchbares (Java).



  • Original erstellt von kartoffelsack:
    SmartPointer. Wenn die letzte Referenz eines Pointers die Gültigkeit verliert, wird der Speicher freigegeben.

    SmartPointer sind etwas, was ich wirklich mag. So klein die Klasse ist, so ist sie für mich eines der besten Beispiele für die sinnvolle Anwendung von Templates und dem Überladen von Operatoren.
    In Delphi bilde ich SmartPointer wie schon angedeutet mit "interface" nach, da diese auch Referenzen zählen und sich "selbst" freigeben. Um sich Tipparbeit zu sparen gibt es "with", wobei ich persönlich "with" nicht sonderlich mag.

    Der C++Builder ist übrigens ganz besonders übel in sachen Compile-Zeit. Bei anderen Compilern is das nicht so extrem. Leider haben die andere Nachteile 😞 🙄

    Toll finde ich dass der C++Builder beim Übersetzen nur ca. 7 Prozent des Prozessors belegt. Wie schnell könnte er sein, wenn er wirklich den ganzen Prozessor nutzen würde.
    Wenn man nicht aus der Entwicklungsumgebung heraus übersetzt, sondern über Batch-Dateien, dann soll er angeblich bis zu dreimal so schnell sein.



  • Original erstellt von Daniel E.:
    Das hat mit ernsthaftem Programmieren sowieso nichts zu tun.

    Heißt das, dass ein "ernsthafter" Programmierer immer über alles genau Bescheid weiß, jeden Hilfetext vollständig versteht und nie durch ausprobieren herausfinden muss, was ihm dieser Hilfetext genau sagen will oder wie z.B. bestimmte Effekte an der Oberfläche wirken?

    Dann werde ich nie ein "ernsthafter" Programmierer werden.

    [ Dieser Beitrag wurde am 08.01.2003 um 16:49 Uhr von Eisenherz editiert. ]



  • Ich hatte mehr an etwas wie '-Probier mal da ne 3 statt 2! -Geht nicht! -Probier 'ne 4!' gedacht ;).
    Auf einer halbwegs fundierten Grundlage etwas zu probieren ist okay, auch wenn ich dafür keinen offiziellen Code benutzten würde ... YMMV.



  • Original erstellt von kingruedi:
    Also wenn ich all das glaube, was mir Bashar von ADA erzählt hat, frag ich mich, warum die kein ADA Builder 😉 entwickelt haben

    Nur einige Ergänzungen zu Ada:
    Diese Programmiersprache wurde nicht nur Zwecks Vereinheitlichung (das DoD hatte ganz schön Chaos..) entwickelt, sondern besonders für bessere Wiederverwendbarkeit, Selbstdokumentation, Laufzeit-Sicherheit und Portabilität
    (jeder validierter Ada95-Compiler musste einen Test bestehen)
    Kingruedis Frage ist berechtigt, aber leider gewinnt nicht immer der Beste...
    Die Firma Aonix entwickelt übrigens genau das... ObjectAda nennt sich das Teil.
    ..
    last but not least: Ada ist ein Name, keine Abkürzung, dafür würden euch die
    Jungs unter comp.lang.ada einen Kopf kürzen 😉



  • Toll finde ich dass der C++Builder beim Übersetzen nur ca. 7 Prozent des Prozessors belegt. Wie schnell könnte er sein, wenn er wirklich den ganzen Prozessor nutzen würde.

    Also mein C-Builder belegt > 90% und braucht trotzdem ewig. Hast Du die Hintergrund-Compilierung an? Damit ist er nämlich NOCH langsamer.

    Weiterhin gibt es in Object Pascal nicht nur ?class? sondern auch ?object?. Das ist ein Überbleibsel aus Turbo Pascal 5.5-Zeiten. Derartige Klasen verhalten sich ähnlich wie C++-Klassen. Man kann also nicht nur dynamisch eine Instanz erzeugen, sondern auch eine, die autom. am Anfang der Methode erzeugt und am Schluss wieder freigegeben wird

    Soweit ich mich entsinne müssen aber Ctor und Dtor trotzdem explizit aufgerufen werden. Das ist ja der springende Punkt.

    [ Dieser Beitrag wurde am 08.01.2003 um 18:58 Uhr von kartoffelsack editiert. ]



  • Lesbarkeit:
    OPascal kann man wirklich schneller lesen teilweise, aber was mich stört
    Funktionsaufrufe müssen keine () bei leerer Parameter Liste haben 😞
    und das der Typ einer Funktion erst am Ende kommt

    function lala(foobar : Integer) : Real;
    

    Aber ich finde C++ ist auch leicht zu lesen, wenn man sich dran gewöhnt. Templates können aber wirklich Funktionen unübersichtlich machen, aber das ist auch Gewöhnungssache IMHO

    ADA:
    Ich dachte immer, dass ADA eine Verbesserung (deutliche!) von Pascal ist, sozusagen inc(Pascal)

    Compilezeit:
    zur Compilezeit Minimierung sind die Systeme sehr praktisch, die das compilieren auf verschiedene Rechner aufteilen, ähnlich nach dem SETI@Home Prinzip, ich weiss aber nicht, ob es so was für Windows gibt. Aber für mal eben ausprobieren alles neuzukompilieren ist ein bisschen übertrieben, ist es nicht? (man kann natürlich pech haben und probiert mal so ein bisschen an wichtigen Stellen rum und man kommt nicht mehr an "Alles Neuerstellen" vorbei, aber an den Basis stellen sollte man eh lieber am Anfang rumfummeln ;))



  • Original erstellt von kingruedi:
    **
    ADA:
    Ich dachte immer, dass ADA eine Verbesserung (deutliche!) von Pascal ist, sozusagen inc(Pascal)**

    Wer von Pascal auf Ada (watch the spelling) umsteigt, verbessert sich tatsächlich deutlich 😉
    Dass einige Ideen von Pascal auf Ada übernommen wurden, sieht man am Syntax
    recht schnell.... aber trotzdem ist Ada keine "Weiterentwicklung", sondern vielmehr eine komplette Neuentwicklung mit bestimmten Vorgaben...



  • Original erstellt von kartoffelsack:
    **Also mein C-Builder belegt > 90% und braucht trotzdem ewig. Hast Du die Hintergrund-Compilierung an? Damit ist er nämlich NOCH langsamer.
    **

    Ich hatte bis vor kurzem sogar 100 Prozent. Dann habe ich die Unterstützung des DMA-Transfers vom Betriebssystem aktiviert. Seit dem braucht er nur noch ca 7 Prozent. An den Übersetzungszeiten selbst hat das aber nichts geändert. Bei mir macht es auch keinen Unterschied, ob ich die Hintergrund-Compilierung an habe.
    Wir haben ein paar Leute von Borland im Haus. Die konnten mir das aber auch nicht erklären.

    Soweit ich mich entsinne müssen aber Ctor und Dtor trotzdem explizit aufgerufen werden. Das ist ja der springende Punkt.

    Ich muss gestehen, dass ich seit Borland Pascal 7 nicht mehr damit gearbeitet habe und ich mich deswegen evtl. falsch erinnere. Ich bin jetzt aber zu faul dem weiter nachzugehen.

    [ Dieser Beitrag wurde am 09.01.2003 um 17:35 Uhr von Eisenherz editiert. ]

    [ Dieser Beitrag wurde am 09.01.2003 um 17:36 Uhr von Eisenherz editiert. ]



  • Original erstellt von kingruedi:
    **Lesbarkeit:
    OPascal kann man wirklich schneller lesen teilweise, aber was mich stört
    Funktionsaufrufe müssen keine () bei leerer Parameter Liste haben 😞
    und das der Typ einer Funktion erst am Ende kommt

    function lala(foobar : Integer) : Real;
    

    **

    Mir geht es genau anders herum. Mich stört, dass bei C++/Java/C# zuerst der Typ kommt. Wenn ich nach einer Methode in einer Klasse suche, dann klappere ich die Methodennamen ab, bis ich einen finde, der nach der gesuchten Funktionalität klingt. Die Methodennamen stehen aber fast nie auf der gleichen Höhe, da die Typbezeichnungen unterschiedlich lang sind. Außerdem kann noch ein virtual oder ähnliches davor stehen, was es mir entgültig erschwert den Namen der Methode auf Anhieb zu erkennen.
    Bei Pascal kommt das ganze Zeugs dahinter, die Namen der Methoden stehen also alle (fast) auf gleicher Höhe. Außerdem sehe ich bei Pascal durch das fett geschriebene "function" bzw. "procedure" sofort, dass es sich um eine Methode und nicht um ein Feld handelt. Bei C++ muss ich immer erst nach den unscheinbaren Klammern schauen.



  • Ich denke, dass das eh sehr subjektiv ist, wie gut man eine Sprache lesen kann oder nicht (außer bei Brainfuck, da haben sicher alle eine Meinung ;)).

    Mir gefällt der C(++) Weg besser, dir der (O)Pascal Weg



  • Also mein C-Builder belegt > 90% und braucht trotzdem ewig.

    BTW : Warum brauchen C++-Compiler eigentlich so lange zum Kompilieren? g++ kompiliert bei mir ein 80-Zeilen C++-Programm in 4 Sekunden. javac kompiliert bei mir ein 7000-Zeilen Java-Programm in 4 Sekunden. ...ich hatte bei g++ übrigens noch nichtmal mit "-O3" kompiliert.

    [ Dieser Beitrag wurde am 09.01.2003 um 18:35 Uhr von Gregor editiert. ]



  • @gregor
    Der Compiler hat mehr zu tun, weil der Aufbau der Sprache komplexer ist. z.B. das Header-Konzept (komplexer meint nicht zwingend besser). Wenn dann noch Templates hinzukommen ...

    @Eisenherz

    Deswegen code ich so

    //...
     int
    foo(double d);
    
     double
    foo(int i);
    
     void
    bar();
    

    dann sind die Dinger auch auf einer Linie.

    Ansonsten könnt ich auch mal schaun, ob DMA bei mir aktiviert ist. Dann könnt ich besser surfen, wenn er compiliert 😃

    [ Dieser Beitrag wurde am 09.01.2003 um 20:08 Uhr von kartoffelsack editiert. ]



  • Das Header Konzept wird doch vom PP aufgelöst und sollte doch eigentlich nicht so schwer sein. Ich denke Templates sind da schon komplexer



  • @Kartoffelsack
    Ich mach das so:

    int     foo(double d);
    double  foo(int i);
    void    bar();
    


  • Die lange Kompilierzeit dürfte auch damit zusammenhängen, dass Operatoren je nach Verwendung und Position verschiedene Bedeutungen haben können, die sich erst durch den Zusammenhang ergeben.



  • @WebFritzi
    oder so

    int                                                                                          foo();
    std::mulimap<my::specialAccessKey, std::pair<double, std::string>, my::someSpecialPredicate> doAussagekraeftigerFunktionsname(int* pBar);
    

    😃

    @Lucki
    Das mit den Operatoren ist aber doch auch nix anderes als ne ganz normale Funktionsüberladung. Das kann man in Delphi und Java aber doch auch

    @kingruedi
    Aber der Präprozessor kopiert ja nur den ganzen Code aus den Headern in jedes Modul rein. d.h. dass pro cpp-Datei der gesamte Code der Header übersetzt werden muss. Wenn man da ein paar Header aus der STL verwendet, kommen da gleich ein paar tausen Programmzeilen zusammen. Und wenn ein mittelkleines Projekt dann vielleicht aus 30 Modulen besteht, ist das schon irrsinnig viel Code.
    Beim CBuilder kann man Präkompilierte Header verwenden. Das ist in der Praxis allerdings recht schwer: Die Header müssen immer in der gleichen Reihenfolge verwendet werden, man muss die Dateinamen in den Includes gleich schreiben (also nicht mal groß, mal klein), wenns inline-Funktionen gibt, packt ers nicht, genausowenig standard-Parameter, templates machen Probleme etc.
    Aber wenn man drauf achtet, gehts schon: Ich habs mal bei nem nicht wirklich goßen Projekt ausprobiert (mit vielleicht 30 eher kleinen Klassen in entsprechend vielen Modulen): Ohne vorkompilierte Header: 900 sec, mit 300. Das ist schon ne Beschleunigung um Faktor 3, aber verdammt das sind immer noch 5 Minuten für ein lächerliches Projekt. Außerdem versteh ichs auch nicht: Wenn er die ganzen Header ohne vorkomp. Header wirklich für jedes Modul übersetzt, mit aber nur einmal, hätte das das ganze noch erheblich mehr beschleunigen sollen.
    Andere Compiler sind dann aber schon ein ganzes stück schneller. Ich schätz, die merken sich die einzelnen Header irgendwie und basteln die dann zusammen.

    [ Dieser Beitrag wurde am 10.01.2003 um 10:55 Uhr von kartoffelsack editiert. ]



  • @kartoffelsack

    Gute Idee, wenn es keinen Styleguide gäbe, der das anders vorschreibt. Trotzdem hätte ich das Problem noch mit den Code von anderen Programmierern, die das nicht so formatieren.

    Zwecks DMA: Bei Windows NT4 heißt das Programm zum aktivieren dmacheck.exe. Ich weiß aber nicht, wo sich das bei einer normalen Installation befindet. Vielleicht im Ordner i386 auf der Installations-CD

    Danach geht das Surfen richtig flüssig. 😃


Anmelden zum Antworten