AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Sprachen und Entwicklungsumgebungen Object-Pascal / Delphi-Language Warnung vor massivem Einsatz von Generics in Delphi
Thema durchsuchen
Ansicht
Themen-Optionen

Warnung vor massivem Einsatz von Generics in Delphi

Ein Thema von WladiD · begonnen am 16. Dez 2024 · letzter Beitrag vom 25. Sep 2025
Antwort Antwort
Seite 4 von 4   « Erste     234   
Benutzerbild von jaenicke
jaenicke

Registriert seit: 10. Jun 2003
Ort: Berlin
10.127 Beiträge
 
Delphi 12 Athens
 
#31

AW: Warnung vor massivem Einsatz von Generics in Delphi

  Alt 18. Dez 2024, 09:17
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...
...
Da das Klassen sind, kann man doch auch noch anders ableiten.
Delphi-Quellcode:
TIntegerList = TList<Integer>;

TCountList = class(TIntegerList);
TWidthList = class(TIntegerList);
TLengthList = class(TIntegerList);
Ä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.
Sebastian Jänicke
AppCentral

Geändert von jaenicke (18. Dez 2024 um 09:22 Uhr)
  Mit Zitat antworten Zitat
EKON 29
DevidEspenschied

Registriert seit: 7. Sep 2006
Ort: Berlin
449 Beiträge
 
Delphi 12 Athens
 
#32

AW: Warnung vor massivem Einsatz von Generics in Delphi

  Alt 18. Dez 2024, 10:15
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.
Devid
Devid Espenschied
Pre-Sales Consultant
Embarcadero Germany GmbH
germany.info@embarcadero.com

Kein Support per PN
  Mit Zitat antworten Zitat
Benutzerbild von Stevie
Stevie

Registriert seit: 12. Aug 2003
Ort: Soest
4.058 Beiträge
 
Delphi 10.1 Berlin Enterprise
 
#33

AW: Warnung vor massivem Einsatz von Generics in Delphi

  Alt 18. Dez 2024, 14:21
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.

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.
Stefan
“Simplicity, carried to the extreme, becomes elegance.” Jon Franklin

Delphi Sorcery - DSharp - Spring4D - TestInsight
  Mit Zitat antworten Zitat
Benutzerbild von jaenicke
jaenicke

Registriert seit: 10. Jun 2003
Ort: Berlin
10.127 Beiträge
 
Delphi 12 Athens
 
#34

AW: Warnung vor massivem Einsatz von Generics in Delphi

  Alt 18. Dez 2024, 15:16
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.
Sebastian Jänicke
AppCentral
  Mit Zitat antworten Zitat
Benutzerbild von Stevie
Stevie

Registriert seit: 12. Aug 2003
Ort: Soest
4.058 Beiträge
 
Delphi 10.1 Berlin Enterprise
 
#35

AW: Warnung vor massivem Einsatz von Generics in Delphi

  Alt 14. Jan 2025, 12:26
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 TList<TApfel> und TList<TBirne> habe (beides sind Klassen), gibt es den code für 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. IList<TApfel> und 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.
Stefan
“Simplicity, carried to the extreme, becomes elegance.” Jon Franklin

Delphi Sorcery - DSharp - Spring4D - TestInsight

Geändert von Stevie (14. Jan 2025 um 12:30 Uhr)
  Mit Zitat antworten Zitat
Redeemer

Registriert seit: 19. Jan 2009
Ort: Kirchlinteln (LK Verden)
1.158 Beiträge
 
Delphi 2009 Professional
 
#36

AW: Warnung vor massivem Einsatz von Generics in Delphi

  Alt 25. Sep 2025, 11:26
Ich möchte das hier nochmal ausgraben.

Ich habe folgende Units:
  • Dictionaries.pas: definiert ein TWuppdiCtionaryInteger<T> = class(TDictionary<Integer, T>) ... end; mit einigen Zusatzfunktionen (z.B. eine ENotFoundException mit dem Namen des fehlenden Keys sowie eine sortierte Liste der Keys). Es gibt sie analog noch mit einigen weiteren Datentypen neben Integer als Key (string, TPoint, usw.).
  • Etwa 10 verschiedene *.Stammdaten.pas: Definieren jeweils 10 bis 20 Records und deklarieren globale Variablen für Dictionaries davon. Zum Beispiel type TWuppdi = record ... end; und var Wuppdis: TWuppdiCtionaryInteger<TWuppdi>; .
  • Cache.pas: Erstellt und füllt beim Start des Programms die Dictionary-Variablen, im genannten Beispiel also Wuppdis . Das ganze läuft in einem Thread.
Alle DCUs, die *.Stammdaten.pas verwenden, blähen sich auf. Insbesondere natürlich Cache.dcu, die bei mir jetzt so um die 8 MiB groß ist.

Was ich probiert habe:
  1. Ich habe eine *.Dictionarytypen.pas hinzugefügt, die den verwendeten TWuppdiCtionaryInteger<T> einen Namen gibt: type TDictWuppdis = TWuppdiCtionaryInteger<TWuppdi>; . Danach habe ich eine *.Cache.pas hinzugefügt, mit den var Wuppdis: TDictWuppdis; , und die uses der anderen Units entsprechend angepasst. Das hat die EXE aber nur weiter aufgebläht. Die allgemeine Cache.dcu ist gleich groß geblieben.
  2. Ich habe dann von *.Dictionarytypen.pas die Typdefinition in eine Vererbung geändert: type TDictWuppdis = class(TWuppdiCtionaryInteger<TWuppdi>); Dementsprechend musste ich in der allgemeinen Cache.pas den verwendeten Konstruktor auf den des neuen Typs ändern. Das hat funktioniert.
  3. Also habe ich anschließend nochmal die Typdefinition in einen Alias zurückgeändert, alles andere aber so gelassen (also z.B. weiter den Konstruktor der neuen Namen verwendet). Dann war es wieder so groß wie nach Versuch 1. Cache.dcu hingegen wurde sogar noch marginal größer als in Versuch 1.
  4. Anschließend habe ich ausgehend von Versuch 2 den Inhalt beider neuen Units zurück in *.Stammdaten.pas kopiert und die beiden neuen Dateien gelöscht. Gleiches Ergebnis wie Versuch 2. Reicht also auch.

tl;dr: Ich möchte Devids Post somit zwei Dinge hinzufügen:
  • Es reicht nicht aus, seinen Generics-verwendenden Typen einfach nur einen Namen zu geben (type IntDict = TDictionary<Integer>; ), selbst wenn man nur noch diesen neuen Namen verwendet. Man muss sie zwingend ableiten (type IntDict = class(TDictionary<Integer>); ), was dann bekanntlich die Verwendung des neuen Namens im Regenfall erzwingt.
  • Edge Case: Das Problem tritt auch auf, wenn – um bei Devids Beispiel zu bleiben – eine globale Variable des Typs TList<Integer> in Unit A deklariert und in Unit B erstellt wird. Schon der Aufruf des Konstruktors legt offenbar die komplette Klasse in der DCU ein weiteres Mal an. Sind Variablen des Typs TList<Integer> allerdings nur in Unit A deklariert, kann auch die neue Klasse dort abgeleitet werden und es muss keine Unit C geben.

Mich verwundert aber: In beiden erfolgreichen Versuchen (2 und 4) ist neben der EXE nur die allgemeine Cache.dcu kleiner geworden. Andere DCUs sind nicht kleiner geworden. Ich habe das darauf geschoben, dass der Konstruktur ursprünglich die Klassendeklaration (Wuppdis := TWuppdiCtionaryInteger<TWuppdi>.Create(); ) enthielt, kann mir dann aber nicht erklären, warum ein Alias ohne Ableitung (type IntDict = TDictionary<Integer>; ) und dessen ausschließliche Verwendung keinerlei Verbesserung bringen.

inb4: Ja, ich weiß, globale Variablen sind Böse und so.
Delphi 2010.
Janni
2005 PE, 2009 PA, XE2 PA

Geändert von Redeemer (25. Sep 2025 um 11:28 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.840 Beiträge
 
Delphi 12 Athens
 
#37

AW: Warnung vor massivem Einsatz von Generics in Delphi

  Alt 25. Sep 2025, 13:13
Hast du das mal mit einem halbwegs aktuellen Delphi gegengecheckt? Gerade in dem Bereich hat sich in den letzten Jahren immerhin schon einiges getan.

Ich könnte das auch tun wenn du ein brauchbares Beispielprojekt bereitstellst.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Benutzerbild von jaenicke
jaenicke

Registriert seit: 10. Jun 2003
Ort: Berlin
10.127 Beiträge
 
Delphi 12 Athens
 
#38

AW: Warnung vor massivem Einsatz von Generics in Delphi

  Alt 25. Sep 2025, 13:23
Hast du das mal mit einem halbwegs aktuellen Delphi gegengecheckt? Gerade in dem Bereich hat sich in den letzten Jahren immerhin schon einiges getan.
Oh ja. Die Generics von Delphi 2009 waren quasi nicht brauchbar und die von 2010 sind wie eine Pferdekutsche gegenüber einem modernen Auto verglichen mit den heutigen Generics.

Ich hatte ein Projekt veröffentlicht mit 10.4 oder so und wurde gefragt, ob ich auch alte Delphiversionen unterstützen würde. Mit jeder Version, die ich zurückgegangen bin, musste ich Teile des Quelltextes streichen. Und als ich dann bei 2009 ankam, habe ich es behandelt wie Delphi 7, weil einfach die Generics gar nicht klappten.
Sebastian Jänicke
AppCentral
  Mit Zitat antworten Zitat
Redeemer

Registriert seit: 19. Jan 2009
Ort: Kirchlinteln (LK Verden)
1.158 Beiträge
 
Delphi 2009 Professional
 
#39

AW: Warnung vor massivem Einsatz von Generics in Delphi

  Alt 25. Sep 2025, 14:59
Die Aussage bezog sich auf mein Hauptprojekt, das ich in der Firma (alleine) entwickle. Es benutzt zwar trotz seiner Größe extrem wenige Drittkomponenten (ich glaube 3 oder 4), aber für die UniDACs haben wir keine neuere Lizenz und nur DCUs.

Müsste also erst ein Minimalbeispiel erstellen.

Echte Probleme mit Generics (irgendwas funktioniert nicht/nicht richtig) hatte ich nicht, auch nicht im Vergleich zu neueren CEs bei Privatprojekten.
Janni
2005 PE, 2009 PA, XE2 PA
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 4 von 4   « Erste     234   


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 20:19 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