Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Warnung vor massivem Einsatz von Generics in Delphi (https://www.delphipraxis.net/216359-warnung-vor-massivem-einsatz-von-generics-delphi.html)

WladiD 16. Dez 2024 11:40

Delphi-Version: 11 Alexandria

Warnung vor massivem Einsatz von Generics in Delphi
 
Hallo zusammen,

ich überlege schon länger, ob ich diesen Post verfassen und meine Erkenntnisse mit der Community teilen sollte. Heute habe ich mich schließlich dazu überwunden.

Unsere Vorgeschichte: Wir setzen aktuell Delphi 11.3 ein. Vor einigen Jahren wurde im Rahmen der Modernisierungsarbeiten eine interne Empfehlung herausgegeben, wann immer möglich, generische Typen, entweder aus der internen Basisbibliothek oder aus dem Spring-Framework abzuleiten und zu verwenden. Grundsätzlich ist dieser Schritt begrüßenswert und richtig. Doch keiner aus unserem Team konnte zu diesem Zeitpunkt ahnen, welche langfristigen Folgen dies haben wird.

Die Folgen sind:
  • Die DCUs werden aufgebläht, da jeder in der entsprechenden Unit deklarierte generische Typ stumpf nach Template-Manier reinkompiliert wird. Wenn z.B. ein TDictionary<K,V> deklariert wurde, so ist jede Methode oder Feld mit K oder V auch in der DCU enthalten. Das an sich scheint noch nicht so schlimm zu sein, denn..

  • Nach erfolgter Kompilierung macht sich der Linker auf die Arbeit und sucht in allen zu linkenden DCUs nach gleichen generischen Typen, um sie nur einmalig in die Exe zu ziehen. Das ist ein löblicher Schritt, denn dadurch soll der Code-Bloat in der Exe so weit wie möglich eingedämmt werden.
    Beispiel: TDictionary<K,V> kommt in UnitA, UnitB und UnitC vor. In dem Fall befindet sich zwar in jeder DCU der replizierte Code dafür, aber nach getaner Arbeit des Linkers, kommt der Code für den konkreten generischen Typ nur einmal ins Binary.
    Hört sich doch gut an, wo ist das Problem?...

  • Nun leider kommt dieser Vorgang nicht ohne Aufwand aus. Der erste große Nachteil ist der Zeitaufwand, nochmals: Sowohl der Compiler als auch der Linker muss für jeden generischen Typ Arbeit leisten und zwar deutlich mehr als bei non-generic Typen. Ich muss zugeben, dass dieser Aufwand ziemlich lange kaum auffällt, aber ab einem bestimmten Punkt kippt. Ein interessanter Vergleich hierzu ist das CO2, welches die Menschheit nach und nach in die Atmosphäre entlässt, das war viele Jahrzehnte auch kein Problem…aber ich schweife ab 😉.
    Hier ein paar Zahlen von den zwei häufigsten generischen Typen aus dem Spring-Framework, die wir verwenden:
    IList<T> über 4000x in über 600 Units
    IDictionary<K,V> über 1000x in über 300 Units

    Bei uns braucht der Linker schon mal ca. 10-20 Sekunden.
    Hört sich ja nicht so schlimm an! Wo ist das Problem, schließlich haben wir genug Zeit…

  • Jetzt kommen wir zu einem Punkt, den wir nicht so einfach relativieren können:
    Der RAM-Verbrauch der dcc32, dem Delphi-Compiler, ist bei Verwendung von Generics immens. Wir können schon seit einigen Monaten nicht mehr in der IDE kompilieren, weil wir ständig EOutOfMemory-Exceptions bekommen. Die Lösung ist aktuell die Projektoption "MSBuild extern für die Compilierung verwenden". Damit hat die IDE scheinbar wieder Luft, aber bei der Erzeugung des Projekts sieht man im Task-Manager wie der RAM-Verbrauch der dcc32.exe so langsam über die 3 GB-Marke schreitet und dennoch hin und wieder mal mit einem EOutOfMemory abbricht.
    Ich weiß, dass die Compiler in der 12er-Version auch als 64-Bit-Versionen vorliegen und der Versionssprung steht bei uns auch an.
    Also doch alles gut?

  • Leider Nein: Sobald man das Projekt debuggt, welches extern über MS-Build erzeugt wurde, muss die IDE die RSM-Datei einlesen und da ist wieder der RAM-Verbrauch. Einmal den Debugger gestartet und schon steht die bds.exe auf 2,6 GB und man weiß schon, gleich passiert es "Zu wenig Arbeitsspeicher".

    Ich weiß nicht, wie die Prioritäten bei Embarcadero bzgl. der Umstellung der IDE auf 64-bit sind. Gelesen habe ich bisher nur etwas von "Fernziel". Auf meine Anfrage im Support hat man mir auch nichts in dieser Hinsicht sagen können.

  • Als wenn das schon nicht genug wäre…die DelphiLSP-Prozesse, welche für die Code-Vervollständigung verwendet werden, werden durch massiven Einsatz von Generics ebenfalls langsam, bis nicht mehr zu gebrauchen. Mal schauen, wie sich die 64-Bit-Versionen davon schlagen werden.

Ich bin ein Fan von Generics, aber unter diesen Umständen kann ich vom weiträumigen Einsatz in großen Delphi-Projekten nur abraten!

Das Spring4D-Framework, so sehr ich es auch mag, sticht hier leider nochmals unangenehm hervor, wahrscheinlich weil die Ableitungshierarchien sowohl in den Interfaces als auch in den implementierenden Klassen tief verschachtelt sind. In Spring4D v2 hat Stefan schon sehr viel gegen den Code-Bloat getan, aber gegen den hohen RAM-Verbrauch des Compilers/Linkers kann er nicht viel tun.

Dies kann nur Embarcadero fixen.

So, jetzt habe ich mal meinen Frust hier kund getan und bin gespannt, ob es irgendjemandem hier auch so ergeht?

jaenicke 16. Dez 2024 12:10

AW: Warnung vor massivem Einsatz von Generics in Delphi
 
Zitat:

Zitat von WladiD (Beitrag 1544292)
Ich weiß nicht, wie die Prioritäten bei Embarcadero bzgl. der Umstellung der IDE auf 64-bit sind. Gelesen habe ich bisher nur etwas von "Fernziel". Auf meine Anfrage im Support hat man mir auch nichts in dieser Hinsicht sagen können.

Frag zu solchen Themen am besten direkt bei Marco Cantù an. Auf der EKON klang das auf jeden Fall schon näher dran. Vielleicht kann Devid Espenschied dazu auch etwas sagen. Ich schicke ihm mal den Link zu dem Thread.

Redeemer 16. Dez 2024 13:46

AW: Warnung vor massivem Einsatz von Generics in Delphi
 
Ich danke dir für deinen Post. Geht mir auch alles so.

Ich find's interessant, dass sich nicht die DCU aufbläht, wo Variablen mit der generischen Klasse deklariert werden, sondern eine andere DCU, die viele von diesen Variablen genutzt werden - obwohl zu dem Zeitpunkt schon klar ist, welche Typen damit verwendet werden und welche nicht. Die Erklärung ist gut.

Der schöne Günther 16. Dez 2024 15:16

AW: Warnung vor massivem Einsatz von Generics in Delphi
 
Das war auf jeden Fall interessant zu lesen und kurzweilig erklärt 👍

Wir sind glücklicherweise noch nicht an dem Punkt wo dem Compiler/Linker grundsätzlich der Speicher ausgeht, aber vor allem die Linker-Zeiten machen wirklich echt keinen Spaß mehr.

Gibt es denn, außer dem Versuch die Toolkette auf 64 Bit umzustellen um das Problem zu verdecken, noch andere Entwicklungen in den letzten Jahren? Unsere Hauptanwendung ist immer noch auf Delphi 10.0 Seattle - Ist es in den letzten Versionen eher besser, schlechter oder unverändert?

Sinspin 16. Dez 2024 16:08

AW: Warnung vor massivem Einsatz von Generics in Delphi
 
Ohhhh, Danke dass du dir die Arbeit gemacht hast.

Wir verwenden 11.1. Dessen LSP mag scheinbar Generics generell nicht sonderlich. Zum Einsatz kommen die eigentlich fast nur wo es Delphi gerne so haben möchte.
Alles andere decke ich mit der guten alten TStringList oder Memtables ab.

AuronTLG 16. Dez 2024 16:14

AW: Warnung vor massivem Einsatz von Generics in Delphi
 
Äh, nur um sicherzugehen:

Die generischen Typen selbst, nicht die Klassen aus der Generics-unit sind das Problem, oder?
D.h. bei TList<T> ist "T" das Problem, und nicht die generische Liste selbst, bzw eine TList<TWasAuchImmer> mit einem spezifischen Typ TWasAuchImmer wäre unproblematisch?

WladiD 16. Dez 2024 17:32

AW: Warnung vor massivem Einsatz von Generics in Delphi
 
Zitat:

Zitat von AuronTLG (Beitrag 1544323)
Äh, nur um sicherzugehen:

Die generischen Typen selbst, nicht die Klassen aus der Generics-unit sind das Problem, oder?
D.h. bei TList<T> ist "T" das Problem, und nicht die generische Liste selbst, bzw eine TList<TWasAuchImmer> mit einem spezifischen Typ TWasAuchImmer wäre unproblematisch?

In deinem Beispiel ist die neue Entität TList<TWasAuchImmer> als Ganzes das "Problem", weil es für den Compiler/Linker extra Arbeit bedeutet, was er leider in der jetzigen Fassung nicht effizient macht.

Aber wie schon Eingangs geschrieben, wird es erst zum Problem, wenn die Masse an solchen generischen Entitäten eine gewisse Schwelle überschreitet.

WladiD 17. Dez 2024 05:12

AW: Warnung vor massivem Einsatz von Generics in Delphi
 
Zitat:

Zitat von Der schöne Günther (Beitrag 1544320)
Gibt es denn, außer dem Versuch die Toolkette auf 64 Bit umzustellen um das Problem zu verdecken, noch andere Entwicklungen in den letzten Jahren? Unsere Hauptanwendung ist immer noch auf Delphi 10.0 Seattle - Ist es in den letzten Versionen eher besser, schlechter oder unverändert?

Die Entwicklung von Delphi geht insgesamt in die richtige Richtung. Jede Version ist bisher etwas besser als die Vorherige geworden, insbesondere seit Marco Cantu die Entwicklung leitet und Idera der Eigentümer geworden ist.

TigerLilly 17. Dez 2024 07:16

AW: Warnung vor massivem Einsatz von Generics in Delphi
 
@WladiD: Ist das mit der Spring4D v2 immer noch so? Ich habe da das im Kopf (siehe weiter unten nach den Benchmarks:
https://delphisorcery.blogspot.com/2...lution-of.html

WladiD 17. Dez 2024 08:02

AW: Warnung vor massivem Einsatz von Generics in Delphi
 
Zitat:

Zitat von TigerLilly (Beitrag 1544337)
@WladiD: Ist das mit der Spring4D v2 immer noch so? Ich habe da das im Kopf (siehe weiter unten nach den Benchmarks:
https://delphisorcery.blogspot.com/2...lution-of.html

Spring4D v2 hat uns sehr beim Reduzieren des Code-Bloats geholfen. Unsere Exe ist beim Wechsel von Spring4D v1.x auf v2 von 170 auf ca. 110 MB geschrumpft, auch der RAM-Verbrauch des Compilers/Linkers sank dadurch deutlich. Doch unser Code wächst weiter und so kommen stetig neue generische Typen dazu und dies führt wieder zu den Problemen die ich Eingangs ausgeführt habe.

DevidEspenschied 17. Dez 2024 08:52

AW: Warnung vor massivem Einsatz von Generics in Delphi
 
Hallo WladiD,

insgesamt hast Du recht, angesichts der Architektur von Generics im Delphi-Compiler (und der Kernentscheidung, sie zu einem Kompilierungszeit-Tool ohne Laufzeitunterstützung zu machen) verursachen sie eine erhebliche Code-Aufblähung. Wir haben uns mit einigen Optimierungen befasst, und es gibt Raum für Verbesserungen bei der Kompilierungszeit und der Speichernutzung, aber solange wir nicht das gesamte System neu gestalten, werden die Verbesserungen in das aktuelle Modell fallen.

Entwicklern steht eine sehr wichtige Lösung, ein Workaround oder ein Hack zur Verfügung: die wiederholte Deklaration für dieselbe generische Typinstanz vermeiden. Zur Verdeutlichung: Ein generischer Typ ist TList<T>, eine generische Typinstanz ist TList<Integer>. Wenn man TList<Integer> in Unit A und Unit B hat, dann hat man zwei Typen, wobei alle Methoden in jede der beiden (oder 200) Units kopiert werden. Wenn man die Unit C erstellt, TList<Integer> dort einfügt, ihr einen bestimmten Typnamen gibt und diese Unit und diesen Typ verwendet, greift das Ganze auf die allgemeine Typverwendung zurück. Der Unterschied ist meines Wissens nach sehr signifikant und wir wissen, dass es bei vorhandenem Code etwas mühsam ist...

Der schöne Günther 17. Dez 2024 10:46

AW: Warnung vor massivem Einsatz von Generics in Delphi
 
Vielen Dank, das ganze Thema ist sehr anschaulich und hilfreich 👍

In meinem Fall bin ich mir unsicher abzuschätzen, ob das ganze in unserer Codebasis überhaupt schon ein nennenswertes Problem ist, oder in wie ferner Zukunft es problematisch werden könnte.

Ich kann mich erinnern, dass es ein Tool gab, das DCU-Dateien analysiert und darüber eine Aussage treffen konnte. Hat jemand den Namen noch parat?

Redeemer 17. Dez 2024 15:04

AW: Warnung vor massivem Einsatz von Generics in Delphi
 
Wirkt sich das Aufblähen der DCUs eigentlich auch auf die Größe der EXE aus?

jaenicke 17. Dez 2024 15:25

AW: Warnung vor massivem Einsatz von Generics in Delphi
 
Zitat:

Zitat von Redeemer (Beitrag 1544379)
Wirkt sich das Aufblähen der DCUs eigentlich auch auf die Größe der EXE aus?

Nein, das ist der Punkt, um den es geht. Der Linker wirft die doppelten Codeteile heraus und ersetzt diese durch Referenzen auf das erste Vorkommen des generischen Typs mit den passenden generischen Typparametern.

Wenn man nun sehr viele solcher Typen in den einzelnen Units hat, ist der Aufwand des Ersetzens sehr hoch. Und da die nötigen Informationen im Speicher benötigt werden, wird dafür viel Arbeitsspeicher benötigt.

freimatz 17. Dez 2024 16:31

AW: Warnung vor massivem Einsatz von Generics in Delphi
 
Habe ich es dann richtig verstanden? Statt
Delphi-Quellcode:
TCountList = TList<Integer>;
TWidthList = TList<Integer>;
TLengthList = TList<Integer>;
Wäre es dann also besser es so zu machen?
Delphi-Quellcode:
TIntegerList = TList<Integer>;

TCountList = type TIntegerList;
TWidthList = type TIntegerList;
TLengthList = type TIntegerList;

himitsu 17. Dez 2024 16:48

AW: Warnung vor massivem Einsatz von Generics in Delphi
 
Es wäre auch viel zu einfach, die jeweiligen TypBezeichner im Generic schnell zum voll-qualifizierten Namen auflösen und diesen Namen dann in iner kleinen Liste zu speichern und bei der Generic-Deklaration anfangs in der Liste zu schauen,
anstatt erstmal zu kompilieren und dann in einer fetten Liste nach dem Resultat zu suchen. :roll::stupid:

Rolf Frei 17. Dez 2024 16:54

AW: Warnung vor massivem Einsatz von Generics in Delphi
 
Hat Delphi 12.2 nicht einen 64 Bit Compiler und Linker erhalten, der aber idiotischerweise nur in der Enterprise+ Version enthalten ist. Ist damit das Memory Problem nicht gelöst? Oder mache ich hier ein Durcheinander?

Zitat:

Delphi 64-bit Compilers

RAD Studio version 12.2 Enterprise and Architect versions include 64-bit versions of the Delphi compilers. The new feature is referred to as 64-bit tools architecture. Using 64-bit tools allows users to have a larger memory space available to the compiler and, therefore, the ability to compile larger applications without running into memory issues.

The following are the new 64-bit tools:

Delphi Windows 32-bit target compiler
Delphi Windows 64-bit target compiler

Using the external MSBuild to compile, in the Delphi compiler configuration in the RAD Studio IDE Project Options dialog box, specify the version of the tools (including the command line compilers) to use in the “Preferred tool architecture” field.

Find the Delphi Windows command line compilers, dcc32.exe and dcc64.exe, in the RAD Studio installation bin64 folder (C:\Program Files (x86)\Embarcadero\Studio\23.0\bin64 by default), the. Similar executables still exist in the product bin folder, the command line compiler 32-bit versions.

himitsu 17. Dez 2024 16:59

AW: Warnung vor massivem Einsatz von Generics in Delphi
 
Jupp, es gibt einen zweiten Win64-Compiler und nur in Enterprise (nicht CE und Professional), und auch nur für C++Builder (glaub i) ... auch wenn dennoch in den Settings überall "Win64 (modern)" zu finden ist ... schon länger, selbst wenn ausschließlich Delphi (nicht RAD Studio) installiert ist. :freak:

Rolf Frei 17. Dez 2024 17:09

AW: Warnung vor massivem Einsatz von Generics in Delphi
 
Wir haben hier ja zum Einen was wir für eine Output gegenerieren wollen und zum Anderen eben neu, wie der Compiler/Linker selber compiliert ist, also 32 Bit oder bei den neuen mit 64 Bit. Bisher war wohl der Compiler und Linker 32 Bit Programme inkl 4GB Memorybegerenzung. Die neuen 64 Bit Compiler sind in nativem 64 Bit compiliert und haben damit diese Memorygrenze nicht mehr. Dass da die Doku von Win64 etc. redet ist ja so schon korrekt, denn auch bisher konnte man ja selber 32 + 64 bit Programme erzeugen.

himitsu 17. Dez 2024 18:04

AW: Warnung vor massivem Einsatz von Generics in Delphi
 
https://www.embarcadero.com/de/produ...w-in-12-athens
https://docwiki.embarcadero.com/RADS...on_Development
https://en.delphipraxis.net/topic/11...in-delphi-121/

WladiD 17. Dez 2024 18:35

AW: Warnung vor massivem Einsatz von Generics in Delphi
 
Zitat:

Zitat von Rolf Frei (Beitrag 1544393)
Hat Delphi 12.2 nicht einen 64 Bit Compiler und Linker erhalten, der aber idiotischerweise nur in der Enterprise+ Version enthalten ist. Ist damit das Memory Problem nicht gelöst? Oder mache ich hier ein Durcheinander?

Es ist zumindest eine Zwischenlösung, wenn das jeweilge Projekt wieder kompiliert werden kann, bei der die 32-bittige dcc32.exe sonst scheitert.

Das Problem dabei ist jedoch, dass ein entsprechend großes Projekt eine große RSM-Datei erzeugt. Diese wird auch zum lokalen Debuggen benötigt, wenn man das Projekt über MS-Build erzeugt. Das heißt, im ungünstigen Fall kann man vielleicht wieder kompilieren, aber nicht mehr debuggen, weil die IDE in ihr Speicherlimit reinläuft. Bei uns ist gleich beim ersten Debug-Versuch die bds.exe bei über 2GB. Nach einigen weiteren Debug-Versuchen kommt die geliebte EOutOfMemory...

himitsu 17. Dez 2024 19:11

AW: Warnung vor massivem Einsatz von Generics in Delphi
 
Jupp, alles, was nicht 32 Bit ist, muß ja remotegedebuggt werden, da die IDE und der InlineDebugger ja nur 32 Bit sind.

Vielleicht, wenn in 25 Jahren dann wieder, wenn die IDE auch 64 Bit ist.


Wobei es dennoch irgendwie komisch ist, dass die "gleichen" Debuginfos jeweils so unterschiedlich groß sind.

Dass eine billige ZIP-Komprimierung aber so extrem viel einspart, lässt einen irgendwie denken, dass da viel "nichts" drin steckt.

TurboMagic 17. Dez 2024 19:17

AW: Warnung vor massivem Einsatz von Generics in Delphi
 
Naja, ich glaube schon, dass wir viel früher als in 25 Jahren eine 64 Bit IDE sehen werden.
Nur wäre es natürlich klasse, wenn man den Speicherbedarf auch ohne Wechsel auf 64 Bit senken
könnte.

Die Methode "viele Hardware Ressourcen auf ein Problem zu schmeißen" ist ja auch nicht gerade
umweltfreundlich und kann auch an ihre Grenzen stoßen...

jaenicke 17. Dez 2024 20:23

AW: Warnung vor massivem Einsatz von Generics in Delphi
 
Zitat:

Zitat von TurboMagic (Beitrag 1544402)
Naja, ich glaube schon, dass wir viel früher als in 25 Jahren eine 64 Bit IDE sehen werden.

Was Marco Cantù auf der EKON gesagt hat, war so ungefähr:
Sie haben eine lauffähige 64-Bit IDE, die aber noch nicht stabil genug ist. Sie werden diese in den nächsten Monaten so weit haben, dass man damit zumindest testen kann. Und als erstes müssen ja z.B. die Komponentenhersteller ran. Von daher gehe ich mal davon aus, dass eine wirklich relativ normal für alle nutzbare 64-Bit IDE Richtung 2026 kommen könnte. Und dazwischen irgendwann eine Beta für alle.
Wie gesagt: Das ist meine Erinnerung und Interpretation dessen, was ich dort gehört habe.

Zitat:

Zitat von TurboMagic (Beitrag 1544402)
Nur wäre es natürlich klasse, wenn man den Speicherbedarf auch ohne Wechsel auf 64 Bit senken
könnte.

Da wurde ja auch schon dran gearbeitet, aber es sind halt auch sehr viele Informationen. Und wenn ich sehe, dass Visual Studio für ein echt sehr kleines Projekt schon 1,5 GiB Arbeitsspeicher benötigt und zum Kompilieren noch einmal 200 MiB dazu kommen, dann finde ich nicht, dass Delphi besonders viel braucht. Der Unterschied ist halt die plattformbedingte Beschränkung des Arbeitsspeichers bei Delphi.

Zitat:

Zitat von TurboMagic (Beitrag 1544402)
Die Methode "viele Hardware Ressourcen auf ein Problem zu schmeißen" ist ja auch nicht gerade
umweltfreundlich und kann auch an ihre Grenzen stoßen...

Bei den heutigen PCs, insbesondere Entwicklermaschinen, halte ich es aber für sehr sinnvoll, möglichst viel im Arbeitsspeicher für schnellen Zugriff zu halten.

Stevie 17. Dez 2024 21:28

AW: Warnung vor massivem Einsatz von Generics in Delphi
 
Zitat:

Zitat von DevidEspenschied (Beitrag 1544342)
Wenn man die Unit C erstellt, TList<Integer> dort einfügt, ihr einen bestimmten Typnamen gibt und diese Unit und diesen Typ verwendet, greift das Ganze auf die allgemeine Typverwendung zurück. Der Unterschied ist meines Wissens nach sehr signifikant

Leider falsch.

Zitat:

Zitat von freimatz (Beitrag 1544388)
Habe ich es dann richtig verstanden? Statt
Delphi-Quellcode:
TCountList = TList<Integer>;
TWidthList = TList<Integer>;
TLengthList = TList<Integer>;
Wäre es dann also besser es so zu machen?
Delphi-Quellcode:
TIntegerList = TList<Integer>;

TCountList = type TIntegerList;
TWidthList = type TIntegerList;
TLengthList = type TIntegerList;

Kompiliert leider nicht - E2574 - siehe auch https://quality.embarcadero.com/browse/RSP-27505

Zum allgemeinen Thema:
Hab ich schon 2014 bzw 2017 gesagt - siehe:
https://delphisorcery.blogspot.com/2...-annoying.html
https://quality.embarcadero.com/browse/RSP-18080

Zitat:

Zitat von WladiD (Beitrag 1544292)
Ich bin ein Fan von Generics, aber unter diesen Umständen kann ich vom weiträumigen Einsatz in großen Delphi-Projekten nur abraten!

Zur konkreten Problematik bzgl Spring4D 2.0 - es mag an den speziellen Typen liegen die ihr in den generischen Parametern nutzt, speziell wenn das sehr viele verschiedene record Typen sind, dann gibt es leider keine Möglichkeit, die Code folding Techniken anzuwenden, die ich in 2.0 eingebaut habe, aber ggf andere Möglichkeiten.

Zitat:

Zitat von WladiD (Beitrag 1544292)
generische Typen, entweder aus der internen Basisbibliothek oder aus dem Spring-Framework abzuleiten und zu verwenden

Ich weiß nicht, in welchem Maße ihr von den Klassen aus Spring4D ableitet, aber je nachdem wie ihr das macht und diese dann verwendet, kann das erst das Problem verursachen, was ich mit 2.0 massiv reduziert habe.

Schick mir gern eine pm oder email, wenn ihr diesbezüglich Hilfe von mir benötigt.

himitsu 17. Dez 2024 21:54

AW: Warnung vor massivem Einsatz von Generics in Delphi
 
Zitat:

Delphi-Quellcode:
TIntegerList = TList<Integer>;

TCountList = type TIntegerList;
TWidthList = type TIntegerList;
TLengthList = type TIntegerList;

Da das Klassen sind, kann man doch auch noch anders ableiten. :gruebel:
Delphi-Quellcode:
TIntegerList = TList<Integer>;

TCountList = class(TIntegerList);
TWidthList = class(TIntegerList);
TLengthList = class(TIntegerList);

WladiD 18. Dez 2024 07:06

AW: Warnung vor massivem Einsatz von Generics in Delphi
 
Zitat:

Zitat von DevidEspenschied (Beitrag 1544342)
Entwicklern steht eine sehr wichtige Lösung, ein Workaround oder ein Hack zur Verfügung: die wiederholte Deklaration für dieselbe generische Typinstanz vermeiden. Zur Verdeutlichung: Ein generischer Typ ist TList<T>, eine generische Typinstanz ist TList<Integer>. Wenn man TList<Integer> in Unit A und Unit B hat, dann hat man zwei Typen, wobei alle Methoden in jede der beiden (oder 200) Units kopiert werden. Wenn man die Unit C erstellt, TList<Integer> dort einfügt, ihr einen bestimmten Typnamen gibt und diese Unit und diesen Typ verwendet, greift das Ganze auf die allgemeine Typverwendung zurück. Der Unterschied ist meines Wissens nach sehr signifikant und wir wissen, dass es bei vorhandenem Code etwas mühsam ist...

Hallo David,

den Workaround über einen Typ-Alias für generische Interfaces hat ein Kollege schon vor einem Jahr probiert. Die Erkenntnis war damals, dass es nichts gebracht hat. Ich habe auch ein ähnliches Experiment in einem isolierten Test-Projekt durchgeführt und bin zum gleichen Ergebnis gekommen, aber ich muss zugeben, dass meine primäre Metrik die Größe der resultierenden Exe war und nicht die Größe der einzelnen DCUs. Dies ist wiederum auf die gute Arbeit des Linkers zurückzuführen.

Gestern hat ein Kollege, auf ihren Post hin, wieder ein Testprojekt gebaut und dort kann man tatsächlich feststellen, dass ein Alias IListString = IList<String> etwas gebracht hat, wenn die zugehörige Factory (TCollections.CreateList<String>) nicht in der konsumierenden Unit vorkommt, sondern über eine eigene Factory-Funktion in einer dedizierten Unit bezogen wird.

Das ist schon mal eine interessante neue Erkenntnis.

Da ich gerade dabei bin...
Wie ist Ihre Aussage bezüglich einer 64-Bit-IDE?
Wann gibt es ungefähr die erste Beta?

freimatz 18. Dez 2024 08:57

AW: Warnung vor massivem Einsatz von Generics in Delphi
 
Zitat:

Zitat von WladiD (Beitrag 1544413)
Da ich gerade dabei bin...
Wie ist Ihre Aussage bezüglich einer 64-Bit-IDE?
Wann gibt es ungefähr die erste Beta?

Bitte nicht, sondern separat. Das Thema Generics ist schon gross genug. :-D

MyRealName 18. Dez 2024 09:04

AW: Warnung vor massivem Einsatz von Generics in Delphi
 
Zitat:

Zitat von freimatz (Beitrag 1544416)
Zitat:

Zitat von WladiD (Beitrag 1544413)
Da ich gerade dabei bin...
Wie ist Ihre Aussage bezüglich einer 64-Bit-IDE?
Wann gibt es ungefähr die erste Beta?

Bitte nicht, sondern separat. Das Thema Generics ist schon gross genug. :-D

Ein Pun der feinsten Klasse, I commend you, good sir!

freimatz 18. Dez 2024 09:09

AW: Warnung vor massivem Einsatz von Generics in Delphi
 
Zitat:

Zitat von himitsu (Beitrag 1544406)
...
Da das Klassen sind, kann man doch auch noch anders ableiten. :gruebel:
Delphi-Quellcode:
TIntegerList = TList<Integer>;

TCountList = class(TIntegerList);
TWidthList = class(TIntegerList);
TLengthList = class(TIntegerList);

:shock: Äh - na klar geht auch. Vermutlich sogar etwas schöner.
Und hilft das?

jaenicke 18. Dez 2024 09:17

AW: Warnung vor massivem Einsatz von Generics in Delphi
 
Zitat:

Zitat von Stevie (Beitrag 1544404)
Zitat:

Zitat von DevidEspenschied (Beitrag 1544342)
Wenn man die Unit C erstellt, TList<Integer> dort einfügt, ihr einen bestimmten Typnamen gibt und diese Unit und diesen Typ verwendet, greift das Ganze auf die allgemeine Typverwendung zurück. Der Unterschied ist meines Wissens nach sehr signifikant

Leider falsch.

Das stimmt, aber wenn man eine eigene Klasse ableitet wie hier...
Zitat:

Zitat von freimatz (Beitrag 1544418)
Zitat:

Zitat von himitsu (Beitrag 1544406)
...
Da das Klassen sind, kann man doch auch noch anders ableiten. :gruebel:
Delphi-Quellcode:
TIntegerList = TList<Integer>;

TCountList = class(TIntegerList);
TWidthList = class(TIntegerList);
TLengthList = class(TIntegerList);

:shock: Äh - na klar geht auch. Vermutlich sogar etwas schöner.
Und hilft das?

Dann funktioniert es. Dann ist die konsumierende kompilierte Unit wieder entsprechend kleiner. Dafür reicht auch:
Delphi-Quellcode:
TCountList = class(TList<Integer>);
TTextList = class(TList<string>);
Hintergrund ist, dass entscheidend ist, wo der generische Parameter aufgelöst wird. Diese DCU enthält entsprechend den Code. Wenn man einen so aufgelösten abgeleiteten Typ ohne generischen Parameter anderswo verwendet, enthält die betreffende Unit auch nicht mehr den Code der ursprünglichen generischen Klasse, selbst wenn man weitere Klassen davon ableitet.

DevidEspenschied 18. Dez 2024 10:15

AW: Warnung vor massivem Einsatz von Generics in Delphi
 
Das Problem ist, dass generische Typen eine flexiblere Typkompatibilitätsregel bieten und mit der Typdeklaration wird diese Regel verletzt. Der Vorteil ist jedoch, dass man am Ende eine einzige Instanz des generischen Typs hat, viel weniger Code, schnellere Kompilierung und Verknüpfung... Ich weiß, dass dies nicht ideal ist, aber ich bezweifle, dass sich dies in nächster Zeit ändern wird.

Stevie 18. Dez 2024 14:21

AW: Warnung vor massivem Einsatz von Generics in Delphi
 
Zitat:

Zitat von WladiD (Beitrag 1544413)
Gestern hat ein Kollege, auf ihren Post hin, wieder ein Testprojekt gebaut und dort kann man tatsächlich feststellen, dass ein Alias IListString = IList<String> etwas gebracht hat, wenn die zugehörige Factory (TCollections.CreateList<String>) nicht in der konsumierenden Unit vorkommt, sondern über eine eigene Factory-Funktion in einer dedizierten Unit bezogen wird.

Der Alias für das Interface ist irrelevant - der ausschlaggebende Faktor ist das verlagern der parameterisierten Factory in ihre eigene Unit, so dass das in RSP-18080 beschriebene Problem nicht entsteht.

Zitat:

Zitat von DevidEspenschied (Beitrag 1544422)
Das Problem ist, dass generische Typen eine flexiblere Typkompatibilitätsregel bieten und mit der Typdeklaration wird diese Regel verletzt. Der Vorteil ist jedoch, dass man am Ende eine einzige Instanz des generischen Typs hat, viel weniger Code, schnellere Kompilierung und Verknüpfung... Ich weiß, dass dies nicht ideal ist, aber ich bezweifle, dass sich dies in nächster Zeit ändern wird.

Das Problem ist im zuvor verlinkten Issue eingehend beschrieben und sollte von Compilerentwicklern verstanden und lösbar sein. Der Compiler muss die intrinsic Functions wie GetTypeKind und ähnliche bereits dann auflösen, wenn die dcus generiert werden und nicht erst, wenn die finale Binary gebaut wird.

jaenicke 18. Dez 2024 15:16

AW: Warnung vor massivem Einsatz von Generics in Delphi
 
Zitat:

Zitat von Stevie (Beitrag 1544435)
Das Problem ist im zuvor verlinkten Issue eingehend beschrieben und sollte von Compilerentwicklern verstanden und lösbar sein. Der Compiler muss die intrinsic Functions wie GetTypeKind und ähnliche bereits dann auflösen, wenn die dcus generiert werden und nicht erst, wenn die finale Binary gebaut wird.

Das löst das Problem dann aber nur in manchen Fällen, insbesondere bei Spring4D mit Code Folding.

Wenn du aber irgendwelche generische Typen verwendest, die in nicht verbundenen Units liegen, müssen diese in der DCU enthalten bleiben, auch wenn der gleiche generische Parameter in 100 Units verwendet wird. Das kann dann erst der Linker lösen. Denn der Compiler kann ja nicht einfach in eine DCU einen Verweis auf eine fremde DCU einbauen, nur weil diese gerade mit kompiliert wird und den gleichen Typ enthält.

Rein theoretisch könnnte ich mir vorstellen, dass der Compiler die konkreten Typen in eigene DCUs auslagert, die dann von mehreren DCUs verwendet werden könnten. Die nötige Funktionalität gibt es aktuell aber nicht und da hängt dann noch einiges mehr dran, angefangen bei der Benennung dieser Dateien. Trotzdem wäre es die einzige Lösung, die mir einfällt, wie das ganze überhaupt allgemein lösbar sein könnte, sprich ohne dass der Linker das alles noch einmal komplett aussiebt.

Stevie 14. Jan 2025 12:26

AW: Warnung vor massivem Einsatz von Generics in Delphi
 
Zitat:

Zitat von jaenicke (Beitrag 1544383)
Zitat:

Zitat von Redeemer (Beitrag 1544379)
Wirkt sich das Aufblähen der DCUs eigentlich auch auf die Größe der EXE aus?

Nein, das ist der Punkt, um den es geht. Der Linker wirft die doppelten Codeteile heraus und ersetzt diese durch Referenzen auf das erste Vorkommen des generischen Typs mit den passenden generischen Typparametern.

Leider funktioniert das bei "normalen" generics nicht so wirklich gut, wenn ich
Delphi-Quellcode:
TList<TApfel>
und
Delphi-Quellcode:
TList<TBirne>
habe (beides sind Klassen), gibt es den code für
Delphi-Quellcode:
TList<T>
2mal in der Binary (einmal für TApfel und einmal für TBirne) obwohl er komplett identisch ist. Bei Spring4d foldet er das intern auf die implementierung von TList<TObject>. Das geht, da die collections Interface basiert sind.
Delphi-Quellcode:
IList<TApfel>
und
Delphi-Quellcode:
IList<TBirne>
erzeugen nur wenig Binärcode und dahinter hängt dann jeweils dieselbe implementierung (mehr oder weniger, gibt noch einige Details, die hier aber irrelevant sind).

Schwierig wird es dann bei assoziativen Collections, also solchen, wo man 2 generische Parameter hat, da sich die Kombinationen dann multiplizieren. Das kann man inzwischen sehr gut sehen, wenn man eine FMX Anwendung oder eine Anwendung mit einer Drittanbieter Bibliothek verwendet, die auch ausgiebig Gebrauch von Generics machen, z.B. DevExpress. Da hat man dann mitunter einen zweistelligen Prozentanteil an Binärgröße nur mit Zeugs aus System.Generics.Collections verbraten.


Alle Zeitangaben in WEZ +1. Es ist jetzt 14:31 Uhr.

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