AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren

Fluent Design und Records

Ein Thema von hschmid67 · begonnen am 23. Aug 2019 · letzter Beitrag vom 26. Aug 2019
Antwort Antwort
Seite 2 von 3     12 3   
hschmid67

Registriert seit: 2. Jul 2012
Ort: Weilheim i. Obb.
49 Beiträge
 
Delphi 10.2 Tokyo Enterprise
 
#11

AW: Fluent Design und Records

  Alt 24. Aug 2019, 15:59
Super!

Vielen, vielen Dank. Jetzt hab ich es verstanden.

Hier noch mein vollständiges Beispiel, das jetzt funktioniert (natürlich nur im Anfangsstadium):

Delphi-Quellcode:
unit hs.str2;

interface

type
  PhsStr2 = ^ThsStr2;
  ThsStr2 = record
    FStr: string;
    function Init(const mString: string): PhsStr2;
    class operator implicit(const aValue: ThsStr2): string;
    class operator implicit(const aValue: string): ThsStr2;
  end;

implementation

uses
  System.SysUtils;

{ ThsStr2 }

class operator ThsStr2.implicit(const aValue: ThsStr2): string;
begin
  Result := aValue.FStr;
end;

class operator ThsStr2.implicit(const aValue: string): ThsStr2;
begin
  Result.FStr := aValue;
end;

function ThsStr2.Init(const mString: string): PhsStr2;
begin
  FStr := mString;
  Result := @Self;
end;

end.
Und der Aufruf läuft jetzt erfolgreich:

Delphi-Quellcode:
procedure Test;
var
  lStr: ThsStr2;
  lDummy: string;
begin
  lDummy := lStr.Init('dummy');
end;
Genau das, was ich gesucht hatte - und in meinen Augen dann richig schöner Code, denn man kann das Ganze ja beliebig erweitern, etwa


lDummy := lStr.Init('dummy').CopyFromChar('-').CopyToChar('#');

Das möchte ich nämlich gerade machen: All meine String-Funktionen in einen Aufruf, in ein Objekt/einen Record zu packen, ohne globale Proceduren oder besonderes Speichermanagement (zumindest nicht sichtbar).

Jetzt wäre es nur noch schön, wenn man es so aufrufen könnte:


lDummy := lStr('dummy').CopyFromChar('-').CopyToChar('#');

also ohne das Init, aber das geht wohl nicht...

Vielen Dank und viele Grüße
Harald
Harald
  Mit Zitat antworten Zitat
Benutzerbild von uligerhardt
uligerhardt

Registriert seit: 19. Aug 2004
Ort: Hof/Saale
1.682 Beiträge
 
Delphi 2007 Professional
 
#12

AW: Fluent Design und Records

  Alt 24. Aug 2019, 16:06
Schaut gut aus. Bzgl. des letzten Satzes: Du könntest dem Record einen Konstruktor oder eine Factory-Funktion verpassen. Dann solltest du so etwas schreiben können:
Delphi-Quellcode:
lDummy := ThsStr2.Create('dummy').CopyFromChar('-').CopyToChar('#'); // Mit Record-Konstruktor
// oder
lDummy := MakehsStr2('dummy').CopyFromChar('-').CopyToChar('#'); // Mit Factory-Funktion
Uli Gerhardt
  Mit Zitat antworten Zitat
hschmid67

Registriert seit: 2. Jul 2012
Ort: Weilheim i. Obb.
49 Beiträge
 
Delphi 10.2 Tokyo Enterprise
 
#13

AW: Fluent Design und Records

  Alt 24. Aug 2019, 16:17
Hallo, auch hierfür nochmal danke.
Klar, das, was ich mit Objekten und Interfaces machen kann, also eine Factory-Methode, das kann ich auch mit einem Record machen - hätte ich auch selbst drauf kommen können.

Verblüffend, was man mit Delphi doch auch alles machen kann, wenn man nur weiß, wie!

Ich werde es jetzt also so machen (doch eine globale Funktion, aber die eine passt dann schon):

function hsStr(const mValue: string = ''): ThsStr2;

und dann sieht der Aufruf tatsächlich so aus - und ich kann es mit oder ohne Initialisierungsstring aufrufen:

lDummy := hsStr('dummy').CopyFromChar('-').CopyToChar('#');

Vielen Dank und herzliche Grüße

Harald
Harald
  Mit Zitat antworten Zitat
Benutzerbild von uligerhardt
uligerhardt

Registriert seit: 19. Aug 2004
Ort: Hof/Saale
1.682 Beiträge
 
Delphi 2007 Professional
 
#14

AW: Fluent Design und Records

  Alt 24. Aug 2019, 16:19
Uli Gerhardt
  Mit Zitat antworten Zitat
hschmid67

Registriert seit: 2. Jul 2012
Ort: Weilheim i. Obb.
49 Beiträge
 
Delphi 10.2 Tokyo Enterprise
 
#15

AW: Fluent Design und Records

  Alt 24. Aug 2019, 17:06
noch zwei Ergänzungen:

Ich war vorhin wohl doch zu voreilig: Es funktioniert nicht ganz ohne Dereferenzierung, zumindest nicht die implizite Zuweisung. Will ich das Ergebnis nach einem Implicit-Operator direkt einem String zuweisen, dann geht es nur so:

Delphi-Quellcode:
lDummy := hsStr('dummy').CopyFromChar('-').CopyToChar('#')^; // funktioniert mit dem abschließenden ^
lDummy := hsStr('dummy').CopyFromChar('-').CopyToChar('#'); // funktioniert NICHT ohne das abschließende ^
hmmm

Allerdings habe ich inzwischen auch die Geschwindigkeit der beiden Konstrukte getestet, also einmal mit einem Objekt/Interface und einmal mit einem Record und die Record-Variante ist bei sonst völlig identischem Code fast doppelt so schnell.

Viele Grüße
Harald
Harald
  Mit Zitat antworten Zitat
Benutzerbild von uligerhardt
uligerhardt

Registriert seit: 19. Aug 2004
Ort: Hof/Saale
1.682 Beiträge
 
Delphi 2007 Professional
 
#16

AW: Fluent Design und Records

  Alt 24. Aug 2019, 17:17
Ich war vorhin wohl doch zu voreilig: Es funktioniert nicht ganz ohne Dereferenzierung, zumindest nicht die implizite Zuweisung. Will ich das Ergebnis nach einem Implicit-Operator direkt einem String zuweisen, dann geht es nur so:

Delphi-Quellcode:
lDummy := hsStr('dummy').CopyFromChar('-').CopyToChar('#')^; // funktioniert mit dem abschließenden ^
lDummy := hsStr('dummy').CopyFromChar('-').CopyToChar('#'); // funktioniert NICHT ohne das abschließende ^
hmmm
Dass man den ^ überhaupt manchmal weglassen darf, ist eh schon eine Krücke. Wo es dann zu uneindeutig wird, ist es halt ganz verboten.

Allerdings habe ich inzwischen auch die Geschwindigkeit der beiden Konstrukte getestet, also einmal mit einem Objekt/Interface und einmal mit einem Record und die Record-Variante ist bei sonst völlig identischem Code fast doppelt so schnell.
Jo. Ich vermute mal, weil keine überflüssigen Speichereservierungen vorgenommen werden. Bei einem Interface kämen dann auch noch die virtuelle Methodenauflösung hinzu, wenn ich mich nicht täusche.
Uli Gerhardt
  Mit Zitat antworten Zitat
peterbelow

Registriert seit: 12. Jan 2019
Ort: Hessen
372 Beiträge
 
Delphi 10.3 Rio
 
#17

AW: Fluent Design und Records

  Alt 25. Aug 2019, 17:09
Liebe Delphi-Gemeinde,

ich mag im Design meiner Objekte das Pattern des Fluent Design sehr gerne und gestalte meine Methoden deshalb gerne damit. Ich meine damit also etwa ein solches Gebilde:

Result := CreateSomeInterface.DoSomething('withParameter').DoSomethingOther.ConvertEverythingToString;

Das ist an manchen Stellen sehr praktisch und macht den Code in meinen Augen etwas schöner, vor allem, wenn man mit Interfaces statt mit Objekten arbeitet.
Naja, Schönheit liegt im Auge des Betrachters.

Stell Dir mal vor, Du mußt sowas debuggen, dann ist es nicht mehr so schön...
Peter Below
  Mit Zitat antworten Zitat
dummzeuch

Registriert seit: 11. Aug 2012
Ort: Essen
767 Beiträge
 
Delphi 2007 Professional
 
#18

AW: Fluent Design und Records

  Alt 25. Aug 2019, 18:54
Result := CreateSomeInterface.DoSomething('withParameter').DoSomethingOther.ConvertEverythingToString; Das ist an manchen Stellen sehr praktisch und macht den Code in meinen Augen etwas schöner, vor allem, wenn man mit Interfaces statt mit Objekten arbeitet.
Naja, Schönheit liegt im Auge des Betrachters.

Stell Dir mal vor, Du mußt sowas debuggen, dann ist es nicht mehr so schön...
Einfach vernuenftig formatieren ...
Delphi-Quellcode:
Result := CreateSomeInterface
  .DoSomething('withParameter')
  .DoSomethingOther
  .ConvertEverythingTo
... und schon ist das kein Problem mehr. Und lesbarer ist es (IMHO) auch.
(Ob der OP das dann allerdings immernoch "schön" findet?).
Thomas Mueller
  Mit Zitat antworten Zitat
HolgerX

Registriert seit: 10. Apr 2006
Ort: Leverkusen
879 Beiträge
 
Delphi 6 Professional
 
#19

AW: Fluent Design und Records

  Alt 25. Aug 2019, 20:03
Hmm..

Result := CreateSomeInterface.DoSomething('withParameter').DoSomethingOther.ConvertEverythingToString; Das ist an manchen Stellen sehr praktisch und macht den Code in meinen Augen etwas schöner, vor allem, wenn man mit Interfaces statt mit Objekten arbeitet.
Naja, Schönheit liegt im Auge des Betrachters.

Stell Dir mal vor, Du mußt sowas debuggen, dann ist es nicht mehr so schön...
Einfach vernuenftig formatieren ...
Delphi-Quellcode:
Result := CreateSomeInterface
  .DoSomething('withParameter')
  .DoSomethingOther
  .ConvertEverythingTo
... und schon ist das kein Problem mehr. Und lesbarer ist es (IMHO) auch.
(Ob der OP das dann allerdings immernoch "schön" findet?).
So etwas ist immer gefährlich....

Was ist, wenn es beim '.DoSomething('withParameter')' kracht oder etwas geliefert wird, was in '.DoSomethingOther' zur Exception führt?

Wenn ich das in einer Zeile schreibe, wie kann ich dann im Debugger erkennen, wo es geknallt hat?

(Nur so meine Meinung )
(Ja ich Verwende Delphi 6 Pro und will NICHT wechseln!)
  Mit Zitat antworten Zitat
Benutzerbild von stahli
stahli

Registriert seit: 26. Nov 2003
Ort: Halle/Saale
4.089 Beiträge
 
Delphi 10.4 Sydney
 
#20

AW: Fluent Design und Records

  Alt 25. Aug 2019, 20:54
Mal eine Frage, was Ihr grundsätzlich von einer solchen Darstellung haltet (mal völlig unabhängig von Delphi und anderen realen Sprachen).
Es geht mir nur um die reine Lesbarkeit und Wünsche diesbezüglich.

Das wäre ja Delphi ohne irgendwelche Klimmzüge:
Code:
  Result := CreateSomeInterface;
  Result.DoSomething('withParameter');
  Result.DoSomethingOther;
  Result.ConvertEverythingTo;
Warum will man das anders darstellen?
Um nicht mehrfach "Result" zu schreiben?

---

Ok, wenn man jetzt (rein hypothetisch!) dem IDE-Editor folgendes beibringen könnte:
"Wenn in den folgenden Zeilen das gleiche erste Wort steht und dann ein Punkt folgt, dann lasse das erste Wort in der Darstellung weg und rücke alles ab dem Punkt ein!"
dann würde das so aussehen:
Code:
  Result := CreateSomeInterface;
         .DoSomething('withParameter');
         .DoSomethingOther;
         .ConvertEverythingTo;
---

Da aber dann der Editor abweichenden Code darstellen müsste als der, den der Compiler erhält, müsste man das etwas anders aufziehen:
Man müsste dem Compiler sagen: "Wenn eine Anweisung mit einem Punkt beginnt, dann denke Dir mal, dass davor die Variable steht, der in der vorherigen Anweisung etwas zugewiesen wurde."
Die IDE könnte einfach die Anweisung ab dem Punkt einrücken.
Code:
  Result := CreateSomeInterface;
         .DoSomething('withParameter');
         .DoSomethingOther;
         .ConvertEverythingTo;
Das sähe also aus wie bei der vorherigen Überlegung, aber der Code wäre identisch zur Darstellung.
Das hätte den Haken, dass man letztlich nur in Verbindung mit der Einrückung klar erkennt, was dort gemeint ist.

---

Gut, schauen wir uns mal with an:
Code:
  Result := CreateSomeInterface;
  with Result do
  begin
    DoSomething('withParameter');
    DoSomethingOther;
    ConvertEverythingTo;
  end;
Eigentlich ja gar nicht sooo schlecht, allerdings bekannter Maßen mit einem recht hohen Verwechslungsrisiko und die Umschließung mit begin..end ist auch etwas nervig.

---

Mich würde das zu folgenden gewünschten Sprachfeature führen: "use"
Code:
  use Result := CreateSomeInterface;
             .DoSomething('withParameter');
             .DoSomethingOther;
             .ConvertEverythingTo;
             Report(.Text);
  Report('use gilt nicht mehr');
"use" würde with entsprechen und so lange gelten, wie folgende Anweisungen Bezeichner benutzen, die mit einem Punkt anfangen.
Dann wäre auch noch die Report-Anweisung möglich.
Sobald eine Anweisung nicht nicht mehr auf Result bezieht (also kein Bezeichner mit einem . anfängt) ist der use-Bezug hinfällig und ungültig.

---

Wenn, dann würde ich mir so etwas wünschen.
Das wäre nachvollziehbar und einfach ein besseres "with".

Alle Klassen umzubauen um Anweisungen mit einem Punkt starten zu können wäre mir zu aufwendig und bezüglich der Debugbarkeit halte ich das auch nicht für hilfreich.
Außerdem sollten Funktionen für die Logik da sein und nicht für das Code-Styling.

Wenn ich eine Methode TPerson.SetIsNice(True) habe, dann sollte die möglicherweise für die Validierung ein Accept zurück geben und nicht die Klasse.

Also ich brauche ein fluent interface eher nicht und würde eher ein anderes Sprachfeature wünschen, um Codekürzungen zu erreichen. Da wäre ich dann dabei.
Stahli
http://www.StahliSoft.de
---
"Jetzt muss ich seh´n, dass ich kein Denkfehler mach...!?" Dittsche (2004)

Geändert von stahli (25. Aug 2019 um 20:59 Uhr)
  Mit Zitat antworten Zitat
Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

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 10:42 Uhr.
Powered by vBulletin® Copyright ©2000 - 2020, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2020 by Daniel R. Wolf