Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Operator Overloading for CLASSES (not records!) (https://www.delphipraxis.net/203202-operator-overloading-classes-not-records.html)

TheSledgeHammer 23. Jan 2020 12:49

Delphi-Version: 10.3 Rio

Operator Overloading for CLASSES (not records!)
 
Hallo Community,

zunächst mal: ja, der Titel ist absichtlich in Englisch, damit ihn Leute auch finden, wenn sie in Google englische Begriffe eingeben.

Zur Sache: Laut der aktuellsten Doku von Emba (Stand 23.01.2020) bzgl. der Überladung von Operatoren steht ganz klar im Text geschrieben, dass dieses Feature ausdrücklich auch für Klassen verwendbar wäre und nicht nur für Records:
http://docwiki.embarcadero.com/RADSt...#Codebeispiele

Ihr könnt es euch denken: der Konjunktiv steht da nicht umsonst. So, wie es dort beschrieben ist, geht es natürlich nicht - wäre auch zu schön gewesen, aber warum überrascht mich das nicht? :roll:
Es hat mich schon stutzig gemacht, dass die Codebeispiele nur für Records geschrieben sind, aber man glaubt ja als naiver Entwickler zunächst mal das, was in der Doku geschrieben steht...

Ein "Glück" - und deshalb formuliere ich ja diesen Beitrag auch - haben schlaue Leute eine Alternative gefunden. Diese wurde auch schon hier in den "Delphi-News aus aller Welt" verlinkt, allerdings ist dort der Link defekt.
(https://www.delphipraxis.net/194454-...B7-github.html)
Daher habe ich hier mal den Link nochmal heraus gesucht: https://gist.github.com/lynatan/886e...dd89ed42ab2214

Jetzt sieht es aber so aus, dass diese Alternative nicht so ganz klappt, zumindest nicht für den Equal-Operator. Hat beim Thema "operator overloading" bei Klassen jemand Erfahrung, die mir/uns da weiterhelfen kann?

Codehunter 23. Jan 2020 13:21

AW: Operator Overloading for CLASSES (not records!)
 
Ich habe mich vor einiger Zeit mit einem verwandten Thema beschäftigt. Deshalb finde ich das hier grad sehr interessant. Aber für Unwissende: Was bitte ist denn ein Non-ARC-Compiler?

einbeliebigername 23. Jan 2020 13:41

AW: Operator Overloading for CLASSES (not records!)
 
Hallo,

Zitat:

Zitat von Codehunter (Beitrag 1455843)
Was bitte ist denn ein Non-ARC-Compiler?

ARC= Automatic Reference Counting -> Ein Compiler ohne automatischer Referenzzählung. Der Win32/64 Delphi-Compiler oder die .Net-Compiler. Bei den anderen Delphi-Compilern will Embarcadero ja wieder weg vom ARC. Ich hätte gern ein Mix aus ARC/Non-ARC.

TheSledgeHammer 23. Jan 2020 13:50

AW: Operator Overloading for CLASSES (not records!)
 
Zitat:

Zitat von Codehunter (Beitrag 1455843)
Ich habe mich vor einiger Zeit mit einem verwandten Thema beschäftigt. Deshalb finde ich das hier grad sehr interessant.

Sehr schöner Artikel! Aber auch hier: nur für Records.

Ich hab auch noch irgendwo beim Herumstöbern eine Erklärung gefunden, warum bisher kein operator overloading für Klassen implementiert wurde; hatte irgendwas mit dem Garbage Collector (GC) zu tun. Erklärt wurde das so, dass für jedes Mal, wo ein Operator ausgeführt wird, eine weitere Instanz der Klasse erzeugt werden müsste. Und die wird nur intern erzeugt, aber nicht freigegben und da es mit dem GC in Delphi ja nun etwas schwierig ist, würde diese Instanz als MemLeak weiter sein einsames Dasein fristen. So ganz steig ich da auch nicht durch.

Aber das kann ich irgendwie nicht so recht glauben, dass man das mittlerweile nicht irgendwie gebacken bekommt. Ich sag's mal so: andere Programmiersprachen können's doch auch!? Und offenbar hat man das für iOS im Jahr 2013 schon umgesetzt, dann sollte man doch bis ins Jahr 2019 auch irgendwie für nicht-iOS-Systeme eine Lösung parat haben! Fehlender GC hin oder her...

Und besonders lustig wird's dann, wenn in der Doku geschrieben steht, dass es gehen sollte.

Uwe Raabe 23. Jan 2020 14:20

AW: Operator Overloading for CLASSES (not records!)
 
Zitat:

Zitat von TheSledgeHammer (Beitrag 1455845)
Und besonders lustig wird's dann, wenn in der Doku geschrieben steht, dass es gehen sollte.

Weil es für die ARC-Compiler ja geht.

himitsu 23. Jan 2020 14:29

AW: Operator Overloading for CLASSES (not records!)
 
Zitat:

Zitat von TheSledgeHammer (Beitrag 1455845)
hatte irgendwas mit dem Garbage Collector (GC) zu tun

ARC = einfache billigversion eines komplexen Garbage Collectors

Mit ARC werden Objekte (TObject usw.) wie Interfaces behandelt, also automatisch freigegeben, wenn alle Variablen weg sind. (dafür wird Free einfach so still und heimlich ignoriert)

Die ClassOperators benötigen aber eine automatische Speicherverwaltung, da der Entwickler (Du) das hier nicht selbst macht, bzw. oft garnicht machen kann. (Free aufrufen, wenn nicht mehr benötigt)


Zitat:

Zitat von einbeliebigername (Beitrag 1455844)
Ich hätte gern ein Mix aus ARC/Non-ARC.

Ich hätte auch gern [WeakRef] im Non-ARC-Compiler für interface-Variablen.
Und dass der Compiler unbekannte Attribute nicht einfach so still und heimlich ignoriert. (da wenigstens eine Warnung anzeigt)

Für Records wäre auch ein ClassOperator für New, Copy und Dispose praktisch, damit man dort z.B. auch Pointer und Objekte selbst behandeln kann, die im Record stecken.
Hatte da vor vielen Jahren mal einen QC geschrieben, sogar mit Lösung was wo wie nötig wäre (wenige Codezeilen zu ändern), aber .... ich warte immernoch.



Insgesamt macht ARC und NonARC hier echt Spaß, wenn man versucht einen objektorientierten Code zu schreiben, der auf allen Platformen funktioniert. Da kann man sich oft nur die Haare raufen und aufgeben. (außer man stellt alles komplett auf Interfaces um)

Codehunter 23. Jan 2020 14:36

AW: Operator Overloading for CLASSES (not records!)
 
Zitat:

Zitat von TheSledgeHammer (Beitrag 1455845)
Sehr schöner Artikel! Aber auch hier: nur für Records.

Genau genommen sind Records auch Klassen.

Zitat:

Zitat von TheSledgeHammer (Beitrag 1455845)
Ich hab auch noch irgendwo beim Herumstöbern eine Erklärung gefunden, warum bisher kein operator overloading für Klassen implementiert wurde; hatte irgendwas mit dem Garbage Collector (GC) zu tun. Erklärt wurde das so, dass für jedes Mal, wo ein Operator ausgeführt wird, eine weitere Instanz der Klasse erzeugt werden müsste.

Das glaube ich schon. Wenn man genau hinschaut, mache ich das in meinem Tutorial sogar absichtlich. Für einfache Klassen müsste es trotzdem gehen. Ich sehe noch nicht mal das Freigeben als das große Problem an. Eher schon das Instantiieren der Klassen. Die meisten Klassen haben ja parametrisierte oder überladene Konstruktoren. Wie sollte der Compiler da wissen, welcher der richtige ist?

himitsu 23. Jan 2020 14:44

AW: Operator Overloading for CLASSES (not records!)
 
Nee, das Erstellen machst du ja, in den Operatoren, und gibst es als Result zurück.
Drum ist dem Compiler das vollkommen egal.

Zitat:

Zitat von Codehunter (Beitrag 1455853)
Genau genommen sind Records auch Klassen.

In Delphi ist es andersrum.
Klassen sind intern ein Record mit einem Pointer davor. (und der Pointer zeigt in die Mitte des Records, statt auf dessen Anfang)

In Sowas wie Java, .NET und Dergleichen, da stimmt deine Aussage schon, wobei dort oft eher alles Objekte sind, soger ein schnöder Integer (drum kann der auch NULL bzw. EMPTY werden).

Stevie 23. Jan 2020 15:20

AW: Operator Overloading for CLASSES (not records!)
 
Ich bin mir ziemlich sicher, dass der equals operator für Klassen auch auf ARC keine Beachtung findet, wenn left und right vom Typen sind, dem man diesen Operator verpasst.
Denn damit würde man den schon funktionierenden = Operator für TObject überschreiben können.

Genauso kann man auch mit dem "&&op_*" Hack in einem helper einem Integer nicht seine = oder <, > Operatoren umschreiben.

Es gibt übrigens 2 Arten von Operatoren: die, die neue "Instanzen" zurückgeben, wie z.B. Addition und solche die nur Boolean o.ä. zurückliefern wie Vergleiche - letztere wären auch ohne ARC komplett problemlos möglich.

Zitat:

Zitat von himitsu (Beitrag 1455851)
Ich hätte auch gern [WeakRef] im Non-ARC-Compiler für interface-Variablen.

Gibt's seit XE8 oder so (es heißt übrigens [Weak])

Zitat:

Zitat von himitsu (Beitrag 1455851)
Für Records wäre auch ein ClassOperator für New, Copy und Dispose praktisch, damit man dort z.B. auch Pointer und Objekte selbst behandeln kann, die im Record stecken.

Wird früher oder später kommen - fast wär's mit 10.3 so weit gewesen - aber weint bitte nicht, wenn ihr seht, wie inperformant das implementiert ist.

TheSledgeHammer 23. Jan 2020 15:24

AW: Operator Overloading for CLASSES (not records!)
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1455849)
Zitat:

Zitat von TheSledgeHammer (Beitrag 1455845)
Und besonders lustig wird's dann, wenn in der Doku geschrieben steht, dass es gehen sollte.

Weil es für die ARC-Compiler ja geht.

Das steht da aber nicht, dass das nur für ARCs gilt...

TheSledgeHammer 23. Jan 2020 15:31

AW: Operator Overloading for CLASSES (not records!)
 
Wenn ich mal zusammenfassen darf: die Möglichkeit Operatoren zu überladen, ist wohl nur auf reinen ARC-Systemen möglich, sehe ich das jetzt richtig? Für nonArc-Systeme, also solche, bei denen man einen richtigen GC bräuchte oder aber selbst alle Objekte wieder frei gibt, ist das nicht realisierbar?

TheSledgeHammer 23. Jan 2020 15:34

AW: Operator Overloading for CLASSES (not records!)
 
Zitat:

Zitat von himitsu (Beitrag 1455855)
Zitat:

Zitat von Codehunter (Beitrag 1455853)
Genau genommen sind Records auch Klassen.

In Delphi ist es andersrum.
Klassen sind intern ein Record mit einem Pointer davor. (und der Pointer zeigt in die Mitte des Records, statt auf dessen Anfang)

Also wenn DAS stimmt, dann frag ich mich erstrecht, warum das operator overloading bei Records geht und bei Klassen nicht. Wenn eine Klasse nachher nichts anderes sein soll als ein Rekord... :gruebel:

Stevie 23. Jan 2020 15:38

AW: Operator Overloading for CLASSES (not records!)
 
Klassen sind keine Records, und Records sind keine Klassen. Nur weil eine Klasse Felder wie ein Record hat und somit ein Teil ihres Speicherlayouts dem eines Records gleicht, macht es das nicht zum Record oder könnte gar dessen Funktionalitäten übernehmen - auch wenn intern für einige Dinge vom Compiler generierte record type Info genutzt wird (um zum Beispiel Felder für managed types korrekt zu finalisieren).

Klassen sind Referenztypen (Zeiger auf idR heapallokierten Speicher) und Records sind Wertetypen. Ja, man kann Zeiger auf Records haben und sie auch selbst aufm Heap allokieren, aber dann hantiert man nunmal mit Zeigern, also einem Referenztyp auf einen Wertetypen.

Records und die Operatoren, welche einen Record zurück geben arbeiten idR mit CopyRecord und der Standardmechanismus für Methoden, die einen Record zurückliefern, finden statt - Keine Heapallokation. Ein Operator, der Objekte zurückgeben würde, müsste eine Heapallokation durchführen. Generell noch kein Problem, aber wenn man zum Beispiel den Code
Delphi-Quellcode:
x := a + b + c;
hat, wird dort mind ein Temp Wert erzeugt (entweder a+b oder b+c) und erst das ergebnis dieses Temp Wertes mit dem dritten Wert landet in x, bei einer Heapallokation -> Speicherleck.

himitsu 23. Jan 2020 15:45

AW: Operator Overloading for CLASSES (not records!)
 
Zitat:

Zitat von Stevie (Beitrag 1455861)
Gibt's seit XE8 oder so (es heißt übrigens [Weak])

Jo, gemerkt, aber im Win32 wird die Aangabe einfach vom Compiler ignoriert. (gut, ich glaub im 10.1 zuletzt ausprobiert)

Codehunter 24. Jan 2020 06:19

AW: Operator Overloading for CLASSES (not records!)
 
Zitat:

Zitat von himitsu (Beitrag 1455855)
Zitat:

Zitat von Codehunter (Beitrag 1455853)
Genau genommen sind Records auch Klassen.

In Delphi ist es andersrum.
Klassen sind intern ein Record mit einem Pointer davor. (und der Pointer zeigt in die Mitte des Records, statt auf dessen Anfang)

Um mal meinen Vater zu zitieren: "Alles ein Gemehr" :lol:

Was mich an der Sache hier viel mehr interessiert hat waren überladene Operatoren in Record Helpers. Das wäre wirklich eine nützliche Sache. Denn damit könnte man das Standardverhalten für einfache Typen lokal übersteuern. Beispiel:
Delphi-Quellcode:
var
  S: string;
begin
  S := 'foo';
  if S in ['foo', 'bar'] then begin
    {...}
  end;
end;
das wäre doch viel übersichtlicher als komplexe if-or-or-or-then-Konstrukte. Noch besser wäre natürlich, wenn case auch mit Strings umgehen könnte:
Delphi-Quellcode:
var
  S: string;
begin
  S := 'foo';
  case S of
    'foo': {...}
    'bar': {...}
  end;
end;
Für case-Anweisungen fehlt irgendwie ein überladbarer Operator. Equality spielt da zwar mit rein, aber case an sich ist nicht flexibel genug. Da ist switch-case in anderen Sprachen (z.B. Javascript, PHP) deutlich komfortabler.

freimatz 24. Jan 2020 07:36

AW: Operator Overloading for CLASSES (not records!)
 
Ich bin froh, dass das nicht geht. Das verhindert damit oft unsauberen Code. (Wegen SoC https://en.wikipedia.org/wiki/Separation_of_concerns)

Codehunter 24. Jan 2020 08:11

AW: Operator Overloading for CLASSES (not records!)
 
Zitat:

Zitat von freimatz (Beitrag 1455914)
Ich bin froh, dass das nicht geht. Das verhindert damit oft unsauberen Code. (Wegen SoC https://en.wikipedia.org/wiki/Separation_of_concerns)

Nach deiner Logik wäre ja die "Quelltextsauberkeit" umgekehrt äquivalent zur Anzahl verfügbarer Sprachfeatures :lol:

Stevie 24. Jan 2020 09:45

AW: Operator Overloading for CLASSES (not records!)
 
Zitat:

Zitat von Codehunter (Beitrag 1455906)
Was mich an der Sache hier viel mehr interessiert hat waren überladene Operatoren in Record Helpers. Das wäre wirklich eine nützliche Sache. Denn damit könnte man das Standardverhalten für einfache Typen lokal übersteuern.

Das geht wie gesagt nur bei Typen, denen man sowieso Operatoren verpassen kann, wie Records oder Klassen (bei Klassen mit der schon besprochenen Einschränkung). Nicht aber bei string, Integer und Co. Ich hab z.B. weitere Operatoren für System.Rtti.TValue geschrieben, die Anwendung finden, wenn ich die entsprechende Unit einbinde.

Zitat:

Zitat von Codehunter (Beitrag 1455906)
Für case-Anweisungen fehlt irgendwie ein überladbarer Operator. Equality spielt da zwar mit rein, aber case an sich ist nicht flexibel genug. Da ist switch-case in anderen Sprachen (z.B. Javascript, PHP) deutlich komfortabler.

Die unterstützung von nicht ordinalen Typen in einem switch/case hat aber in den mir bekannten Sprachen nichts mit Operatoren auf den unterstützten Typen zu tun sondern sind in der Sprachsyntax bzw dem Compiler verankert, der dann weiß, wie er damit umzugehen hat. Bei Ordinaltypen kann eine Jumptable auf den passenden Wert gebaut werden, so macht Delphi das, aber bei anderen Typen müssen andere Strategien her, die in aller Regel der Compiler entscheidet (wie z.B. in C# bei string). Kommen dann noch so interessante Dinge wie Pattern matching hinzu, wirds komplexer.

Bzgl Verbesserung des case of Statements: einfach mal nen Vote für RSP-16478 abgeben und die Daumen drücken.

freimatz 24. Jan 2020 11:07

AW: Operator Overloading for CLASSES (not records!)
 
Zitat:

Zitat von Codehunter (Beitrag 1455920)
Zitat:

Zitat von freimatz (Beitrag 1455914)
Ich bin froh, dass das nicht geht. Das verhindert damit oft unsauberen Code. (Wegen SoC https://en.wikipedia.org/wiki/Separation_of_concerns)

Nach deiner Logik wäre ja die "Quelltextsauberkeit" umgekehrt äquivalent zur Anzahl verfügbarer Sprachfeatures :lol:

Nein. Nach meiner Logik steht "das" steht für ein Sprachfeature und genau das erwähnte.

himitsu 24. Jan 2020 11:33

AW: Operator Overloading for CLASSES (not records!)
 
Nativ fehlt halt so Einiges in Delphi, was man schonmal gebraucht hätte. (Einiges gibt es zum Glück von Fremdanbietern, was aber auch schnell den Gesamtpreis von Delphi etwas in die Höhe treibt)

DefaultPropery für Strings (das mit dem Default-Attritut ist schon blöd, denn Eines steht davor und das Andere dahinter und wenn ich jetzt frage wer von euch überhaupt weiß dass es sowas gibt, dann hebt bestimmt kaum jemand die Hand), Attribute hinter dem was man beschreiben will (statt davor/drüber), kleine Makros, assoziative Arrays, ein besseres CASE, ...

Nicht schön, aber was soll's.
Delphi-Quellcode:
case IndexStr(S, ['A', 'B', 'C']) of
  0{A}: ...;
  1{B}: ...;
  2{C}: ...;
end;

type TX = (A, B, C);
//case TX(IndexStr(S, ['A', 'B', 'C'])) of
case TX(GetEnumValue(TypeInfo(TX), S)) of
  A: ...;
  B: ...;
  C: ...;
end;

Codehunter 24. Jan 2020 12:10

AW: Operator Overloading for CLASSES (not records!)
 
Zitat:

Zitat von himitsu (Beitrag 1455940)
assoziative Arrays

Also diesbzgl. bin ich mit TDictionary doch recht zufrieden.

Uwe Raabe 24. Jan 2020 12:29

AW: Operator Overloading for CLASSES (not records!)
 
Zitat:

Zitat von himitsu (Beitrag 1455940)
wenn ich jetzt frage wer von euch überhaupt weiß dass es sowas gibt, dann hebt bestimmt kaum jemand die Hand

:hi:

Rollo62 24. Jan 2020 12:58

AW: Operator Overloading for CLASSES (not records!)
 
:hi:

und danke für die Erinnerung das es sowas gibt ...


Alle Zeitangaben in WEZ +1. Es ist jetzt 20:21 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