Dabei ist das gerade ein recht einfaches Beispiel im Vergleich zu manch anderem, was man mit Generics anstellen kann...fliegermichl hat geschrieben: Fr 22. Apr 2022, 09:24 Das andere Beispiel mit der generischen Sortierung ist mir zu hoch oder ich muss es wohl noch 10 mal lesen um es begreifen zu können![]()
Generics for Dummies
-
- Beiträge: 962
- Registriert: Mi 3. Jun 2020, 07:18
- OS, Lazarus, FPC: L 2.0.8, FPC Trunk, OS Win/Linux
- CPU-Target: Aarch64 bis Z80 ;)
- Wohnort: München
Re: Generics for Dummies
FPC Compiler Entwickler
- fliegermichl
- Lazarusforum e. V.
- Beiträge: 1650
- Registriert: Do 9. Jun 2011, 09:42
- OS, Lazarus, FPC: Lazarus Fixes FPC Stable
- CPU-Target: 32/64Bit
- Wohnort: Echzell
Re: Generics for Dummies
Naja, es heisst ja auch Generics for Dummies. Also scheine ich hier richtig zu seinPascalDragon hat geschrieben: Fr 22. Apr 2022, 09:40Dabei ist das gerade ein recht einfaches Beispiel im Vergleich zu manch anderem, was man mit Generics anstellen kann...fliegermichl hat geschrieben: Fr 22. Apr 2022, 09:24 Das andere Beispiel mit der generischen Sortierung ist mir zu hoch oder ich muss es wohl noch 10 mal lesen um es begreifen zu können![]()

Re: Generics for Dummies
Ich sag doch: Dummies brauchen keine Generics!fliegermichl hat geschrieben: Fr 22. Apr 2022, 11:24 Naja, es heisst ja auch Generics for Dummies. Also scheine ich hier richtig zu sein![]()
Aber auf mich will ja keiner hören...

Re: Generics for Dummies
Hi
Schön das es diess Thema schon gibt und das auch schon so viel Infos zusammengetragen wurden.
Ich selbst nutze Generics schon eine Weile für spezielle Listen von eigenen Klassen. Es ist einfach einfacher diese direkt aus der Liste als "korrekten" Typ zu erhalten.
Nach stundenlangen Suchen imNetz bin ich noch nicht auf die richtige Lösung gestossen und wollte deshalb hier mal nachfragen.
Für meine EBML lib bräuchte ich folgendes (ist ein c++ code)
Für mich sieht das so als könnte man dies mit Generics nachbilden.
Ein Master Element hat eine Liste wo andere EBML-Typ-Elemente gespeichert sind.
All die Elemente sind von TEBMLElement abgeleitet und die Liste ist spezialisiert auf den Typ TEBMLElement.
Momentan muss ich das ganze wie folgt aufrufen:
Leider funktioniert der Generic Code nicht. Innerhalb der Generic function kann ich nicht mal auf die "const Master" zugreifen, obwohl ich im Funktionskopf den Type für "Master" festlegen kann: TEbmlMaster.
Ich nutze FPC 3.2.2 Lazarus 3.0
Was mache ich falsch?
Schön das es diess Thema schon gibt und das auch schon so viel Infos zusammengetragen wurden.
Ich selbst nutze Generics schon eine Weile für spezielle Listen von eigenen Klassen. Es ist einfach einfacher diese direkt aus der Liste als "korrekten" Typ zu erhalten.
Nach stundenlangen Suchen imNetz bin ich noch nicht auf die richtige Lösung gestossen und wollte deshalb hier mal nachfragen.
Für meine EBML lib bräuchte ich folgendes (ist ein c++ code)
Code: Alles auswählen
template <typename Type>
Type & GetChild(EbmlMaster & Master)
{
return *(static_cast<Type *>(Master.FindFirstElt(EBML_INFO(Type), true)));
}
// call with
// MyDocType = GetChild<EDocType>(TestHead);
Code: Alles auswählen
generic function GetChild<T>(const Master: TEbmlMaster): T;
begin
Result := T(Master.GetChild(T));
end;
//call: // MyDocType = specialize GetChild<TDocType>(aMaster);
All die Elemente sind von TEBMLElement abgeleitet und die Liste ist spezialisiert auf den Typ TEBMLElement.
Momentan muss ich das ganze wie folgt aufrufen:
Code: Alles auswählen
begin...
MyDocType := TDocType(Master.GetChild(TDocType))
end;
Ich nutze FPC 3.2.2 Lazarus 3.0
Was mache ich falsch?
-
- Beiträge: 6955
- Registriert: Do 2. Jan 2014, 17:21
- OS, Lazarus, FPC: Linux (die neusten Trunk)
- CPU-Target: 64Bit
- Wohnort: Schweiz
Re: Generics for Dummies
Ist die volle Unterstützung von generic nicht FPC 3.3.x vorbehalten ?Ich nutze FPC 3.2.2 Lazarus 3.0
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot
Mit Java und C/C++ sehe ich rot
Re: Generics for Dummies
Ich habe mir eben mit FPdeluxe die neuste Lazarus Version und FPC 3.3.1 installiert, aber auch da geht der Generic Code nicht.
"Master" ist nach wie vor nur Text, nix was der Compiler kennt.
"Master" ist nach wie vor nur Text, nix was der Compiler kennt.
-
- Beiträge: 962
- Registriert: Mi 3. Jun 2020, 07:18
- OS, Lazarus, FPC: L 2.0.8, FPC Trunk, OS Win/Linux
- CPU-Target: Aarch64 bis Z80 ;)
- Wohnort: München
Re: Generics for Dummies
Bitte gib ein vollständiges, minimales, selbstständiges Beispiel und nicht nur Codeschnipsel.hubblec4 hat geschrieben: Do 4. Jul 2024, 17:22 Für mich sieht das so als könnte man dies mit Generics nachbilden.
Ein Master Element hat eine Liste wo andere EBML-Typ-Elemente gespeichert sind.Code: Alles auswählen
generic function GetChild<T>(const Master: TEbmlMaster): T; begin Result := T(Master.GetChild(T)); end; //call: // MyDocType = specialize GetChild<TDocType>(aMaster);
All die Elemente sind von TEBMLElement abgeleitet und die Liste ist spezialisiert auf den Typ TEBMLElement.
Momentan muss ich das ganze wie folgt aufrufen:
Leider funktioniert der Generic Code nicht. Innerhalb der Generic function kann ich nicht mal auf die "const Master" zugreifen, obwohl ich im Funktionskopf den Type für "Master" festlegen kann: TEbmlMaster.Code: Alles auswählen
begin... MyDocType := TDocType(Master.GetChild(TDocType)) end;
Ich nutze FPC 3.2.2 Lazarus 3.0
Was mache ich falsch?
FPC Compiler Entwickler
Re: Generics for Dummies
Code: Alles auswählen
generic function GetChild<T>(const Master: TEbmlMaster): T;
begin
Result := T(Master.GetChild(T));
end;
Fürs testen kann man mein Master gegen eine einfache StringList austauschen.
Code: Alles auswählen
generic function GetChild<T>(const SList: TStringList): T;
begin
SList. // <--- das geht bereits nicht. An der Stelle nach dem Punkt kann man kein STRG+Leertaste aufrufen.
Result := T(SList.Objects[0]);
end;
-
- Beiträge: 962
- Registriert: Mi 3. Jun 2020, 07:18
- OS, Lazarus, FPC: L 2.0.8, FPC Trunk, OS Win/Linux
- CPU-Target: Aarch64 bis Z80 ;)
- Wohnort: München
Re: Generics for Dummies
Ich sehe hier noch immer keinen kompletten Code. Gib mir bitte etwas, dass ich as-is der fpc.exe vorwerfen kann, da ich keine Lust habe zu raten, was du eventuell noch zusätzlich machst.
FPC Compiler Entwickler
Re: Generics for Dummies
OK. Ich habs mal in ein mini Programm gepackt.
Edit: habe da mal noch eine var angelegt für das auffangen des MemStreams.
Und was mich wundert, es kompiliert und scheint zu klappen.
Ausser eben das man in der generic function nicht auf die Variablen zugreifen kann im Code-Editor.
Aber wenn man es so "hinschreibt" das es alles passt dann scheint der compiler alles richtig zu machen.
Code: Alles auswählen
program generic_function;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}
cthreads,
{$ENDIF}
Classes
{ you can add units after this };
generic function GetChild<T>(const SList: TStringList): T;
begin
//SList. // <--- das geht bereits nicht. An der Stelle nach dem Punkt kann man kein STRG+Leertaste aufrufen.
Result := T(SList.Objects[0]);
end;
var
SList: TStringList;
m: TMemoryStream;
begin
SList := TStringList.Create;
SList.OwnsObjects := true;
SList.AddObject('MStream', TMemoryStream.Create);
m := specialize GetChild<TMemoryStream>(SList);
SList.Free;
end.
Und was mich wundert, es kompiliert und scheint zu klappen.
Ausser eben das man in der generic function nicht auf die Variablen zugreifen kann im Code-Editor.
Aber wenn man es so "hinschreibt" das es alles passt dann scheint der compiler alles richtig zu machen.
-
- Beiträge: 6955
- Registriert: Do 2. Jan 2014, 17:21
- OS, Lazarus, FPC: Linux (die neusten Trunk)
- CPU-Target: 64Bit
- Wohnort: Schweiz
Re: Generics for Dummies
Dann ist wohl Lazarus (noch) nicht auf diese Funktion angepasst.Ausser eben das man in der generic function nicht auf die Variablen zugreifen kann im Code-Editor.
Aber wenn man es so "hinschreibt" das es alles passt dann scheint der compiler alles richtig zu machen.
Dies habe ich auch schon mehrmals erlebt.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot
Mit Java und C/C++ sehe ich rot
Re: Generics for Dummies
Ok, gut zu wissen. dann muss da Lazarus selbst noch etwas angepasst werden.
Nachdem ich das alles getestet hatte und es zu funktionieren schien, habe ich dann alles in meiner EBML Lib versucht einzubauen.
Dort habe ich wie gesagt statt der TStringList, eine eigene Klasse namens TEbmlMaster.
Wenn ich das nun alles dort so einbaue, dan mekert diesmal der compiler und sagt "Illegal expresion"
Dann habe ich überlegt ob es an meiner Klasse liegen kann. Habe dann mal eine minimal Klasse erstellt und damit gehts auch wieder.
Keine Ahung warum das bei meiner Lib nicht geht.
Die ganze Lib hier zu posten wäre viel zu viel.
EDIT:
Fehler gefunden. Nun klappt es auch in der EBML lib.
Nachdem ich das alles getestet hatte und es zu funktionieren schien, habe ich dann alles in meiner EBML Lib versucht einzubauen.
Dort habe ich wie gesagt statt der TStringList, eine eigene Klasse namens TEbmlMaster.
Wenn ich das nun alles dort so einbaue, dan mekert diesmal der compiler und sagt "Illegal expresion"
Dann habe ich überlegt ob es an meiner Klasse liegen kann. Habe dann mal eine minimal Klasse erstellt und damit gehts auch wieder.
Keine Ahung warum das bei meiner Lib nicht geht.
Die ganze Lib hier zu posten wäre viel zu viel.
EDIT:
Fehler gefunden. Nun klappt es auch in der EBML lib.
Re: Generics for Dummies
Da nun alles funktioniert möchte ich gerne noch etwas beisteuern was dem ein oder anderen vielleicht hilft.
Das Ziel des ganzen war ja den geschrieben Code etwas zu verkleinern und leserlicher zu machen.
Mit der generic function GetChild spart man sich somit das casten an jeder Stelle des Codes zu schreiben. Dafür muss man nun aber immer das keyword "specialize" schreiben wenn man die generic function aufrufen will.
Daher möchte ich an der Stelle etwas "Werbung" machen für die Code-Macro Funktion.
Vielleicht liesst das ja mal ein FreePascal Entwickler, denn es wäre super genial wenn die Macros auch Paramater verstehen könnten (so wie in c++).
Dann würde das ganze so aussehen.
Das Ziel des ganzen war ja den geschrieben Code etwas zu verkleinern und leserlicher zu machen.
Mit der generic function GetChild spart man sich somit das casten an jeder Stelle des Codes zu schreiben. Dafür muss man nun aber immer das keyword "specialize" schreiben wenn man die generic function aufrufen will.
Daher möchte ich an der Stelle etwas "Werbung" machen für die Code-Macro Funktion.
Code: Alles auswählen
program generic_function;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}
cthreads,
{$ENDIF}
Classes
{ you can add units after this };
{$MACRO ON}
{$define GET_CHILD:=specialize GetChild}
generic function GetChild<T>(const SList: TStringList): T;
begin
Result := T(SList.Objects[0]);
end;
var
SList: TStringList;
m: TMemoryStream;
begin
SList := TStringList.Create;
SList.OwnsObjects := true;
SList.AddObject('MStream', TMemoryStream.Create);
//m := specialize GetChild<TMemoryStream>(SList);
m := GET_CHILD<TMemoryStream>(SList);
SList.Free;
end.
Dann würde das ganze so aussehen.
Code: Alles auswählen
program generic_function;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}
cthreads,
{$ENDIF}
Classes
{ you can add units after this };
{$MACRO ON}
{$define GET_CHILD(a,b):=specialize GetChild<a>(b)}
generic function GetChild<T>(const SList: TStringList): T;
begin
Result := T(SList.Objects[0]);
end;
var
SList: TStringList;
m: TMemoryStream;
begin
SList := TStringList.Create;
SList.OwnsObjects := true;
SList.AddObject('MStream', TMemoryStream.Create);
m := GET_CHILD(TMemoryStream, SList);
SList.Free;
end.
-
- Beiträge: 2141
- Registriert: Di 23. Sep 2014, 17:46
- OS, Lazarus, FPC: Win10 | Linux
- CPU-Target: x86_64
Re: Generics for Dummies
Oder du benutzt einfach Mode Delphi und ImplicitSpecialization und brauchst auch kein Specialize und oftmals nicht mal mehr <type>:
PS: implicitfunctionspecialization braucht Trunk
Code: Alles auswählen
program Project1;
{$mode Delphi}
{$ModeSwitch implicitfunctionspecialization}
procedure GenericWrite<T>(const Val: T);
begin
WriteLn(Val);
end;
begin
GenericWrite(42); // Integer
GenericWrite('42'); // String
GenericWrite(3.14); // Double
GenericWrite<Single>(3.14); // Single
end.