AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Fluent Design und Records

Ein Thema von hschmid67 · begonnen am 23. Aug 2019 · letzter Beitrag vom 26. Aug 2019
Antwort Antwort
Benutzerbild von dummzeuch
dummzeuch

Registriert seit: 11. Aug 2012
Ort: Essen
1.686 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#1

AW: Fluent Design und Records

  Alt 25. Aug 2019, 17: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
983 Beiträge
 
Delphi 6 Professional
 
#2

AW: Fluent Design und Records

  Alt 25. Aug 2019, 19: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.352 Beiträge
 
Delphi 11 Alexandria
 
#3

AW: Fluent Design und Records

  Alt 25. Aug 2019, 19: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 19:59 Uhr)
  Mit Zitat antworten Zitat
Schokohase
(Gast)

n/a Beiträge
 
#4

AW: Fluent Design und Records

  Alt 25. Aug 2019, 20:13
@stahli

Das Besondere am Fluent Interface ist kein Ersatz für
Delphi-Quellcode:
Result := CreateSomeInterface;
Result.DoSomething('withParameter');
Result.DoSomethingOther;
Result.ConvertEverythingTo;
sondern das hier
Delphi-Quellcode:
ResultA := CreateSomeInterface; // IFoo
ResultB := ResultA.DoSomething('withParameter'); // IBar
ResultC := ResultB.DoSomethingOther; // IOther
ResultD := ResultC.ConvertEverythingTo; // string
Natürlich ist es möglich das alle ResultX vom gleichen Typ sind und dann auch auf die gleiche Instanz verweisen, aber sie müssen es eben nicht.

Und die eingebaute Code-Formatierung formatiert das so (wenn man einen Zeilenkommentar anhängt)
Delphi-Quellcode:
Result := CreateSomeInterface() // IFoo
  .DoSomething('withParameter') // IBar
  .SoSomethingOther() // IOther
  .ConvertEverythingTo(); // string
  Mit Zitat antworten Zitat
Benutzerbild von Mavarik
Mavarik

Registriert seit: 9. Feb 2006
Ort: Stolberg (Rhld)
4.154 Beiträge
 
Delphi 10.3 Rio
 
#5

AW: Fluent Design und Records

  Alt 26. Aug 2019, 12:44
Es gibt mehrere Gründe den Sourcecode "so" zu schreiben.

Beispiel SQL:

Delphi-Quellcode:
  TCRUDSearch.&For(fPerson).Where('NAME').LIKE(LastName.Trim)
  {}         .begin_Optional(FirstName.Trim <> '')
  {}            ._AND.Where('VORNAME').LIKE(FirstName.Trim)
  {}         .end_Optional.OrderBy('NAME')
  {}         .OrderBy('VORNAME ASC')
  {}         .Limit(100)
  {}         .Start(SearchResult);
Wie üblich die {} , damit der Formatter das nicht zerstört.
Nicht nur das ich mit diesem Interface keine Tippfehler mehr im "SQL-Source-Text" habe, ich kann auch mit dem "begin Optional(Statement)" je nach Kondition des Statements einen anderen SQL Code erzeugen.

oder halt sowas:

Delphi-Quellcode:
    TFMXFluentCreator<TDayLBL>.CreateDefault(FDayLBL[i-1],LConfig)
    {}                        .FontSize(FFontSize)
    {}                        .Skip(LConfig.Trim <> '',2).FontColor(LDisplayDay.Color).FontBold(LDisplayDay.Bold)
    {}                        .Text(FDays[i-1])
    {}                        {$IFNDEF NOHints}
    {}                          .Skip((LDisplayDay.Hint = '')).Hint(LDisplayDay.Hint)
    {}                        {$ENDIF}
    {}                        ;
Ich empfehle hierzu mein CodeRage Video. Auch wenn hier leider noch von Fluid und nicht Fluent gesprochen wird. // Danke Stefan hab es in ALLEN Sourcen renamed...

Hier gibe es wie bei meine SQL Creator (begin/end) ein Skip Command mit dem man 1-N der nächsten Fluent-Aufrufe überspringen kann je nach Kondition.
Per LConfig kann ich Aufruf die ich beliebig vordefinieren kann, zusätzlich abrufen.

Wenn man ListBoxItems im Source erzeugen möchte ist das eine fürchterliche Tipperei, besonders durch die TWhateverbezeichner.Value {$SCOPEDENUMS ON}.

Da sieht es doch schon deutlich einfacher aus, wenn man

Delphi-Quellcode:
TFMXFluentCreator<TListBoxItem>.RegisterDefault(Procedure (LBI : TFMXFluentCreator<TListBoxItem>)
  begin
    LBI.Style('listboxitembottomdetail')
       .Height(49)
       .Parent(ListBox1)
       .ItemMore.OnClick(Procedure (Sender : TObject)
          begin
            AViewModel.Edit((Sender as TListBoxItem).TagString);
            Translate.SetFocus;
          end,false);
  end);
schreiben kann..

Grüsse Mavarik

Geändert von Mavarik (26. Aug 2019 um 12:49 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von dummzeuch
dummzeuch

Registriert seit: 11. Aug 2012
Ort: Essen
1.686 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#6

AW: Fluent Design und Records

  Alt 26. Aug 2019, 14:03
Hmm..

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?
In der Regel ja. Deshalb die Formatierung mit einem Aufruf pro Zeile.
Zum Debuggen wäre natürlich eine Variable einfacher:

Delphi-Quellcode:
Result := CreateSomeInterface;
Result := Result.DoSomething('withParameter');
Result := Result.DoSomethingOther;
Result := Result.ConvertEverythingTo;
Aber das versaut das "schöne" dann komplett.

(Vorausgesetzt, es ist durchgehend derselbe Interface-Typ, denn wie Schokohase schon schrieb: Das ist nicht notwendigerweise der Fall. Wenn nicht, muesste man auch noch jede Menge Variablen deklarieren, was noch viel mehr Tipperei ist.)

Ich habe einige wenige solcher Konstruktionen, bei denen diese Kaskade einen Funktionsaufruf mit zig Parametern ersetzt hat. Die Lesbarkeit hat es auf jeden Fall verbessert.
Thomas Mueller

Geändert von dummzeuch (26. Aug 2019 um 14:09 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

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

AW: Fluent Design und Records

  Alt 26. Aug 2019, 14:43
Zum Debuggen wäre natürlich eine Variable einfacher
Macht sich auch besser im Watch-Fenster oder bei Ctrl-F7.

Es ist halt immer ein Kompromiss zwischen "schön" bzw. lesbar und leichter zu debuggen.

Wenn nicht, muesste man auch noch jede Menge Variablen deklarieren, was noch viel mehr Tipperei ist.
Na ja, unter Rio hält sich das ja noch in Grenzen:
Delphi-Quellcode:
begin
  var ResultA: IFoo := CreateSomeInterface; // IFoo
  var ResultB: IBar := ResultA.DoSomething('withParameter'); // IBar
  var ResultC: IOther := ResultB.DoSomethingOther; // IOther
  var ResultD: string := ResultC.ConvertEverythingTo; // string
end;
Ach ja, früher galt with auch als richtig cool, weil man da soviel Tipperei spart.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Benutzerbild von stahli
stahli

Registriert seit: 26. Nov 2003
Ort: Halle/Saale
4.352 Beiträge
 
Delphi 11 Alexandria
 
#8

AW: Fluent Design und Records

  Alt 26. Aug 2019, 15:03
Solche Zwischenschritte in einzelne Variablen zu speichern stört mich gar nicht. Ich finde, das erhöht sogar die Übersichtlichkeit deutlich.

Das mache ich auch schon mal bei etwas komplizierteren Berechnungen (Winkel o.ä.). Da nehme ich gern in Kauf, mal eine Variable anzulegen.

Einzig, eine ständige Wiederholung der gleichen Variable würde ich u.U. gern vermeiden, wenn es dafür eine abgekürzte Darstellung/Schreibweise gäbe (Alternative zum with).
Meine Klassen würde ich dafür aber nicht umbauen.


In Bezug auf "Tipparbeit vermeiden" fallen mir da ganz andere Themen ein, die ich wirklich wichtig fände und wo die IDE wirklich keine Hilfe ist.
Stahli
http://www.StahliSoft.de
---
"Jetzt muss ich seh´n, dass ich kein Denkfehler mach...!?" Dittsche (2004)
  Mit Zitat antworten Zitat
Benutzerbild von Mavarik
Mavarik

Registriert seit: 9. Feb 2006
Ort: Stolberg (Rhld)
4.154 Beiträge
 
Delphi 10.3 Rio
 
#9

AW: Fluent Design und Records

  Alt 26. Aug 2019, 15:39
Naja sagen wir mal so...

Für ein Interface, Klasse oder Record das man so verwendet/erstellt bietet es sich natürlich an, einen Unittest zu schreiben, dann braucht man i.d.R. auch nicht debuggen oder eher selten.

Mavark
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

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

AW: Fluent Design und Records

  Alt 26. Aug 2019, 15:53
bietet es sich natürlich an, einen unittest zu schreiben, dann braucht man i.d.r. Auch nicht debuggen oder eher selten.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Antwort Antwort


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 03:07 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