Gebrauch von With

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
Warf
Beiträge: 1908
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Gebrauch von With

Beitrag von Warf »

Marc hat geschrieben:Hallo Theo

Vielen Dank für die schnelle Hilfe!

Ich hab es jetzt so gemacht :

Code: Alles auswählen

 Form2 := TForm2.CREATE(Application);
 Form2.ShowModal;
 FreeAndNil(Form2);

Das scheint zu funktionieren.


Man braucht nicht mal ne Variable:

Code: Alles auswählen

With TForm2.Create(nil) do // Owner nicht benötigt wenn man selbst freed
try
  ShowModal();
finally
  Free;
end;

Benutzeravatar
theo
Beiträge: 10467
Registriert: Mo 11. Sep 2006, 19:01

Re: Form schliessen und wieder öffnen

Beitrag von theo »

Warf hat geschrieben:Man braucht nicht mal ne Variable:

Den Gebrauch von "with" sollte man nun wirklich nicht noch fördern... :roll:

Warf
Beiträge: 1908
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: Form schliessen und wieder öffnen

Beitrag von Warf »

theo hat geschrieben:
Warf hat geschrieben:Man braucht nicht mal ne Variable:

Den Gebrauch von "with" sollte man nun wirklich nicht noch fördern... :roll:


Naja, kommt drauf an. Wenn man z.B. ein sehr langes prefix hat dann lohnt es sich auf jeden fall:

Code: Alles auswählen

Form2.Image1.Bitmap.Canvas.MoveTo(0,0);
Form2.Image1.Bitmap.Canvas.LineTo(Form2.Image1.Bitmap.Width,Form2.Image1.Bitmap.Height);
// vs
With Form2.Image1.Bitmap do
begin
  Canvas.MoveTo(0,0);
  Canvas.LineTo(Width, Height);
end;


Ich persönlich verwende es auch immer wenn ich ein Objekt für wenige Operationen brauche, z.B. eine Textdatei in einen stream laden:

Code: Alles auswählen

With TStringList.Create do
try
  LoadFromFile(FName);
  SaveToStream(Stream);
finally
  Free;
end;


Weder LoadFromFile noch SaveToStream sind in irgendeiner form mehrdeutig im Kontext einer Formsklasse, daher spricht absolut nichts dagegen.

Man muss sich nur an ein paar Spielregeln halten:
1. Keine geschachtelten With
2. Auf Methoden und Felder des Objektes innerhalb von with immer mit Self zugreifen
3. Mehrdeutige bezeichnet mit unitname.Bezeichner aufrufen (z.B. wenn man eine property Pos hat dann würde man System.Pos für die Funktion verwenden).

Und wenn man nicht in einem Objekt ist spricht sogar absolut nichts gegen with.

Wovon ich nichts halte sind größere With blöcke, mehr als 5-10 Zeilen würde ich auch nicht in einen With block hauen

Benutzeravatar
theo
Beiträge: 10467
Registriert: Mo 11. Sep 2006, 19:01

Re: Form schliessen und wieder öffnen

Beitrag von theo »

Es kann jeder programmieren wie er will, aber empfehlen würde ich es einem Einsteiger nie.
Das erste was ich beim Debuggen von fremdem Code mache, ist alle "with" rausschmeißen. :wink:

Warf
Beiträge: 1908
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: Form schliessen und wieder öffnen

Beitrag von Warf »

theo hat geschrieben:Es kann jeder programmieren wie er will, aber empfehlen würde ich es einem Einsteiger nie.
Das erste was ich beim Debuggen von fremdem Code mache, ist alle "with" rausschmeißen. :wink:


Ist halt ein typischer Fall von "Code der einfacher zu schreiben als zu lesen ist"

pluto
Lazarusforum e. V.
Beiträge: 7178
Registriert: So 19. Nov 2006, 12:06
OS, Lazarus, FPC: Linux Mint 19.3
CPU-Target: AMD
Wohnort: Oldenburg(Oldenburg)

Re: Form schliessen und wieder öffnen

Beitrag von pluto »

Ist halt ein typischer Fall von "Code der einfacher zu schreiben als zu lesen ist"

Ich finde eine Variable zu nutzen, als einfacher und übersichtlicher...
Häuft verwende ich Variablen um Zugriffe(Damit meine ich unter anderem Umwandlungen) zu "Sparen"....
MFG
Michael Springwald

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: Form schliessen und wieder öffnen

Beitrag von wp_xyz »

Warf hat geschrieben:

Code: Alles auswählen

Form2.Image1.Bitmap.Canvas.MoveTo(0,0);
Form2.Image1.Bitmap.Canvas.LineTo(Form2.Image1.Bitmap.Width,Form2.Image1.Bitmap.Height);
// vs
With Form2.Image1.Bitmap do
begin
  Canvas.MoveTo(0,0);
  Canvas.LineTo(Width, Height);
end;


Abweichend vom Thema - aber ich kann das einfach nicht mehr sehen: Ich nehme mal an, dass es hier um eine Methode von TForm2 geht. Dann hast du hier die Todsünde begangen, in der Implementierung der Methode die Instanz-Variable zu verwenden. Als Folge wird dein Code nur funktionieren, wenn die Instanz von TForm2 Form2 heißt und nicht anders. Das ist derselbe Unsinn, wie wenn man gezwungen wäre jeden Integer "i" zu nennen.

Je öfter solcher Unsinn in Foren auftaucht, um so öfter wird er angewendet.

Warf
Beiträge: 1908
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: Form schliessen und wieder öffnen

Beitrag von Warf »

wp_xyz hat geschrieben:
Warf hat geschrieben:

Code: Alles auswählen

Form2.Image1.Bitmap.Canvas.MoveTo(0,0);
Form2.Image1.Bitmap.Canvas.LineTo(Form2.Image1.Bitmap.Width,Form2.Image1.Bitmap.Height);
// vs
With Form2.Image1.Bitmap do
begin
  Canvas.MoveTo(0,0);
  Canvas.LineTo(Width, Height);
end;


Ich nehme mal an, dass es hier um eine Methode von TForm2 geht. Dann hast du hier die Todsünde begangen, in der Implementierung der Methode die Instanz-Variable zu verwenden. Als Folge wird dein Code nur funktionieren, wenn die Instanz von TForm2 Form2 heißt und nicht anders. Das ist derselbe Unsinn, wie wenn man gezwungen wäre jeden Integer "i" zu nennen.

Als nächstes zurück zum Thema: theo hat recht, denn das ist auch ein schönes Beispiel für die Probleme mit with. So wie es da steht, sind Width und Height die entsprechenden Eigenschaften des Bitmap. Aber was ist wenn du eigentlich die Eigenschaften des Formular gemeint hast und vergessen hast, "self" (oder - wieder Todsünde - "Form2") voranzustellen? Du bekommst keine Fehlermeldung, und du wirst, wenn dir dein Kunde nach 6 Monaten Darstellugsprobleme gemeldet hat und du alle Details vergessen hast, mit stundenlanger Fehlersuche bestraft.

Das Beispiel hab ich mir einfach ausgedacht und es stammt nicht aus echtem code. Aber lange Präfixe gibt es auch in vielen anderen situation.

Sehr gut eignet sich With z.B. für Listview ähnliche Datenstrukturen:

Code: Alles auswählen

With ListView1.Items.Add do
begin
  Caption := 'CAP';
  SubItems.Add('S2');
  SubItems.Add('S3');
  Tag = Sender;
end;


Wegen der Mehrdeutigkeit, dafür hab ich mir angewöhnt immer self zu verwenden im with. Ansonsten könnte man genauso argumentieren, warum verwendet man Klassen statt Objects / Advanced Records, bei Klassen können Access violations auftreten wenn die Klasse gefreed wurde oder von Anfang an ein Nullpointer war. Einen Fehler zu finden aufgrund eines vorzeitigen Free's kann deutlich schlimmer werden als ein Falscher bezeichner, denn im Worst case wurde der Speicher noch nicht überschrieben und die Klasse verhält sich wie gewohnt, aber irgendwann nach dem Alloziieren einer neuen Klasse ist plötzlich der gesamte Speicher überschrieben, und das Wohlgemerkt ohne einen einzigen Fehler. Z.B.:

Code: Alles auswählen

program Test;
{$Mode ObjFPC}{$H+}
 
type
  TTestClass = class
  private
    FName: String;
  public
    property Name: String read FName write FName;
  end;
 
var foo, bar: TTestClass;
begin
  foo:= TTestClass.Create;
  foo.free;
  foo.Name := 'abc';
  WriteLn(foo.name);
  bar := TTestClass.Create;
  WriteLn(foo.name);
  bar.Free;
end.

Dieser code sollte bei einem x86-64 system mit FPC memory manager zu erst abc danach den leeren string outputen ohne irgendeine Fehlermeldung. Das ist allerdings dennoch kein Grund aufzuhören Klassen zu verwenden, denn Klassen sind super komfortabel (im Gegensatz zu Objects) und da nehme ich das gerne In kauf. Und genauso sehe ich es mit With. Es können echt widerliche Fehler passieren, ist aber relativ leicht unter Kontrolle zu bekommen (und die Fehler durch with sind generell nicht so schwerwiegend, da ein falscher wert im Debugger recht schnell gefunden werden kann)

Mathias
Beiträge: 6160
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Form schliessen und wieder öffnen

Beitrag von Mathias »

Ich verwende auch sehr gerne with, man kann damit auch sehr schön Blöcke abtrennen.

Code: Alles auswählen

  // Shader des Quadrates
  with Quad_Shader do begin
    Shader := TShader.Create([FileToStr('quad.vert'), FileToStr('quad.frag')]);
    with Shader do begin
      UseProgram;
 
      WorldMatrix_id := UniformLocation('Matrix');
    end;
  end;
 
  // Shader des Würfels.
  with Cube_Shader do begin
    Shader := TShader.Create([FileToStr('cube.vert'), FileToStr('cube.frag')]);
    with Shader do begin
      UseProgram;
      glUniform1i(UniformLocation('Sampler0'), 0);
 
      WorldMatrix_id := UniformLocation('Matrix');
    end;
  end;

Aber schlussendlich ist es Geschmackssache.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Benutzeravatar
theo
Beiträge: 10467
Registriert: Mo 11. Sep 2006, 19:01

Re: Form schliessen und wieder öffnen

Beitrag von theo »

Mathias hat geschrieben:Ich verwende auch sehr gerne with, man kann damit auch sehr schön Blöcke abtrennen.

Code: Alles auswählen

  // Shader des Quadrates
  with Quad_Shader do begin
    Shader := TShader.Create([FileToStr('quad.vert'), FileToStr('quad.frag')]);
    with Shader do begin
      UseProgram;
 
      WorldMatrix_id := UniformLocation('Matrix');
    end;
  end;
 
  // Shader des Würfels.
  with Cube_Shader do begin
    Shader := TShader.Create([FileToStr('cube.vert'), FileToStr('cube.frag')]);
    with Shader do begin
      UseProgram;
      glUniform1i(UniformLocation('Sampler0'), 0);
 
      WorldMatrix_id := UniformLocation('Matrix');
    end;
  end;



Grauenhaft. :shock:
Ich habe schon viele Bugs gefunden, welche nur durch diese "praktische" Schreibweise entstanden sind.
Bei Verwendung von Code Completion hat das doch auch kaum einen Vorteil.

Benutzeravatar
m.fuchs
Lazarusforum e. V.
Beiträge: 2636
Registriert: Fr 22. Sep 2006, 19:32
OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
CPU-Target: x86, x64, arm
Wohnort: Berlin
Kontaktdaten:

Re: Gebrauch von With

Beitrag von m.fuchs »

Moderationshinweis: Ich habe mir mal erlaubt, die Diskussionen zu with aus dem ursprünglichen Thema in ein neues zu verschieben.
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de

Benutzeravatar
m.fuchs
Lazarusforum e. V.
Beiträge: 2636
Registriert: Fr 22. Sep 2006, 19:32
OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
CPU-Target: x86, x64, arm
Wohnort: Berlin
Kontaktdaten:

Re: Form schliessen und wieder öffnen

Beitrag von m.fuchs »

Warf hat geschrieben:Ist halt ein typischer Fall von "Code der einfacher zu schreiben als zu lesen ist"

Code der einfacher zu schreiben als zu lesen ist, ist grundsätzlich kein guter Code.

Mathias hat geschrieben:Ich verwende auch sehr gerne with, man kann damit auch sehr schön Blöcke abtrennen.

Wenn du Blöcke abtrennen möchtest, dann verwende doch einfach mal Methoden.

Code: Alles auswählen

 
procedure InitQuadShader(QuadShader: TWasWeissIch);
begin
  QuadShader.Shader := TShader.Create([FileToStr('quad.vert'), FileToStr('quad.frag')]);
  QuadShader.Shader.UseProgram;
  QuadShader.Shader.WorldMatrix_id := UniformLocation('Matrix');
end;
 
procedure InitCubeShader(CubeShader: TWasWeissIch);
begin
  CubeShader.Shader := TShader.Create([FileToStr('cube.vert'), FileToStr('cube.frag')]);
  CubeShader.Shader.UseProgram;
  CubeShader.Shader.glUniform1i(UniformLocation('Sampler0'), 0);
  CubeShader.Shader.WorldMatrix_id := UniformLocation('Matrix');
end
 
 
(* ... *)
 
InitQuadShader(Quad_Shader);
InitCubeShader(Cube_Shader);


Aber ich finde es gut, dass die Diskussion aufgekommen ist. So konnte ich gleich mal meine Code-Quality-Checks um ein Verbot von with...do erweitern. :mrgreen:
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de

mse
Beiträge: 2013
Registriert: Do 16. Okt 2008, 10:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
CPU-Target: x86,x64,ARM

Re: Gebrauch von With

Beitrag von mse »

Warum Free Pascal immer noch keine sichere "with" Version anbietet ist mir schleierhaft.
Sonst wird ja kritiklos jeder Mist von allen möglichen anderen Programmiersprachen übernommen um aus Free Pascal ein aufgeblähtes Monster zu machen.
Nur ein sicheres "with", wo eine Ergänzung wirklich sinnvoll wäre, wird seit über zehn Jahren ergebnislos diskutiert.

Benutzeravatar
m.fuchs
Lazarusforum e. V.
Beiträge: 2636
Registriert: Fr 22. Sep 2006, 19:32
OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
CPU-Target: x86, x64, arm
Wohnort: Berlin
Kontaktdaten:

Re: Gebrauch von With

Beitrag von m.fuchs »

Ja, da ist das in Visual Basic.NET wirklich sauberer gelöst.

Code: Alles auswählen

With result
  .AutoRenew = True
  .CancelPeriod = tld.CancellationPeriodInDays
  .Contact0 = Model.Core.DaoHelper.GetContactByHandle(context, bulktask.GetPropertyValue("owner"))
  .Contact1 = Model.Core.DaoHelper.GetContactByHandle(context, bulktask.GetPropertyValue("admin"))
  .DateModified = DateTime.Now
  .NameACE = nameACE
  .NameIDN = nameIDN
  .UpdateRequired = True
End With


Andererseits ist der Gebrauch von with häufig ein Zeichen dafür, dass eine Methode zu viel kann.
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de

siro
Beiträge: 730
Registriert: Di 23. Aug 2016, 14:25
OS, Lazarus, FPC: Windows 11
CPU-Target: 64Bit
Wohnort: Berlin

Re: Gebrauch von With

Beitrag von siro »

Ich liebe das "with"..... und vermisse es sehr in "C"
egal ob der "." oder "->" das macht die Software oftmals unnötig unleserlich.
Aber man muss natürlich aufpassen, dass man tatsächlich mit den richtigen Objekten/Records hantiert.
Im Prinzp ist das ja nur ein "versteckter" Pointer auf ein Object oder einen Record.
Hab sogar schon "with" mit 2 Paramtern benutzt. Bei 2 gleichen Objekten geht das aber eventuell in die Hose...
Grad mal probiert:

Code: Alles auswählen

 
with Button1,Button2 do begin
  caption:='Hallo';    // Button2 wird adressiert
end;
 
with Button2,Button1 do begin
  caption:='Hallo';    // Button1 wird adressiert
end;
 
with Button3,Button1,Button2 do begin
  caption:='Hallo';   // Button2 wird adressiert
end;                                   


hier wird anscheinend immer der zuletzt aufgeführte Parameter benutzt.

Siro
Grüße von Siro
Bevor ich "C" ertragen muß, nehm ich lieber Lazarus...

Antworten