Announcement

Collapse
No announcement yet.

objects und Delphi?

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • objects und Delphi?

    Ich will in unserem Delphi5-Projekt objects einsetzen, weil sie mir für Konzepte wie z.B. Punkte lieber sind als classes...<br>
    - Wert- statt Referenzsemantik<br>
    - der ganze Kram mit Create/Free fällt weg (Schreib- und Laufzeitaufwand))<br>
    (Kon- und Destruktor kann ich mir doch sparen, wenn mein Objekt keine virtuellen Methoden enthält???)
    <p>... oder als records + globale Routinen:<br>
    - "nettere" Syntax (Infix p.Plus(q) statt Präfix Plus(p, q);<br>
    ist natürlich Geschmackssache)<br>
    - weniger Probleme mit Namenskollisionen<br>
    - bzw.: weniger Schreibarbeit durch Vermeidung Namensraumpräfixen<br>
    - bessere Unterstützung durch Programmierhilfe ("Intellisense" ;-P)<br>

    <p>Nun scheinen die Borländer aber objects nicht mehr zu mögen und wollen sie laut
    Online-Hilfe aussterben lassen. Darunter leidet insbesondere die Dokumentation.
    Auf der anderen Seite ist die Compilerunterstützung gar nicht so schlecht.
    Gegenüber dem Stand aus dem Referenzhandbuch zu "Borland Pascal Mit Objekten 7.0"
    (geerbt von den Vorvätern) sind ja durchaus noch Features hinzugekommen (properties z.B.).
    <p>Drum die prinzipelle Frage: Kann man's wagen, noch objects zu verwenden?
    <p>Und weiß jemand, ob's irgendwo weitere Doku dazu gibt und, wenn ja, wo?
    <p>Auch diesmal Danke im voraus,<br>
    Uli.

  • #2
    Hi,

    ich würde object keinesfalls verwenden. Leite Deine neuen Objekte von TObject ab. Du MUSST ja keine Konstruktoren schreiben.
    Den Punkt Namenskollisionen verstehe ich nicht.
    Die Programmierhilfe funktioniert bei TObjekten doch gut?

    Und ein sauberes Create/Free in entsprechendem try/except/finally ist doch wesentlich sauberer, denn wenn ich nicht weiss, wie was gerade steht.

    Ich denke, Du erlangst nicht wirklich Vorteile durch "object"

    Gruss

    Tim

    Comment


    • #3
      Hi Timo,<br>
      hätte nicht gedacht, dass sich in dem Thread noch mal was tut. :-)<br>
      <i>ich würde object keinesfalls verwenden. Leite Deine neuen Objekte von TObject ab.
      Du MUSST ja keine Konstruktoren schreiben.</i><br>
      Für "objektorientierte" Sachen mit Klassenhierarchie und Polymorphie und so
      benutze ich natürlich TObject's. Mir gings eben um Sachen wie Punkte/Vektoren.
      In "klassischem" Pascal würde ich das so machen
      <pre>
      type
      TVector = record
      x, y: Double;
      end;

      function AddVectors(p,q: TVector): TVector;
      function SubtractVectors(p,q: TVector): TVector;
      // weitere Funktionen auf TVector's

      procedure Test;
      var
      a, b, c, d, e: TVector;
      begin
      c := AddVectors(a, b);
      e := SubtractVectors(AddVectors(a, b), AddVectors(c, d));
      end;
      </pre>
      In "Test" würde ich viel lieber sowas schreiben (ich weiß: operator overloading == C++ == böse :-)):<pre>
      c := a + b;
      e := ((a + b) - (c + d));
      </pre>
      ... oder wenigstens das:<pre>
      c := a.Plus(b);
      e := (a.Plus(b)).Minus(c.Plus(d))); // OK, die Zeile ist auch nicht soooo schön ;-)
      </pre>
      Hierfür fallen record's flach, weil sie keine Methoden haben können, und TObject's,
      weil sich Obiges eben schwer mit der Referenzsemantik und der Pflicht zum
      Aufräumen vereinbaren lässt.

      <p><i>Den Punkt Namenskollisionen verstehe ich nicht. Die Programmierhilfe
      funktioniert bei TObjekten doch gut? </i><br>
      Den Teil mit Namenskollisionen und Programmierhilfe streich ich mal
      nachträglich wieder, das lässt sich ja mit overload bzw. Ctrl-Space einigermaßen
      umschiffen.

      <p><i>Und ein sauberes Create/Free in entsprechendem try/except/finally ist doch
      wesentlich sauberer, denn wenn ich nicht weiss, wie was gerade steht.</i><br>
      Siehe oben: schreib mal <code>c := a.Plus(b);</code> mit einem
      <code>TVector = class(TObject)</code> - das wird ein Mehrzeiler aus lauter
      Create/Free-Verwaltungskram, und bei Wartungsarbeiten weiß keiner mehr,
      wer denn jetzt für's Erzeugen und/oder Töten der armen Vektoren zuständig ist.

      <p><i>Ich denke, Du erlangst nicht wirklich Vorteile durch "object"</i><br>
      Na ja. Wenn ich gezwungen wäre, ohne objects zu arbeiten, würde ich halt
      records nehmen wie im ersten Codefragment; das wäre auch kein Beinbruch.
      Aber unter D5 hatte ich (noch?) keine Probleme mit objects, und in zukünftigen
      Delphi-Versionen können ja wahrscheinlich -- .NET sei Dank -- records
      (nichtvirtuelle) Methoden haben, also habe ich auch in Zukunft keine Probleme.
      Das object ist tot -- es lebe der record mit Methoden! ;-)

      <p>Ciao, Uli

      Comment


      • #4
        Wie wäres es mit Interfaces ?<br> ich habe eine Large Integer Math. Library gecodet, jeweils mit Objects, Klassen und Interfaces. Mit den Interfaces ergab sich die beste Semantik, Potabilität und uniform Erweiterbarkeit. Ich nutze die Interfaces aber NUR als Datenobjecte OHNE wesentliche Methoden. Die eigentlichen "Methoden" werden procedural gecodet aber dann mit default Parametern und overloading.
        Z.b.:

        <pre>

        type
        IPoint = interface
        function X: Double;
        function Y: Double;
        end;<br>

        procedure PAdd(var A: IPoint; const B: IPoint); overload;
        procedure PAdd(var A: IPoint; const B,C: IPoint); overload;<br>

        implementation<br>

        type
        TPoint = class(TInterfacedObject, IPoint)
        X,Y: Double;
        end;<br>

        function AllocPoint(var A: IPoint): TPoint;
        begin
        if A = nil then A := TPoint.Create;
        end;<bR>

        procedure PSwp(var A,B: IPoint);
        var
        T: Pointer;
        begin
        T := Pointer(A);
        Pointer(A) := Pointer(B);
        Pointer(B) := T;
        end;

        procedure PAdd(var A: IPoint; const B: IPoint);
        begin
        PAdd(A, A, B);
        end;<br>

        procedure PAdd(var A: IPoint; const B,C: IPoint);
        var
        R: IPoint;
        begin
        with AllocPoint(R) do
        begin
        X := B.X + C.X;
        Y := B.Y + C.Y;
        end;
        PSwp(R, A);
        end;

        // vorteil zur Nutzung <br>

        procedure Test;
        var
        A,B,C: IPoint;
        begin
        PSet(A, 1, 1);
        PAdd(C, A, PGet(1, 1));
        PAdd(B, C);
        usw.
        end;<br>

        </pre>

        D.h. keinerlei Initialisierungen/Finalisierungen sind nötig, totzdem können dynamische Speicherbereiche benutzt werden. Zudem gibts die Möglichkeit des "Copy on write demand" also so wie LongStrings oder dynam. Arrays. Dies geht mit objecten nicht. Dadurch werden enorm unnötige Kopieroperationen vermieden.<br>
        Das Nutzerinterface = mathematischen proceduren lässt sich jeder Zeit erweitern OHNE das am Object/Klasse rumgepuscht werden muß. Normalerweise entstehen in expensiven math. Libraries Object mit sovielen Methoden das sie als Monsterklassen bezeichnet werden müssen.
        Desweiteren klappt das overloading + default Paramter + open array Parameters mit proceduren/function einwandfrei, mit Methoden gibts extreme Probleme.

        Gruß Hage

        Comment


        • #5
          Hallo, Hagen!<br>
          <i>Wie wäres es mit Interfaces ?</i><br>
          Finde ich eigentlich prinzipiell eine faszinierende Sache, aber
          irgendwie bin ich bisher immer wegen der "zwangsweisen" Referenzzählung auf die Nase gefallen. Für viele Zwecke wären mir Java-mäßige Interfaces ohne compiler magic erstmal lieber. Für den konkreten Einsatz hier oder diese SafeGuard-Geschichten ist's natürlich praktisch, wie's jetzt ist.

          <i>Die eigentlichen "Methoden" werden procedural gecodet aber dann mit default Parametern und overloading. Z.b.:<i></br>
          Wo ist denn dann noch der Unterschied gegenüber<pre>
          type
          TVector = record
          x, y: Double;
          end;
          <br>
          function AddVectors(p,q: TVector): TVector;
          // oder:
          procedure AddVectors(var Result: TVector; const p,q: TVector);
          </pre>

          Von der Performanz her merkst du wohl keine Nachteile, von wegen viele kleine Allokationen und so? Wie ich dich einschätze, wird deine
          Bibliothek schon eher unter "stressigen" Bedingungen laufen, wo sowas zählt.
          <br>Ich hab so einen Vergleich mal (mehr spaßeshalber) unter VB gemacht -- Type versus *.cls -- und der Unterschied war beachtlich, Faktor 200 oder so. War natürlich keine todsichere, wissenschaftlich fundierte Aktion, aber die Größenordnung wird schon passen. :-) Lag wahrscheinlich an dem ganzen nicht zu umschiffenden COM-Overhead.

          <p>Ciao, Uli

          Comment


          • #6
            Hi Uli

            Deine obige Annahme ist in sofern richtig wenn wir mit ordinalen Datentypen als Unter-Typen arbeiten. Dann wäre es tatsächlich am besten/effizientesten mit Recordtypen und proceduralem Interface.<br>
            Allerdings ging es mir um dynamische Datentypen wie super große Integer/Rationale oder Floating Points. Solche "Typen" sind sehr "empfindlich" in deren Speichermanagement. In meiner Library habe ich solche "forged" Interfaces mit einem eigenen FILO Stack zur Speicherverwaltung kombiniert. Alleine dieser FILO Stack erhöhte die Performance um 10-20%. Z.b. bei der Berechnung der Zahl PI mit 1 Million exakten Dezimalstellen machen 20% sehr viel aus. Ab einer gewissen Größe entscheiden sogar diese 20% über Machbarkeit oder Unlösbar.<bR>

            Gruß Hage

            Comment

            Working...
            X