Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Delphi Generics - Pro und Contra (https://www.delphipraxis.net/180504-generics-pro-und-contra.html)

stahli 23. Mai 2014 22:44

Generics - Pro und Contra
 
Ich habe ein Projekt, das ich jetzt refakturieren will (muss ;-) ).

Eine Dinge habe ich über Generics gelöst - vor allem Listen und Comparer.

Beim Entwickeln und Debuggen hatte ich immer wieder Schwierigkeiten, weil Objekte nicht ohne weiteres zuweisungskompatibel oder Schleifendurchläufe nicht eindeutig nachvollziehbar waren.

Jetzt stellt sich mir die Frage, ob ich lieber auf Generics verzichten sollte.

Sicherlich gibt es dann etwas mehr Schreibarbeit und notwendige Type-Castings an einigen Stellen aber der Programmablauf (nicht der Quelltext) erscheint mir dann nachvollziehbarer.

Ich kenne Generics aus anderen Sprachen nicht, aber im Delphi erscheinen sie mir irgendwie wie ein Fremdkörper.
Man kann zwar mit ihnen durchaus arbeiten, aber im Handling und beim Debuggen wirken sie irgendwie wie eine black box.

Jedenfalls lassen sich klassische Klassen m.E. besser nachvollziehen und händeln.

Wie seht Ihr das?

jaenicke 23. Mai 2014 22:54

AW: Generics - Pro und Contra
 
Wir benutzen massiv Generics und haben dadurch deutlich aufgeräumteren und leichter zu debuggenden Code als vorher. Deine Probleme kann ich nur teilweise nachvollziehen. Das einzige Problem, das ich wirklich habe, ist, dass beim Auswerten (Strg + F7) Generics Probleme machen. Aber insgesamt gibt es mit jeder Version Bugfixes an den Generics, das merke ich schon deutlich.
Interne Fehler wie dieser werden auch weniger:
http://qc.embarcadero.com/wc/qcmain.aspx?d=121517

Ein Nachteil von Generics ist, dass die Größe der Anwendungen dadurch spürbar steigt, aber das stört uns nicht wirklich.

Der schöne Günther 23. Mai 2014 23:26

AW: Generics - Pro und Contra
 
Das einzige was mir spontan zu "Contra" eingefallen wäre ist die Tatsache, dass es in Delphi komischerweise immer Generics genannt wird, aber tatsächlich Templates sind. Da der Linker wohl auf dem Desktop nicht der schlauste ist werden die Anwendungen dort deutlich größer.

Aber Mich stört es auch nicht.

Der QC-Report war meine Entdeckung 8-)

In den ersten XE-Versionen waren (meine ich doch?) Generics noch etwas fehlerbehaftet, aber ich komme eigentlich ganz gut zurecht. Im Debugger sind mir noch nie Probleme aufgefallen. Was meint ihr genau?

Ich könnte mir ehrlich gesagt nicht vorstellen, keine Generics zu haben.

stahli 23. Mai 2014 23:43

AW: Generics - Pro und Contra
 
Ich arbeite mit XE3 und ein kostenpflichtiges Update kommt für mich nicht mehr nicht in Frage.

Konkret stört mich, dass beim debuggen von for-in-Durchläufen generischer Listen das tatsächliche Verhalten nicht nachvollziehbar ist.
Z.B. wird auch bei leeren Listen in einen Durchlauf "hinein gesprungen", dieser aber dann wieder abgebrochen.
Danach steht der Debugger dann wieder auf der Ausgangszeile.

Ich kann das nicht ganz genau erklären, da sich mir das Verhalten noch nicht erschlossen sondern mich immer nur genervt hat.

Dann stört mich, dass man keine klaren Klassennamen und Klassenhierarchien (bei Ableitungen) hat.

Mich verwirrt das eher mehr als dass es mir bringt (kann aber natürlich auch mein Problem sein ;-) ).

himitsu 24. Mai 2014 00:13

AW: Generics - Pro und Contra
 
Jupp, daß Generics eher Templates sind, wo man die Typprüfung schon beim Parsen des Templates macht, anstatt dort nur eine Syntaxprüfung vorzunehmen und die eigentliche Typprüfung erst bei der Verwendung zu machen ... also das ist schrottig und behndert die Nutzung der Generics teilweise extrem.

Was bei den Generics ausfällt, ist daß der Code in der Unit ist, wo der generische Typ entgültig definiert wurde und mir scheint es manchmal auch so, als wenn er dann bei mehreren Units auch mehrmals einkompiliert wird. :gruebel:

Nett ist auch, daß man Debugcode bekommt, obwohl man den für die Unit mit der Definition deaktiviert hat. (ja, der entgültige Code liegt ja nicht in der Unit, aber dennoch hätte man das dann deaktivieren können)


Strg+Linksklick auf eine Methode des generischen Typs leitet einen nicht in die richtige Unit, sondern meistens nur auf das "implementation" der aktuellen Unit. :wall:


Bim Zugreifen/Casten innerhalb der generischen Funktionen muß man oftmals die Typprüfung umgehen (mit wilden Pointern referenzieren und gleich wieder dereferenzieren, damit der Cast durch die kranke Typprüfung rutscht. (wenn es sich nicht um Objekte bei dem Typ handelt)



Aber sonst ist das in XE3 schon relativ gut nutzbar. (ist nicht so schlimm, wie die noch verbuggteren Attribute)

himitsu 24. Mai 2014 00:21

AW: Generics - Pro und Contra
 
Zitat:

Zitat von stahli (Beitrag 1260040)
Konkret stört mich, dass beim debuggen von for-in-Durchläufen generischer Listen das tatsächliche Verhalten nicht nachvollziehbar ist.

Bei nicht generischen Listen passiert das nicht?

Nja, das liegt unter Anderem daran, daß nach der letzten Codezeile der For-In-Schleife der Enumerator freigegeben wird.
Da das ein automatisch generierter Code ist, welcher keine eigene Zeile besitzt, liegt der zufällig an der Position der letzten oder ersten Codezeile der Schleife und für dich sieht es dann halt so aus.
In der Assembleransicht würde das natürlich anders aussehen.

Besser wäre es natürlich, wenn dieser Befehl einfach "übersprungen" und erst wieder an der nächsten richtigen Codezeile angehalten würde. :stupid:

stahli 24. Mai 2014 00:30

AW: Generics - Pro und Contra
 
Liste der Anhänge anzeigen (Anzahl: 1)
Bei normalen For-Schleifen wird diese entweder voll durchlaufen oder gar nicht (weiß gar nicht, wie es aktuell mit "for I := 1 to 0 do ..." steht).

Dass bei generischen Listen der Enumerator freigegeben wird habe ich auch schon mal nachvollzogen.
M.E. müsste der Compiler/Debugger das aber intern regeln (so wie bei "while false do begin end").
Für MEINE ANWENDUNG (und die will ich ja debuggen) ist mir ja Wurscht, was der Compiler da intern veranstaltet.
Mit Assembler will ich mich nicht herum schlagen. Deshalb nutze ich ja Delphi.

Ich finde solche unlogischen Verhaltensweisen halt extrem nervig.
Vereinfachen tun sie die Arbeit jedenfalls nicht.


[EDIT]

Jetzt habe ich noch zwei klare Bugs gefunden:
- Wenn eine generische Liste mit einem Eintrag freigegeben wird knallt es, weil zwei Einträge verglichen werden (warum auch immer).
- Das Freigeben eines Comparers verursacht eine Exception (Eurekalog Prof. kann das aber nicht näher auflösen)
(Darüber hinaus habe ich keine Möglichkeit gefunden, einen zugewiesenen Comparer aus einer Liste wieder zu entfernen.)
Ich bin sicher, dass die Fehler nicht durch mich verursacht werden. Kann natürlich möglicherweise in neueren Bezahlversionen schon gefixt sein.

sx2008 24. Mai 2014 06:12

AW: Generics - Pro und Contra
 
Zitat:

Zitat von himitsu (Beitrag 1260042)
Was bei den Generics ausfällt, ist daß der Code in der Unit ist, wo der generische Typ entgültig definiert wurde und mir scheint es manchmal auch so, als wenn er dann bei mehreren Units auch mehrmals einkompiliert wird. :gruebel:

Ist eigentlich logisch.
Der Compiler nimmt den Code des Generic als Vorlage und erzeugt on-the-fly neuen Sourcecode wobei der aktuelle Datentyp eingefügt wurde.
Dieser generierte Sourcecode wird natürlich in die Unit eingefügt in der auch das Generic mit dem Datentyp zum ersten Mal aufgetaucht ist.
Zur Laufzeit werden dann noch RTTI Daten erzeugt (bei normalen Klassen geschieht dies zur Compile-time).
Zum Sourcecode des Generics selbst gibt es keinen compilierten Objektcode weil das Generic ja nur eine Schablone ist.

Wenn das Generic + Datentyp(en) nur im Abschnitt implementation auftaucht dann weiss der Linker nicht dass es dieses konkrete Generic schon gibt.
Und so kommt es, dass genau der gleiche Code in mehreren Units stecken kann ohne dass der Linker diese Duplikate zu einem zusammenführen kann.

jaenicke 24. Mai 2014 06:55

AW: Generics - Pro und Contra
 
Zitat:

Zitat von stahli (Beitrag 1260044)
- Das Freigeben eines Comparers verursacht eine Exception (Eurekalog Prof. kann das aber nicht näher auflösen)

Freigeben? Das ist doch ein Interface. Normalerweise sieht das so aus:
Delphi-Quellcode:
TComparer<Integer>.Construct(function(const ALeft, ARight: Integer): Integer
begin
  Result := ALeft - ARight;
end);
Dann hast du einen IComparer<Integer>, den du dort nutzen kannst.

Zitat:

Zitat von stahli (Beitrag 1260044)
(Darüber hinaus habe ich keine Möglichkeit gefunden, einen zugewiesenen Comparer aus einer Liste wieder zu entfernen.)

Das geht in der Tat nicht. Wenn du das brauchst, solltest du den Comparer nur an Sort übergeben, damit der gar nicht direkt im Objekt liegt.

jbg 24. Mai 2014 08:36

AW: Generics - Pro und Contra
 
Zitat:

Zitat von sx2008 (Beitrag 1260047)
Wenn das Generic + Datentyp(en) nur im Abschnitt implementation auftaucht dann weiss der Linker nicht dass es dieses konkrete Generic schon gibt.
Und so kommt es, dass genau der gleiche Code in mehreren Units stecken kann ohne dass der Linker diese Duplikate zu einem zusammenführen kann.

Der Linker könnte schon den gleichen Code zusammenfassen, indem er nach gleichem Code sucht. Aber Embarcadero möchte das gar nicht, sonst hätte ich das schon längst zu XE2 Zeiten als Linker-Aufsatz bereitgestellt.

Dejan Vu 24. Mai 2014 08:55

AW: Generics - Pro und Contra
 
D.h.

Delphi-Quellcode:
Var
  foo : TList<TBar>;
...

Var
  bar : TList<TBar>;
Erzeugt doppelten Code?
Dann muss man also

Delphi-Quellcode:
Type TBarList = TList<TBar>;
Var
  foo : TBarList;
...

Var
  bar : TBarList;
Schreiben und die Welt ist in Ordnung?

Der schöne Günther 24. Mai 2014 09:21

AW: Generics - Pro und Contra
 
Ich habe mich damit nie befasst, aber soweit ich es verstanden habe erzeugt folgendes einmal Code für eine Integer-Liste und einmal Code für eine TObject-Liste:

Delphi-Quellcode:
var
   myIntegerList: TList<Integer>;
   myObjectList: TList<TObject>;
Stevie hat da neulich nochmal zu geschrieben:
Zitat:

This by the way is one of the reasons your empty default applications are growing constantly for the recent releases of Delphi: because now generic collections are used all over the place in the runtime. And when I use TList<TButton>, boom, another 10K added to your binary size (approx in XE5). Too bad if you are using more advanced and feature rich collection types like Spring4D. Then every use adds 65K (actually we got down to that number from close to 100K a few months ago).

How could this be solved? Either by the linker fixing this by figuring out identical methods and removing duplicates (the C++ linker has an option for that called COMDAT folding) or the compiler itself could be smart and generate code for equal types only once. Of course he should pay attention to any use of TypeInfo(T) or T.Create for example because that code is actually different. C# does something like this.
Quelle: Delphi Sorcery

himitsu 24. Mai 2014 09:32

AW: Generics - Pro und Contra
 
Zitat:

Zitat von Dejan Vu (Beitrag 1260060)
D.h.

In der selben Unit und in Units, welche die erste Unit einbinden, da könnte es das nur einmal geben, aber bei zwei Units, welche sich nicht kennen, da eventuell nicht. :gruebel:



Zu dem Pack:

Also das ist schon ein komisches Zeug, denn der Code wird in den Units garnicht aufgerufen.
Und das Left/Right in der Methode ist nirgendwo definiert. (ist wohl Compiler-Magic?)
Und scheint es nur so, oder kann in einer generischen TList<> eventuell kein NIL-Objekt abgelegt werden, da Pack dafür da ist, um die zu entfernen? [add] Aber das funktioniert nicht, drum knallt es.

Als TList>TObject> funktioniert folgender Code, aber als TObjectList<TObject> macht es bumm.
Delphi-Quellcode:
var
  L: TList<TObject>;
begin
  L := TObjectList<TObject>.Create; //List<TObject>.Create;
  ShowMessage(IntToStr(L.Count));
  L.Add(nil);
  ShowMessage(IntToStr(L.Count));
  L.Add(Self);
  ShowMessage(IntToStr(L.Count));
  L.Add(Self);
  ShowMessage(IntToStr(L.Count));
  L.Add(nil);
  ShowMessage(IntToStr(L.Count));
  L.Remove(Self);
  ShowMessage(IntToStr(L.Count) + ' ' + IntToStr(L.IndexOf(Self)));
  L.Delete(L.IndexOf(Self)); // bei TObjectList knallt es hier
  ShowMessage(IntToStr(L.Count));
  L.Free;
end;

stahli 24. Mai 2014 09:59

AW: Generics - Pro und Contra
 
Zitat:

Zitat von jaenicke (Beitrag 1260050)
Freigeben? Das ist doch ein Interface.

Oh, ja, stimmt. :oops:
War mir noch gar nicht aufgefallen.

Das ist m.E. das erste mal, dass ich gezwungen bin, ein Interface zu benutzen.
(Ich würde das jetzt weder als besonders positiv oder negativ bewerten, aber eben ungewohnt ... und zu (meinem) üblichen Programmierstil inkonsistent.)

JamesTKirk 24. Mai 2014 10:11

AW: Generics - Pro und Contra
 
Zitat:

Zitat von himitsu (Beitrag 1260042)
Jupp, daß Generics eher Templates sind, wo man die Typprüfung schon beim Parsen des Templates macht, anstatt dort nur eine Syntaxprüfung vorzunehmen und die eigentliche Typprüfung erst bei der Verwendung zu machen ... also das ist schrottig und behndert die Nutzung der Generics teilweise extrem.

Ich persönlich find es gut, dass die Typüberprüfung bereits bei der Definiton des Generics stattfindet. Das hilft Fehler schneller zu finden, als wenn du das erst bei der Spezialisierung mit einem bestimmten Typ hast... Free Pascal ist hier etwas laxer und hat zum Beispiel kein Problem damit, wenn du
Delphi-Quellcode:
T.Something
für ein
Delphi-Quellcode:
T
schreibst, das keinen Constraint hat...

Zitat:

Zitat von himitsu (Beitrag 1260042)
Was bei den Generics ausfällt, ist daß der Code in der Unit ist, wo der generische Typ entgültig definiert wurde und mir scheint es manchmal auch so, als wenn er dann bei mehreren Units auch mehrmals einkompiliert wird. :gruebel:

Das hat sx2008 bereits recht gut erläutert.

Zitat:

Zitat von sx2008 (Beitrag 1260047)
Zur Laufzeit werden dann noch RTTI Daten erzeugt (bei normalen Klassen geschieht dies zur Compile-time).

Du meinst doch sicher zum Zeitpunkt der Spezialisierung zur Compilezeit, oder? Dass die RTTI Daten rein zur Laufzeit erzeugt werden, kann ich mir nicht wirklich vorstellen...

Zitat:

Zitat von jbg (Beitrag 1260058)
Zitat:

Zitat von sx2008 (Beitrag 1260047)
Wenn das Generic + Datentyp(en) nur im Abschnitt implementation auftaucht dann weiss der Linker nicht dass es dieses konkrete Generic schon gibt.
Und so kommt es, dass genau der gleiche Code in mehreren Units stecken kann ohne dass der Linker diese Duplikate zu einem zusammenführen kann.

Der Linker könnte schon den gleichen Code zusammenfassen, indem er nach gleichem Code sucht. Aber Embarcadero möchte das gar nicht, sonst hätte ich das schon längst zu XE2 Zeiten als Linker-Aufsatz bereitgestellt.

Weißt du, warum Embarcadero das nicht möchte? Für Free Pascal plane ich nämlich in Zukunft genau das als Whole Program Optimization Option anzubieten... (und zusätzlich will ich den Compiler beim Spezialisieren überprüfen lassen, ob die selbe Spezialisierung bereits im Interface einer verwendeten Unit vorkommt, damit er diese dann verwendet; das macht FPC aktuell nämlich nicht, dazu muss ich aber erst
Delphi-Quellcode:
class var
in Verbindung mit Generics korrigieren)

Gruß,
Sven

jbg 24. Mai 2014 10:48

AW: Generics - Pro und Contra
 
Zitat:

Zitat von JamesTKirk (Beitrag 1260073)
Ich persönlich find es gut, dass die Typüberprüfung bereits bei der Definiton des Generics stattfindet.

Mir wären C++ Templates lieber gewesen, dann müsste man nicht für jeden Typ einen eigenen Comparer nutzen, der allein durch den Aufruf der Compare-Funktion nicht an die Performance eines direkten "Wert1 = Wert2" herranreicht.

Zitat:

Zitat von JamesTKirk (Beitrag 1260073)
Weißt du, warum Embarcadero das nicht möchte?

Das kann ich nur erahnen:
  • Der Debugger würde nicht den korrekten Datentyp für T anzeigen, da ein T=Integer mit einem T=TObject in manchen Funktionen zusammenfallen könnte. (Wobei das bei einem Release-Build nur Stacktraces betreffen würde)
  • Wenn sie Arbeit in die Compiler-Optimierung stecken würden, müssten sie zugeben, dass ihre Aussage "size doesn't matter nowadays" falsch ist. (wie kommt man auf die Idee das solche Monster von APKs für Smartphones gut wären)
  • Sie haben keine Zeit das einzubauen, sind ja mit ihren Mobile-Compilern beschäftigt (denen auch mal eine Performance-Optimierung gut tun würde)
  • Mein Patch würde die Frage aufwerfen, wer für fehlerhaftes Verhalten beim Endkunden einstehen müsste. (das Totschlag Argument, wenn sie es nicht selbst entwickeln wollen)

Mein Patch funktioniert übrigens nur rudinemtär mit XE2, weil ich "gestoppt wurde".

Stevie 24. Mai 2014 11:24

AW: Generics - Pro und Contra
 
Zitat:

Zitat von Der schöne Günther (Beitrag 1260039)
Das einzige was mir spontan zu "Contra" eingefallen wäre ist die Tatsache, dass es in Delphi komischerweise immer Generics genannt wird, aber tatsächlich Templates sind.

Ob über Templates wie in C++ oder anders (schlauer) in C# - das ist ein Implementierungsdetail, aber Generics sinds beides.
In Delphi gibt es aber sehr wohl Unterschiede und Gemeinsamkeiten zu beidem

Zitat:

Zitat von stahli (Beitrag 1260040)
Z.B. wird auch bei leeren Listen in einen Durchlauf "hinein gesprungen", dieser aber dann wieder abgebrochen.
Danach steht der Debugger dann wieder auf der Ausgangszeile.

Das hat mit der Codegenerierung für eine for-in Schleife an sich zu tun und nicht mit Generics.

Dieser Code:
Delphi-Quellcode:
program Project1;

{$APPTYPE CONSOLE}

type
  TEnumerator = class
    fCurrent: Integer;
    function MoveNext: Boolean;
    property Current: Integer read fCurrent;
  end;

  TEnumerable = class
    function GetEnumerator: TEnumerator;
  end;

function TEnumerable.GetEnumerator: TEnumerator;
begin
  Result := TEnumerator.Create;
end;

function TEnumerator.MoveNext: Boolean;
begin
  Inc(fCurrent);
  Result := fCurrent < 10;
end;

var
  e: TEnumerable;
  i: Integer;
begin
  for i in e do
    Writeln(i);
  Readln;
end.
Führt zu diesem Assembler Code in XE6:

Code:
Project9.dpr.36: for i in e do
0041C454 A1BC3E4200       mov eax,[$00423ebc]
0041C459 E876D8FFFF      call TEnumerable.GetEnumerator
0041C45E 8945EC          mov [ebp-$14],eax
0041C461 33C0             xor eax,eax
0041C463 55               push ebp
0041C464 68C5C44100       push $0041c4c5
0041C469 64FF30           push dword ptr fs:[eax]
0041C46C 648920           mov fs:[eax],esp
0041C46F EB25             jmp $0041c496
0041C471 8B45EC          mov eax,[ebp-$14]
0041C474 8B4004           mov eax,[eax+$04]
0041C477 A3C03E4200       mov [$00423ec0],eax
Project9.dpr.37: Writeln(i);
0041C47C A18CE64100       mov eax,[$0041e68c]
0041C481 8B15C03E4200     mov edx,[$00423ec0]
0041C487 E8E08CFEFF      call @Write0Long
0041C48C E8BB8FFEFF      call @WriteLn
0041C491 E8D27BFEFF      call @_IOTest
Project9.dpr.36: for i in e do
0041C496 8B45EC          mov eax,[ebp-$14]
0041C499 E856D8FFFF      call TEnumerator.MoveNext
0041C49E 84C0             test al,al
0041C4A0 75CF            jnz $0041c471
0041C4A2 33C0             xor eax,eax
0041C4A4 5A              pop edx
0041C4A5 59               pop ecx
0041C4A6 59               pop ecx
0041C4A7 648910           mov fs:[eax],edx
0041C4AA 68CCC44100       push $0041c4cc
Project9.dpr.37: Writeln(i);
0041C4AF 837DEC00         cmp dword ptr [ebp-$14],$00
0041C4B3 740F            jz $0041c4c4
0041C4B5 B201             mov dl,$01
0041C4B7 8B45EC          mov eax,[ebp-$14]
0041C4BA 8B08             mov ecx,[eax]
0041C4BC FF51FC          call dword ptr [ecx-$04]
0041C4BF 33C0             xor eax,eax
0041C4C1 8945EC          mov [ebp-$14],eax
0041C4C4 C3               ret
0041C4C5 E90EA0FEFF      jmp @HandleFinally
0041C4CA EBE3             jmp $0041c4af
Wie man sehen kann, stehen da sowohl die Zeile mit der Schleife als auch der einzeilige Rumpf zweimal drin. Daher stoppt der Debugger auch 2mal hintereindner in der Schleifenzeile beim Start (1. GetEnumerator 2. MoveNext) und noch einmal im Rumpf nachdem der letzte Aufruf von MoveNext false geliefert hat um den Enumerator aufzuräumen.

Zitat:

Zitat von Dejan Vu (Beitrag 1260060)
D.h.

Delphi-Quellcode:
Var
  foo : TList<TBar>;
...

Var
  bar : TList<TBar>;
Erzeugt doppelten Code?

Nein, das war mal in Delphi 2009 und 2010(glaube ich) noch so, aber spätestens in XE hat man programmweit nur eine Implementierung für exakt denselben closed generic Type. Allerdings hat du doppelten Code für
Delphi-Quellcode:
TList<TBar>
und
Delphi-Quellcode:
TList<TFoo>
obwohl der identisch ist. Übrigens ist
Delphi-Quellcode:
type TBarList = TList<TBar>;
kein neuer Typ sondern nur ein Alias. In 2009 oder 2010 hätte es das Problem gelöst, glaube ich - aber sicher bin ich da nicht mehr.

Zitat:

Zitat von JamesTKirk (Beitrag 1260073)
Ich persönlich find es gut, dass die Typüberprüfung bereits bei der Definiton des Generics stattfindet. Das hilft Fehler schneller zu finden, als wenn du das erst bei der Spezialisierung mit einem bestimmten Typ hast...

Leider ist das nur die halbe Wahrheit, denn manche Überprüfungen werden erst bei der Spezialisierung durchgeführt (weil ja dann erst das T fest steht). Dann stopt der Compiler nämlich gerne mal an irgendwelchen Zeilen, die überhaupt nix mit dem Fehler zu tun haben.

mquadrat 26. Mai 2014 11:49

AW: Generics - Pro und Contra
 
Also bei uns schaut der Code mit Generics auch gleich viel sauberer aus, als ohne. Vorher haben wir im Grunde immer eine Objectlist genommen und dann wild gecastet. Das ist doch jetzt sehr viel hübscher.

Patito 26. Mai 2014 14:02

AW: Generics - Pro und Contra
 
Zitat:

Zitat von jbg (Beitrag 1260080)
Zitat:

Zitat von JamesTKirk (Beitrag 1260073)
Ich persönlich find es gut, dass die Typüberprüfung bereits bei der Definiton des Generics stattfindet.

Mir wären C++ Templates lieber gewesen, dann müsste man nicht für jeden Typ einen eigenen Comparer nutzen, der allein durch den Aufruf der Compare-Funktion nicht an die Performance eines direkten "Wert1 = Wert2" herranreicht.

Container-Libraries waren für mich immer der wichtigste Grund Generics haben zu wollen.
Wenn ich jetzt aber sehe, dass ich meine Container (Maps, Multimaps, ...) ganz klassisch
schneller, kleiner und einfacher hinbekomme, fällt es mir nicht wirklich schwer auch
ganz auf Generics zu verzichten.

Ein simpler Typsicherer Wrapper für eine TObjektList mag noch ok sein, aber das reicht dann schon.
Komplexere Konstrukte gehören für mich in einen Code-Generatoren (mit so vielen Parametern und
Einstellungsmöglichkeiten wie man will) oder Metasprachen (die nach Pascal compilieren).
Man muss dafür nicht auch noch die ohnehin schon überladene Pascal-Syntax quälen.

jaenicke 26. Mai 2014 14:49

AW: Generics - Pro und Contra
 
Zitat:

Zitat von Patito (Beitrag 1260276)
Ein simpler Typsicherer Wrapper für eine TObjektList mag noch ok sein, aber das reicht dann schon.

Wobei das als Template mit kleinen Tricks auch schon in Delphi 5 ging.

Aber das ist ja nur der kleinste Teil der Vorteile von Generics. Allerdings sieht man oft die Möglichkeiten gar nicht. Das sieht man relativ oft, wenn jemand Generics noch nicht oft benutzt hat.

TiGü 26. Mai 2014 15:42

AW: Generics - Pro und Contra
 
Zitat:

Zitat von jaenicke (Beitrag 1260292)
Aber das ist ja nur der kleinste Teil der Vorteile von Generics. Allerdings sieht man oft die Möglichkeiten gar nicht. Das sieht man relativ oft, wenn jemand Generics noch nicht oft benutzt hat.

Kennt dazu jemand ein gutes Tutorial oder Blogeintrag, der einen alle Schweinereien mal auflistet?

jaenicke 26. Mai 2014 15:51

AW: Generics - Pro und Contra
 
Man findet schon in der Hilfe einiges, z.B. so etwas:
http://docwiki.embarcadero.com/RADSt...ts_in_Generics

Und ansonsten ist das Grundprinzip ja immer das gleiche, aber es ist so ähnlich wie objektorientierte Programmierung. Es reicht nicht aus OOP um der OOP willen anzuwenden, sondern man muss auch so denken, wenn man Strukturen entwirft. Das gilt für Generics genauso.

Der schöne Günther 26. Mai 2014 17:18

AW: Generics - Pro und Contra
 
Ich denke auch- In der reinen Benutzung ist bei Delphi eigentlich im Vergleich zu Java (Autoboxing ausgenommen, also sogar eigentlich besser als bei Java) oder C++ Templates genau gleich. Da kann man denke ich x-beliebige Lektüre nehmen.

Das "Hallo Welt" der Generics sind meistens wohl generische Stacks, also beispielsweise ein Integer oder Float-Stapel, je wie man grade lustig ist.

mquadrat 26. Mai 2014 19:20

AW: Generics - Pro und Contra
 
Ich benutze es auch im ORM. Hat ein Entity keine besonderen Anforderungen gibt es ein generisches Repository, das für's Laden verwendet wird. Also sowas in der Richtung:

Delphi-Quellcode:
  TEntityRepository.load<TKunde>(1311);
gibt eben den Kunden mit der ID 1311 zurück

Der schöne Günther 27. Mai 2014 09:32

AW: Generics - Pro und Contra
 
Außerdem lassen sich schon coole Sachen basteln wie beispielsweise hier von Uwe Raabe.

Hätte Delphi jetzt noch waschechte Lambda-Ausdrücke (wie seit Java 8 oder C++11) wäre man im siebten Himmel.

implementation 27. Mai 2014 09:55

AW: Generics - Pro und Contra
 
Zitat:

Zitat von Der schöne Günther (Beitrag 1260408)
Hätte Delphi jetzt noch waschechte Lambda-Ausdrücke (wie seit Java 8 oder C++11) wäre man im siebten Himmel.

Was Lambdas angeht kann ich Haskell empfehlen ;)

Stevie 27. Mai 2014 10:07

AW: Generics - Pro und Contra
 
Zitat:

Zitat von implementation (Beitrag 1260409)
Zitat:

Zitat von Der schöne Günther (Beitrag 1260408)
Hätte Delphi jetzt noch waschechte Lambda-Ausdrücke (wie seit Java 8 oder C++11) wäre man im siebten Himmel.

Was Lambdas angeht kann ich Haskell empfehlen ;)

Dann wohl eher C#, da stimmt auch der Rest :)

@Günther: Und Type Inference, die über einen simplen einzelnen Parametertypen hinausgeht.

stahli 27. Mai 2014 10:18

AW: Generics - Pro und Contra
 
Danke Euch.

Ich werde auch bei Generics bleiben und zusätzlich mit Interfaces arbeiten (hatte ich schon länger vor) und sehe bei beiden einige Vorteile.

Einzige Nachteile erscheinen mir, dass der Debugger mit den Generics etwas unkonventionell umgeht und bei XE3 wohl auch noch einige Bugs auftauchen können.

TiGü 27. Mai 2014 10:37

AW: Generics - Pro und Contra
 
Zitat:

Zitat von jaenicke (Beitrag 1260304)
Es reicht nicht aus OOP um der OOP willen anzuwenden, sondern man muss auch so denken, wenn man Strukturen entwirft. Das gilt für Generics genauso.

Das fällt mir etwas schwer!
Aber ich möchte gerne diese Hürde überwinden.

Was da rein technisch passiert ist mir schon halbwegs klar, nur komme ich ohne griffige Beispiele nicht so wirklich dahinter, wozu man das konkret brauchen könnte.

Bspw. der Quellcodeschnipsel aus dem DocWiki:
Delphi-Quellcode:
 type
   TFoo<T: ICloneable> ...
 
   TTest1 = class(TObject, ICloneable)
      ...
   end;
 
   TError = class
   end;
 
 var
   X: TFoo<TTest1>; //  TTest1 wird hier auf ICloneable-Unterstützung                    
                     //  zur Compilierzeit überprüft
Inwiefern kann sowas im richtigen Quelltext Anwendung finden?
Wo sind die Vorteile gegenüber, ich sage mal, herkömmlichen Lösungen?


Mit den meisten Design Pattern geht es mir ähnlich.
Wenn ich das noch nicht selbst programmiert / implementiert habe, bleibt es nebulös im Hirn. :pale:
Erst wenn ich versuche diese Pattern umzusetzen - und sei es mit simplen Beispielen wie Kaffeezubereitung (http://www.oreilly.de/catalog/hfdesi...apter/ch03.pdf) - macht es bei mir Klick.

Der schöne Günther 27. Mai 2014 11:04

AW: Generics - Pro und Contra
 
Drei Daumen hoch für das Buch! Das ist wirklich gut.

stahli 27. Mai 2014 11:34

AW: Generics - Pro und Contra
 
Ja, die Erklärungen der OH finde ich auch nicht so ergiebig.

Das Buch sieht super aus. :thumb:
Werde ich heute Abend weiter lesen (und bestimmt auch kaufen).


Alle Zeitangaben in WEZ +1. Es ist jetzt 06:05 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz