Discussion:
Break/Continue/Exit - setzt ihr das ein?
(zu alt für eine Antwort)
Michael Landenberger
2007-03-04 22:17:38 UTC
Permalink
Hallo,

ich habe mir ja schon lange die GoTos abgewöhnt ;-) aber Break, Continue und
Exit setze ich immer noch gerne ein. Beispielsweise wähle ich manchmal
folgende Konstrukte:

var

StringListe : TStringList;

while Zaehler < MaxWert do begin
if StringListe [Zaehler] = 'abc' then begin
MachIrgendwas;
Continue
end;
if StringListe [Zaehler] = 'def' then begin
MachIrgendwasAnderes;
Continue
end;
(...)
Inc (Zaehler)
end;

oder auch folgende Funktion zum Durchsuchen einer Komponentenliste:

function FindeObjekt (GesuchterWert : Integer) : TComponent;

var

I : Integer;

begin
for I := 0 to Liste.Count - 1 do
if TComponent (Liste [I]).Tag = GesuchterWert then begin
Result := Liste [I];
Exit
end;
Result := nil
end;

Frage: fällt sowas unter "unsauberen" Programmierstil und sollte man sich
besser was anderes überlegen? Oder gibt's dagegen nix einzuwenden?

Gruß

Michael
Holger Lembke
2007-03-04 22:31:52 UTC
Permalink
"Michael Landenberger" <***@arcor.de> wrote:

Break und Continue nutze ich gar nicht. Was der Bauer nicht kennt... Dafür
Exit gerne. Insbesonders, um am Anfang in eine Routine "einfach" wieder
auszusteigen.
Post by Michael Landenberger
function FindeObjekt (GesuchterWert : Integer) : TComponent;
begin
for I := 0 to Liste.Count - 1 do
if TComponent (Liste [I]).Tag = GesuchterWert then begin
Result := Liste [I];
Exit
end;
Result := nil
end;
Wg. "sauber" würde ich das "result:=nil" direkt hinter dem "begin"
anordnen. Definierter Zustand und so. Nachher baut man noch ein Exit (ohne
Zuweisung von Result) ein und darf dann hoffen, dass man die
Compilerwarnung liest und beachtet.

Ansonsten nutze ich diese Schleifenkonstruktion auch gerne.
Post by Michael Landenberger
Frage: fällt sowas unter "unsauberen" Programmierstil und sollte man sich
besser was anderes überlegen? Oder gibt's dagegen nix einzuwenden?
Es gibt auch gegen Gotos nix einzuwenden. Ausser, dass der Code
unübersichtlich wird. Und da sind andere Dinge ähnlich schlimm (zu lange
Blöcke, zu komplexe Ausdrücke etc.).
--
mit freundlichen Grüßen! Passt der Filter auf meine Kamera?
Holgi, +49-531-3497854 ! Ihre Kamera? Immer! Ganz sicher!
Thomas G. Liesner
2007-03-04 22:51:08 UTC
Permalink
Post by Michael Landenberger
ich habe mir ja schon lange die GoTos abgewöhnt ;-) aber Break, Continue und
Exit setze ich immer noch gerne ein. Beispielsweise wähle ich manchmal
var
StringListe : TStringList;
while Zaehler < MaxWert do begin
if StringListe [Zaehler] = 'abc' then begin
MachIrgendwas;
Continue
Continue nutze ich extrem selten.
Post by Michael Landenberger
function FindeObjekt (GesuchterWert : Integer) : TComponent;
var
I : Integer;
begin
for I := 0 to Liste.Count - 1 do
if TComponent (Liste [I]).Tag = GesuchterWert then begin
Result := Liste [I];
Exit
end;
Result := nil
end;
Exit nutze ich hauptsächlich bei Vorprüfungen in Funktionen/Prozeduren,
mittendrin entweder gar nicht oder etliche Male, wenn ich keine extreme
Schachtelung möchte und es z.B. bei Prüfung von Datenvalidät nun mal ein
Dutzend Fehlermöglichkeiten gibt.
Post by Michael Landenberger
function FindeObjekt (GesuchterWert : Integer) : TComponent;
var
I : Integer;
begin
Result := nil
Post by Michael Landenberger
for I := 0 to Liste.Count - 1 do
if (Liste [I] as TComponent).Tag = GesuchterWert then begin
Post by Michael Landenberger
Result := Liste [I];
break
Post by Michael Landenberger
end;
end;
Andere würden in dem Fall eine While-Schleife nehmen, aber bei einem
bekannten Maximalwert finde ich for+break doch praktischer.
Post by Michael Landenberger
Frage: fällt sowas unter "unsauberen" Programmierstil und sollte man sich
besser was anderes überlegen? Oder gibt's dagegen nix einzuwenden?
Ist Geschmackssache.

So long,
Thomas G. Liesner
--
Neue Hamster-stable 2.1.0.11 seit 28.03.2006
http://www.tglsoft.de (Unterpunkt Freeware)
Joachim Mohr
2007-03-05 07:56:18 UTC
Permalink
Post by Thomas G. Liesner
Continue nutze ich extrem selten.
Ich öfters.
Zum Beispiel:

for k := a to b do Begin
try
ladeDatei[k]
except continue End;
machwasmitDatei[k]
end;


oder:

if not selected[i] then continue;

Bei "if selected[i] then begin"
muß ich die ganze Zeit im Hinterkopf das zugehörige
"end" mir merken. Bei längeren, verschachtelten
Prozeduren verliert man schnell den Überblick.

Dann finde ich: "Continue" macht es übersichtlicher.

u.s.w.

MFG Joachim
--
Joachim Mohr, Tübingen
www.joachimmohr.de
Lektionen zu Delphi Vektoren und Musiktheorie
Thomas G. Liesner
2007-03-05 12:16:24 UTC
Permalink
Post by Joachim Mohr
Post by Thomas G. Liesner
Continue nutze ich extrem selten.
Ich öfters.
for k := a to b do Begin
try
ladeDatei[k]
except continue End;
machwasmitDatei[k]
end;
for k := a to b do Begin
try
ladeDatei[k];
machwasmitDatei[k]
Post by Joachim Mohr
except
On E:Exception do Fehlermeldung oder raise Exception
End;
Post by Joachim Mohr
end;
Fehlerschlucken ohne Hinweise an den Benutzer mag ich nicht, falls
Zweifel an der Existenz der Datei bestehen kommt ein FileExists davor,
sonstige Fehler möchte ich wissen.
Post by Joachim Mohr
if not selected[i] then continue;
Bei "if selected[i] then begin"
muß ich die ganze Zeit im Hinterkopf das zugehörige
"end" mir merken. Bei längeren, verschachtelten
Prozeduren verliert man schnell den Überblick.
Das End; wird direkt nach dem begin eingefügt (bei D2006 netterweise
automatisch) und dann erst der Zwischenbereich gefüllt, dann kann da
nichts übersehen/vergessen werden.
Post by Joachim Mohr
Dann finde ich: "Continue" macht es übersichtlicher.
u.s.w.
Bei zu tiefen Schachtelungen fasse ich üblicherweise entweder
Bedingungen zusammen oder lagere in (Sub)Prozeduren/Funktionen aus. Bei
zuviel Ausstiegspunkten ist exit meistens ausreichend, da eh in eine
Hilfsfunktion ausgelagert, ausbrechen innerhalb tiefer Verschachtelungen
kommt eher selten vor.

So long,
Thomas G. Liesner
--
Neue Hamster-stable 2.1.0.11 seit 28.03.2006
http://www.tglsoft.de (Unterpunkt Freeware)
Joachim Mohr
2007-03-06 07:58:17 UTC
Permalink
Post by Joachim Mohr
Post by Joachim Mohr
for k := a to b do Begin
try
ladeDatei[k];
machwasmitDatei[k]
Post by Joachim Mohr
except
On E:Exception do Fehlermeldung oder raise Exception
End;
Post by Joachim Mohr
end;
Einverstanden. Anderes Besipiel. Du löscht MP3-Files, aber der
Player beschlagtnahmt noch eine Datei. Dann wäre folgendes sinnvoll.

for k := a to b do Begin
try
loescheDatei[k];
except
On E:Exception do Fehlermeldung
("Datei konnte nicht gelöscht werden");
Continue; //wenn schon die Hälfte gelöscht ist
//soll auch der möglichen Rest gelöscht werden.
//Deshalb coninue "Mach weiter!"
End;
end;
Post by Joachim Mohr
Fehlerschlucken ohne Hinweise an den Benutzer mag ich nicht.
Da gebe ich Dir Recht! Es gibt aber Ausnahmen:

Beispiel (und darauf bezog sich mein erster Quelltext):

Ich habe ein Programm -ähnlich wie in Powerpoint-,
da wird zu jedem Bild ein Text eingeblendet, der
- falls nötig - in einer extra Datei gespeichert ist.

Ist kein Text gespeichert, erscheint er auch nicht.
Fehlermeldung wäre hier unangebracht udn störend!


MFG Joachim
--
Joachim Mohr, Tübingen
www.joachimmohr.de
Lektionen zu Delphi Vektoren und Musiktheorie
Joe Galinke
2007-03-06 09:11:30 UTC
Permalink
Hallo Joachim,
Post by Joachim Mohr
for k := a to b do Begin
try
loescheDatei[k];
except
On E:Exception do Fehlermeldung
("Datei konnte nicht gelöscht werden");
Continue; //wenn schon die Hälfte gelöscht ist
//soll auch der möglichen Rest gelöscht werden.
//Deshalb coninue "Mach weiter!"
End;
end;
Habe ich heute einen schlechten Tag oder warum verstehe ich das nicht? Was
soll das "Continue" dort? Wenn "Fehlermeldung" nicht zu einer weiteren
Exception führt wird die Schleife doch weiter abgearbeitet, schließlich
wurde die Exception ja behandelt.



Gruß, Joe
--
Joachim Mohr
2007-03-06 10:06:48 UTC
Permalink
Post by Joe Galinke
Hallo Joachim,
Post by Joachim Mohr
for k := a to b do Begin
try
loescheDatei[k];
except
On E:Exception do Fehlermeldung
("Datei konnte nicht gelöscht werden");
Continue; //wenn schon die Hälfte gelöscht ist
//soll auch der möglichen Rest gelöscht werden.
//Deshalb coninue "Mach weiter!"
End;
end;
Habe ich heute einen schlechten Tag oder warum verstehe ich das nicht? Was
soll das "Continue" dort? Wenn "Fehlermeldung" nicht zu einer weiteren
Exception führt wird die Schleife doch weiter abgearbeitet, schließlich
wurde die Exception ja behandelt.
Nein, es ist mein schlechter Tag. Du hast Recht:
In diesem und meinem 2. Beispiel ist continue überflüssig.

MFG Joachim
--
Joachim Mohr, Tübingen
www.joachimmohr.de
Lektionen zu Delphi Vektoren und Musiktheorie
Joachim Mohr
2007-03-06 10:12:06 UTC
Permalink
Post by Joe Galinke
Hallo Joachim,
Post by Joachim Mohr
for k := a to b do Begin
try
loescheDatei[k];
except
On E:Exception do Fehlermeldung
("Datei konnte nicht gelöscht werden");
Continue; //wenn schon die Hälfte gelöscht ist
//soll auch der möglichen Rest gelöscht werden.
//Deshalb coninue "Mach weiter!"
End;
end;
Habe ich heute einen schlechten Tag oder warum verstehe ich das nicht? Was
soll das "Continue" dort? Wenn "Fehlermeldung" nicht zu einer weiteren
Exception führt wird die Schleife doch weiter abgearbeitet, schließlich
wurde die Exception ja behandelt.
Nein! Du hast recht, Das Continue wäre nur erforderlich, falls noch eine
Anweisung noch except ... end käme, die ich dann nicht ausgeführt haben
wollte.

MFG Joachim
--
Joachim Mohr, Tübingen
www.joachimmohr.de
Lektionen zu Delphi Vektoren und Musiktheorie
Joe Galinke
2007-03-06 10:39:22 UTC
Permalink
Hallo Joachim,
Post by Joachim Mohr
Nein! Du hast recht, Das Continue wäre nur erforderlich, falls noch eine
Anweisung noch except ... end käme, die ich dann nicht ausgeführt haben
wollte.
Was aber IMHO auch nur Sinn bei mehreren abgefragten
Exceptionklassen/Exceptiondetails Sinn machen würde. Aber auch dann würde
ich es anders lösen. Die mangelnde Gewohnheit lässt mich Code mit
Continue/Break auch weniger flüssig lesen.

Gruß, Joe
--
Thomas G. Liesner
2007-03-06 10:49:51 UTC
Permalink
Post by Joachim Mohr
Post by Joachim Mohr
Post by Joachim Mohr
for k := a to b do Begin
try
ladeDatei[k];
machwasmitDatei[k]
Post by Joachim Mohr
except
On E:Exception do Fehlermeldung oder raise Exception
End;
Post by Joachim Mohr
end;
Einverstanden. Anderes Besipiel. Du löscht MP3-Files, aber der
Player beschlagtnahmt noch eine Datei. Dann wäre folgendes sinnvoll.
for k := a to b do Begin
try
loescheDatei[k];
except
On E:Exception do Fehlermeldung
("Datei konnte nicht gelöscht werden");
Continue; //wenn schon die Hälfte gelöscht ist
//soll auch der möglichen Rest gelöscht werden.
//Deshalb coninue "Mach weiter!"
End;
Nur, wenn hier noch Code stände, der vor das except nicht mehr passt.
Post by Joachim Mohr
end;
Post by Joachim Mohr
Fehlerschlucken ohne Hinweise an den Benutzer mag ich nicht.
Ich habe ein Programm -ähnlich wie in Powerpoint-,
da wird zu jedem Bild ein Text eingeblendet, der
- falls nötig - in einer extra Datei gespeichert ist.
Ist kein Text gespeichert, erscheint er auch nicht.
Fehlermeldung wäre hier unangebracht udn störend!
Nein, ein FileExists wäre angebracht, sofern das Laden aus mehr als
einem Stringlist.LoadFromFIle besteht, da beim Einlesen in die eigenen
Datenstrukturen auch irgendwas haken kann, was dir beim Verschlucken
nicht auffällt. Und wenn du nur das abkapselst, würde ich optisch
folgendes vorziehen:

Var Geladen: boolean;

...
try
Ladevorgang;
Geladen := true;
except
Geladen := false;
end;
If Geladen then begin
...
end
...

So long,
Thomas G. Liesner
--
Neue Hamster-stable 2.1.0.11 seit 28.03.2006
http://www.tglsoft.de (Unterpunkt Freeware)
Joachim Mohr
2007-03-06 14:06:27 UTC
Permalink
Post by Thomas G. Liesner
Var Geladen: boolean;
...
try
Ladevorgang;
Geladen := true;
except
Geladen := false;
end;
If Geladen then begin
...
end
Ok. Kannst Du mir recht geben, dass folgender Code
Identisches bewirkt.

try
Ladevorgang;
except
continue;
end;

...
Ich spare mir dadurch die Flagge "Geladen" und ein "Begin ... End".
Dann wäre es Geschmackssache.

MFG Joachim
--
Joachim Mohr, Tübingen
www.joachimmohr.de
Lektionen zu Delphi Vektoren und Musiktheorie
Thomas G. Liesner
2007-03-06 15:06:51 UTC
Permalink
Post by Joachim Mohr
Post by Thomas G. Liesner
Var Geladen: boolean;
...
try
Ladevorgang;
Geladen := true;
except
Geladen := false;
end;
If Geladen then begin
...
end
Ok. Kannst Du mir recht geben, dass folgender Code
Identisches bewirkt.
try
Ladevorgang;
except
continue;
end;
Natürlich. Ich habe eine IMHO langweiligere und somit etwas leichter
erfassbarere Variante genannt.
Post by Joachim Mohr
...
Ich spare mir dadurch die Flagge "Geladen" und ein "Begin ... End".
Dann wäre es Geschmackssache.
Ack.

So long,
Thomas G. Liesner
--
Neue Hamster-stable 2.1.0.11 seit 28.03.2006
http://www.tglsoft.de (Unterpunkt Freeware)
Hans-Peter Diettrich
2007-03-06 17:38:19 UTC
Permalink
Post by Thomas G. Liesner
Nein, ein FileExists wäre angebracht, sofern das Laden aus mehr als
einem Stringlist.LoadFromFIle besteht, da beim Einlesen in die eigenen
Datenstrukturen auch irgendwas haken kann, was dir beim Verschlucken
nicht auffällt. Und wenn du nur das abkapselst, würde ich optisch
Var Geladen: boolean;
...
try
Ladevorgang;
Geladen := true;
except
Geladen := false;
end;
If Geladen then begin
...
end
...
Und ich würde die erste Zuweisung an Geladen vor das Try setzen. Das
kostet nichts, ist aber sicher und leicht verständlich. Dann kann auch
der Compiler nicht über möglicherweise uninitialisierte Variablen
meckern, egal ob berechtigt oder nicht. Bei Schleifen kann das Setzen in
der Schleife auch mal unerwartet schiefgehen, wenn nämlich die Schleife
überhaupt nicht betreten wird.

DoDi
Thomas G. Liesner
2007-03-06 21:04:23 UTC
Permalink
Post by Hans-Peter Diettrich
Und ich würde die erste Zuweisung an Geladen vor das Try setzen.
Geschmackssache - da noch nichts geladen wurde, halte ich das für
irritierend. Dann eher auf false setzen und einen leeren Except-Handler.
Post by Hans-Peter Diettrich
Dann kann auch der Compiler nicht über möglicherweise uninitialisierte
Variablen meckern, egal ob berechtigt oder nicht.
Solche Meldungen kommen in meinem Code nicht bzw. werden umgehend zum
Verschwinden gebracht.
Post by Hans-Peter Diettrich
Bei Schleifen kann das Setzen in
der Schleife auch mal unerwartet schiefgehen, wenn nämlich die Schleife
überhaupt nicht betreten wird.
Da das Geladen nur innerhalb der Schleife von Bedeutung ist, passt der
Hinweis nicht auf die skizzierte Situation.

So long,
Thomas G. Liesner
--
Neue Hamster-stable 2.1.0.11 seit 28.03.2006
http://www.tglsoft.de (Unterpunkt Freeware)
Rolf Eike Beer
2007-03-06 21:44:19 UTC
Permalink
Post by Thomas G. Liesner
Post by Joachim Mohr
if not selected[i] then continue;
Bei "if selected[i] then begin"
muß ich die ganze Zeit im Hinterkopf das zugehörige
"end" mir merken. Bei längeren, verschachtelten
Prozeduren verliert man schnell den Überblick.
Das End; wird direkt nach dem begin eingefügt (bei D2006 netterweise
automatisch) und dann erst der Zwischenbereich gefüllt, dann kann da
nichts übersehen/vergessen werden.
Continue spart eine Ebene in der Hierarchie. Je nach Einrückungsstil ist das
sehr hilfreich.
Post by Thomas G. Liesner
Post by Joachim Mohr
Dann finde ich: "Continue" macht es übersichtlicher.
u.s.w.
Bei zu tiefen Schachtelungen fasse ich üblicherweise entweder
Bedingungen zusammen oder lagere in (Sub)Prozeduren/Funktionen aus. Bei
zuviel Ausstiegspunkten ist exit meistens ausreichend, da eh in eine
Hilfsfunktion ausgelagert, ausbrechen innerhalb tiefer Verschachtelungen
kommt eher selten vor.
Schön wäre es dann noch wenn man wüsste oder beeinflussen könnte wann der
Compiler Funktionen inlined.

Eike
Joachim Mohr
2007-03-05 07:31:26 UTC
Permalink
Post by Michael Landenberger
Hallo,
ich habe mir ja schon lange die GoTos abgewöhnt ;-) aber Break, Continue
und Exit setze ich immer noch gerne ein. Beispielsweise wähle ich
var
StringListe : TStringList;
while Zaehler < MaxWert do begin
if StringListe [Zaehler] = 'abc' then begin
MachIrgendwas;
Continue
end;
if StringListe [Zaehler] = 'def' then begin
MachIrgendwasAnderes;
Continue
end;
(...)
Inc (Zaehler)
end;
Hier bietet sich an:

Zaehler := start; //Anfangswert fehlt bei Dir!
while Zaehler < MaxWert do begin
if StringListe [Zaehler] = 'abc' then MachIrgendwas
else if StringListe [Zaehler] = 'def' then MachIrgendwasAnderes;
else (...);
Inc (Zaehler)
end;

oder (schneller).

Ich nehme mal an: Start := 0 und Maxwert := Stringliste.count;

for Zaehler := 0 to Stringliste.count - 1 do
if StringListe [Zaehler] = 'abc' then MachIrgendwas
else if StringListe [Zaehler] = 'def' then MachIrgendwasAnderes;
else (...);
Post by Michael Landenberger
function FindeObjekt (GesuchterWert : Integer) : TComponent;
var
I : Integer;
begin
for I := 0 to Liste.Count - 1 do
if TComponent (Liste [I]).Tag = GesuchterWert then begin
Result := Liste [I];
Exit
end;
Result := nil
end;
Mach ich genauso. Noch nichts besseres gesehen.

MFG Jaochim
--
Joachim Mohr, Tübingen
www.joachimmohr.de
Lektionen zu Delphi Vektoren und Musiktheorie
Hans-Peter Diettrich
2007-03-05 08:10:52 UTC
Permalink
Michael Landenberger wrote:

Habe grade erst ein Problem in Deinem Code entdeckt. Die fehlende
Initialisierung von Zaehler dürfte sich von selbst verstehen, aber...
Post by Michael Landenberger
while Zaehler < MaxWert do begin
if StringListe [Zaehler] = 'abc' then begin
MachIrgendwas;
Continue
Wohin sollte dieses Continue IYO führen?
Post by Michael Landenberger
(...)
Inc (Zaehler)
end;
Dieses Inc wird nach Continue ganz sicher nicht mehr ausgeführt, Du
landest also in einer Endlosschleife :-(

Wir hatten das gerade unter "C for", dort führt ein continue *nicht* wie
sonst üblich zum Schleifen-Test, sondern zum "step" Ausdruck. Siehe
Kommentar unten, den baue ich mir immer ein, wenn ich ein C for in
Pascal nachbaue.

Mit einer sinnvollen Konvention zum Schreiben von verschachtelten
if-else-if würde ich das so schreiben:

while ... do begin
if cond1 then begin
... //ohne Continue!
end else if cond2 then begin
...
end else if cond3 then begin
...
end;
//step
Inc(Zaehler);
end;
Post by Michael Landenberger
Frage: fällt sowas unter "unsauberen" Programmierstil und sollte man
sich besser was anderes überlegen? Oder gibt's dagegen nix einzuwenden?
Break und Exit verwende ich selbst regelmäßig, Continue eher nicht
(siehe "step"), höchstens in For-Schleifen.

Mit Exit und Break bin ich schon zweimal auf die Schnauze geflogen,
einmal weil dummerweise irgendwo eine Funktion Exit herumlag, und ein
andermal hat Delphi (D4?) ein Break in einem Case irgendwie in den
falschen Hals bekommen - damit wurde das Unterprogramm verlassen, und
nicht die Schleife um den Case. Nach dem Einfügen eines Dummy-Statements
war der Fehler aber anscheinend weg.

Huch: Ein Case mit Schleifchen - was da wohl drin sein mag? ;-)

DoDi
Michael Landenberger
2007-03-05 09:44:58 UTC
Permalink
Post by Hans-Peter Diettrich
Dieses Inc wird nach Continue ganz sicher nicht mehr ausgeführt,
Du landest also in einer Endlosschleife :-(
Sorry, ich vergaß zu erwähnen, dass auch in "MachIrgendwas" und
"MachIrgendwasAnderes" ein Inc (Zaehler) eingebaut ist.
Post by Hans-Peter Diettrich
Mit einer sinnvollen Konvention zum Schreiben von verschachtelten
Ich mag verschachtelte if-elses nicht so gerne. Bei vielen verschiedenen
Bedingungen mit den entsprechenden Einrückungen landet der Code für die
letzte else-Bedingung dann womöglich jenseits der 80-Zeichen-Grenze. Bei
Integer-Vergleichen nehme ich natürlich case ... of. Man könnte case im
Prinzip auch für Stringvergleiche nehmen, wenn die Strings immer gleich lang
sind. Dann packt man alle Möglichkeiten in einen Vergleichsstring, sucht mit
Pos () die Position, an der sich der zu testende String befindet, und wertet
das Ergebnis mit case aus. Wie sich das perfomancemäßig auswirkt, habe ich
allerdings noch nicht getestet.
Post by Hans-Peter Diettrich
Mit Exit und Break bin ich schon zweimal auf die Schnauze
geflogen, einmal weil dummerweise irgendwo eine Funktion Exit
herumlag, und ein andermal hat Delphi (D4?) ein Break in einem
Case irgendwie in den falschen Hals bekommen
Vorsichtig muss man auch in try-finally-Blöcken sein. Der finally-Abschnitt
wird auf jeden Fall ausgeführt, auch wenn im try-Abschnitt davor ein Break,
Continue oder Exit steht.

Gruß

Michael
Matthias Hanft
2007-03-05 10:27:12 UTC
Permalink
Post by Michael Landenberger
Ich mag verschachtelte if-elses nicht so gerne. Bei vielen verschiedenen
Bedingungen mit den entsprechenden Einrückungen landet der Code für die
letzte else-Bedingung dann womöglich jenseits der 80-Zeichen-Grenze. Bei
Integer-Vergleichen nehme ich natürlich case ... of.
Man _muß_ ja bei sowas nicht unendlich einrücken. Ich find's schon auch
schade, daß es kein CASE für Strings gibt, aber wenn man den Quältext
einfach analog dazu schreibt, wie von Hans-Peter schon vorgeschlagen:

if Dings1 then begin
TuWas1
end else if Dings2 then begin
TuWas2
end else if Dings3 then begin
TuWas3
end else if Dings4 then begin
TuWas4
end else begin
TuWasGanzAnderes
end;

dann erinnert das doch sehr an CASE und wird auch nicht unendlich breit.

Mach' ich seit einiger Zeit konsequent so - und versteh's auch nach einem
Jahr noch (das find' ich das wichtigste: daß man seinen eigenen Code auch
irgendwann später noch versteht) :-)

Gruß Matthias.
Matthias Frey
2007-03-06 07:08:28 UTC
Permalink
Post by Matthias Hanft
if Dings1 then begin
TuWas1
end else if Dings2 then begin
TuWas2
end else if Dings3 then begin
TuWas3
end else if Dings4 then begin
TuWas4
end else begin
TuWasGanzAnderes
end;
Ich oute mich mal, so was schreib ich manchmal so:

repeat
if Dings1
then begin TuWas1; break; end;
if Dings2
then begin TuWas2; break; end;
if Dings3
then begin TuWas3; break; end;
if Dings4
then begin TuWas4; break; end;
until false

Häufiger sind es solche Kontruktionen wie z.B.
repeat
if not Assigned(Brauch ich jetzt) then break;
if SL.Count <= 0 then break;
TuDiesUndDasUndJenesUndNochVielMehr;
until false

Ohne Castelia ist das sonst recht unübersichtlich.
Post by Matthias Hanft
Gruß Matthias.
Grüße - auch Matthias
Hans-Peter Diettrich
2007-03-06 01:56:40 UTC
Permalink
Post by Michael Landenberger
Post by Hans-Peter Diettrich
Mit einer sinnvollen Konvention zum Schreiben von verschachtelten
Ich mag verschachtelte if-elses nicht so gerne. Bei vielen verschiedenen
Bedingungen mit den entsprechenden Einrückungen landet der Code für die
letzte else-Bedingung dann womöglich jenseits der 80-Zeichen-Grenze.
Deshalb schrieb ich ja: mit einer *sinnvollen* Konvention ;-)
(siehe Beispiel)

DoDi
Michael Landenberger
2007-03-06 08:46:50 UTC
Permalink
Post by Michael Landenberger
Post by Hans-Peter Diettrich
Mit einer sinnvollen Konvention zum Schreiben von verschachtelten
Ich mag verschachtelte if-elses nicht so gerne. Bei vielen verschiedenen
Bedingungen mit den entsprechenden Einrückungen landet der Code für die
letzte else-Bedingung dann womöglich jenseits der 80-Zeichen-Grenze.
Deshalb schrieb ich ja: mit einer *sinnvollen* Konvention ;-)
Für mich persönlich ist das Einrücken jeder einzelnen Anweisungsebene die
einzig sinnvolle Konvention. Alles andere halte ich für unübersichtlicher.

Gruß

Michael
Hans-Peter Diettrich
2007-03-06 17:51:44 UTC
Permalink
Post by Michael Landenberger
Für mich persönlich ist das Einrücken jeder einzelnen Anweisungsebene
die einzig sinnvolle Konvention. Alles andere halte ich für
unübersichtlicher.
Für mich ist ein if-else-if nichts anderes als ein Case. Es wird immer
nur genau ein Zweig ausgeführt, und welcher das ist, läßt sich leichter
nachvollziehen, wenn alle Abfragen auf der gleichen (Einrückungs-)Ebene
liegen. Manche Programmiersprachen haben sogar ein eigenes ElseIf, meist
in Verbindung mit EndIf, dann kann man sich auch noch diese dussligen
Begin...End Klammerungen sparen.

Und ich vermeide jede überflüssige Einrückung, bei mir werden auch
Case-Labels nicht eingerückt. Manche Leute treiben ja die
Platzverschwendung bis zum Exzess, z.B. mit:

if ...
then
begin
...
end
else
begin

Das sind mir etliche Zeilen und Spalten zu viel. Vor allem die
überflüssigen Zeilen verringern die Information drastisch, die in einem
Fenster auf dem Bildschirm dargestellt werden kann. Wer so
verschwenderisch mit dem Platz umgeht, der wird meist nach Zeilen
bezahlt, nicht für das, was sein Code tatsächlich macht ;-)

DoDi
Michael Landenberger
2007-03-06 20:31:11 UTC
Permalink
Post by Hans-Peter Diettrich
Und ich vermeide jede überflüssige Einrückung, bei mir werden
auch Case-Labels nicht eingerückt. Manche Leute treiben ja die
if ...
then
begin
...
end
else
begin
Das sind mir etliche Zeilen und Spalten zu viel.
Mir auch ;-) Ich schreibe in der Regel so:

if ... then begin
...
end
else begin
...
end;

Insbesondere schreibe ich das "begin" immer in die gleiche Zeile wie das
"if" und das "else" immer unter das "end" der if-Bedingung, auch wenn das
viele anders machen.

Eine Verzweigung mit verschachtelten ifs sähe bei mir dann so aus:

if ... then begin
...
end
else
if ... then begin
end
else
if ... then begin
end;

Das mache ich aber nur, wenn es sich nicht vermeiden lässt, es ist mir
nämlich schlicht zu unübersichtlich. In Schleifen bevorzuge ich daher

if ... then begin
...
Continue
end;
if ... then begin
...
Continue
end;

Hier stehen die einzelnen Bedingungen schön untereinander und man kann
schnell sehen, unter welcher Bedingung was passiert. Ebenso ist es sehr
einfach, bei Bedarf weitere Bedingungen hinzuzufügen.

Gruß

Michael
Hans-Peter Diettrich
2007-03-06 22:40:02 UTC
Permalink
Post by Michael Landenberger
if ... then begin
...
end
else
if ... then begin
end
else
if ... then begin
end;
Dagegen habe ich aus meiner Erfahrung einen Einwand:

Eine Struktur kann leichter erkannt und verifiziert werden, wenn jeder
Abschnitt gegenüber dem vorhergehenden und auch dem *nächsten* um
*genau* eine Ebene eingerückt ist.

Lege um Dein Beispiel eine Schleife o.ä. herum, und Du wirst am Ende
Probleme haben, in welcher Spalte das End der Schleife liegen sollte. In
meinem System stellt sich diese Frage nicht, es muß zum vorhergehenden
Statement genau 1 Ebene ausgerückt werden.

Ganz grausig zerrupft wird Dein Code dann, wenn mehr als nur Else-If
vorkommt. Dann können Teile aus nicht so leicht nachvollziehbaren
Gründen um jede beliebige Anzahl von Ebenen nach links springen, und das
Einfügen und vor allem das Löschen einer Bedingung läßt sich von Hand
kaum noch durchführen. Diese Probleme treten in einer flacheren
Einrückungshierarchie erst garnicht auf.
Post by Michael Landenberger
if ... then begin
...
Continue
end;
if ... then begin
...
Continue
end;
Hier stehen die einzelnen Bedingungen schön untereinander und man kann
schnell sehen, unter welcher Bedingung was passiert.
Auch das sehe ich anders. Nur wenn man verfolgt, in welchem Abschnitt
ein Break oder Continue steht, kann man wissen, ob die nachfolgenden
Anweisungen noch ausgeführt werden oder nicht. Wenn alle Else-If Zweige
auf derselben Ebene liegen, dann kann man hingegen schon rein optisch
leicht und sicher ermitteln, wo die Ausführung weitergeht. Das
vereinfacht auch die Prüfung, ob alle Möglichkeiten in den Abfragen
berücksichtigt wurden.

Genaugenommen sehe ich in Deiner Verwendung von Continue hier nur die
schlechte Tradition des GoTo fortgesetzt, nur mit anderen Mitteln. Statt
daß man sich darauf verlassen kann, daß Statements auf der gleichen
Ebene sequentiell durchlaufen werden, muß man in Deinem Code erst nach
Statements suchen, welche diesen sequentiellen Ablauf unterbrechen
könnten. Wenn dann noch ein Continue von vorhergehenden Bedingungen
abhängt, dann muß man sogar den ganzen Weg zurückverfolgen, um
feststellen zu können, wann genau dieses Continue überhaupt ausgeführt
wird. Das ist IMO alles andere als eine strukturierte Programmierung,
selbst wenn die Wahl der Sprachmittel etwas anderes vortäuscht.
Post by Michael Landenberger
Ebenso ist es sehr
einfach, bei Bedarf weitere Bedingungen hinzuzufügen.
Genau deshalb rücke ich Else erst garnicht weiter ein.

DoDi
Joachim Mohr
2007-03-07 08:43:17 UTC
Permalink
Post by Michael Landenberger
if ... then begin
...
end
else begin
...
end;
Ich spare noch eine Zeile
if ... then begin
...
end else Begin
...
end;

Noch eine kleine Anekdote:

Anektdote (Typisch deutsch):

Die Polizei,
die die Bankräuber,
die die Sparkasse in Weiler,
die neben dem Rathaus,
das vom berühmten Architekten,
der auch das Rathaus in Oberdorf,
das kürzlich
abbrannte,
gebaut wurde,
steht,
überfielen,
verfolgte,
hatte Erfolg.

Hab ich das nicht schön mit Einrückungen strukturiert?

MFG Joachim
--
Joachim Mohr, Tübingen
www.joachimmohr.de
Lektionen zu Delphi Vektoren und Musiktheorie
Hans-Peter Diettrich
2007-03-07 09:40:54 UTC
Permalink
Post by Joachim Mohr
Die Polizei,
die die Bankräuber,
die die Sparkasse in Weiler,
die neben dem Rathaus,
das vom berühmten Architekten,
der auch das Rathaus in Oberdorf,
das kürzlich
abbrannte,
gebaut wurde,
steht,
überfielen,
verfolgte,
hatte Erfolg.
Hab ich das nicht schön mit Einrückungen strukturiert?
Wunderschön, beides :-)

Nur klemmt das noch, und anhand der Einrückungen läßt sich der Fehler
Post by Joachim Mohr
das vom berühmten Architekten,
der auch das Rathaus in Oberdorf,
das kürzlich abbrannte,
gebaut hatte,
gebaut wurde,

Mit 2 Leerzeichen pro Einrückung wäre der Fehler noch auffälliger gewesen.

DoDi
Burkhard Schneider
2007-03-07 08:44:04 UTC
Permalink
Post by Michael Landenberger
Post by Hans-Peter Diettrich
Das sind mir etliche Zeilen und Spalten zu viel.
if ... then begin
...
end
else begin
...
end;
ACK. Das sieht bei mir genauso aus.
Post by Michael Landenberger
if ... then begin
...
end
else
if ... then begin
end
else
if ... then begin
end;
Das nicht!! Alleich schon gedanklich bin ich noch nie auf die Idee gekommen,
das es sich bei einem solchen Konstrukt um "verschachtelte ifs" handelt. Für
mich sich das gleichberechtigte Bedingungen auf einer Ebene, von denen nur
ein Zweig ausgeführt werden soll, also durchaus vergleichbar mit einem Case,
nur dass die Bedingung komplexer formuliert werden kann.

Konsequenterweise sähe Dein obiger Code bei mir so aus:

if ... then begin
...
end
else if ... then begin
end
else if ... then begin
end;
Post by Michael Landenberger
Hier stehen die einzelnen Bedingungen schön untereinander und man kann
schnell sehen, unter welcher Bedingung was passiert. Ebenso ist es sehr
einfach, bei Bedarf weitere Bedingungen hinzuzufügen.
Nur, dass man sich das dusselige Continue spart.

Gruß
Burkhard Schneider
Marian Aldenhövel
2007-03-05 10:19:29 UTC
Permalink
Hallo,
Post by Michael Landenberger
if StringListe [Zaehler] = 'abc' then begin
MachIrgendwas;
Continue
end;
if StringListe [Zaehler] = 'def' then begin
MachIrgendwasAnderes;
Continue
end;
Das ist ein if-then-else. Continue macht es nicht besser, schöner, schneller
oder sicherer. Insofern in diesem Fall: Abgelehnt.
Post by Michael Landenberger
for I := 0 to Liste.Count - 1 do
if TComponent (Liste [I]).Tag = GesuchterWert then begin
Result := Liste [I];
Exit
end;
Und das ein repeat:

Result:=NIL;
i:=0;
while (Result=NIL) and (i<Liste.Count) do
if Bedingung
then Result:=Liste[i]
else inc(i);

Also für Dein Beispiel: Abgelehnt.

Ein komplexeres Beispiel könnte allenfalls ein break verdienen, dann eben
die Defaultzuweisung NIL am Anfang.

Exits sind so endgültig. In einer langen Methode kann man bei Änderungen
hinten was anhängen und wenn dann in der Mitte ein Exit die Ausführung dieser
Änderung in zwei Promille der Fälle verhindert gibt das Tränen.

Ciao, MM
--
Marian Aldenhövel, Rosenhain 23, 53123 Bonn
http://www.marian-aldenhoevel.de
"Success is the happy feeling you get between the time you
do something and the time you tell a woman what you did."
Michael Landenberger
2007-03-05 10:44:09 UTC
Permalink
Post by Marian Aldenhövel
Post by Michael Landenberger
if StringListe [Zaehler] = 'abc' then begin
MachIrgendwas;
Continue
end;
if StringListe [Zaehler] = 'def' then begin
MachIrgendwasAnderes;
Continue
end;
Das ist ein if-then-else. Continue macht es nicht besser, schöner,
schneller oder sicherer. Insofern in diesem Fall: Abgelehnt.
Einspruch: zumindest schöner als if - then - else - if - then - else...
finde ich es schon. Und die Geschwindigkeit sollte auch nicht nennenswert
beeinträchtigt werden, denn ein "Continue" auszuführen kostet nicht viel
mehr Rechenzeit als ein "else" (beides sind nur Sprünge). Die Anzahl der
Vergleiche (der eigentlich rechenintensivste Vorgang) ist bei beiden
Lösungen gleich.
Post by Marian Aldenhövel
Post by Michael Landenberger
for I := 0 to Liste.Count - 1 do
if TComponent (Liste [I]).Tag = GesuchterWert then begin
Result := Liste [I];
Exit
end;
Result:=NIL;
i:=0;
while (Result=NIL) and (i<Liste.Count) do
if Bedingung
then Result:=Liste[i]
else inc(i);
Also für Dein Beispiel: Abgelehnt.
for-Schleifen sollen schneller sein als while-Schleifen, habe ich mir mal
sagen lassen.
Post by Marian Aldenhövel
Ein komplexeres Beispiel könnte allenfalls ein break verdienen, dann
eben die Defaultzuweisung NIL am Anfang.
Dieser Vorschlag kam auch schon von anderen Schreibern. Mir stellt sich
allerdings die Frage: warum eigentlich? Die Funktion kann auch bei meiner
Lösung nicht mit undefiniertem Result verlassen werden.
Post by Marian Aldenhövel
Exits sind so endgültig. In einer langen Methode kann man bei
Änderungen hinten was anhängen und wenn dann in der Mitte ein Exit
die Ausführung dieser Änderung in zwei Promille der Fälle verhindert
gibt das Tränen.
Das gilt aber auch für if...then. Wenn deine if-Bedingung 500 Zeilen weiter
oben im Code steht, weißt du manchmal auch nicht mehr, warum der neu
hinzugefügte Code nicht ausgeführt wird.

Gruß

Michael
Mario Rothacher
2007-03-05 11:02:45 UTC
Permalink
Post by Michael Landenberger
Post by Marian Aldenhövel
Post by Michael Landenberger
if StringListe [Zaehler] = 'abc' then begin
MachIrgendwas;
Continue
end;
if StringListe [Zaehler] = 'def' then begin
MachIrgendwasAnderes;
Continue
end;
Das ist ein if-then-else. Continue macht es nicht besser, schöner,
schneller oder sicherer. Insofern in diesem Fall: Abgelehnt.
Einspruch: zumindest schöner als if - then - else - if - then - else...
finde ich es schon. Und die Geschwindigkeit sollte auch nicht
nennenswert beeinträchtigt werden, denn ein "Continue" auszuführen
kostet nicht viel mehr Rechenzeit als ein "else" (beides sind nur
Sprünge). Die Anzahl der Vergleiche (der eigentlich rechenintensivste
Vorgang) ist bei beiden Lösungen gleich.
Einspruch!

Bei einem Else weis ich genau, dass wenn die erste Bedingung zutrifft,
die zweite nicht mehr ausgeführt wird... In Deinem Beispiel muss ich den
Quellcode dazwischen auch noch interpretieren um zum selben Schluss zu
kommen.

In all meinem Code ist bisher noch nie ein Continue benutzt worden. Und
ich will es auch nie benutzen.
Post by Michael Landenberger
Post by Marian Aldenhövel
Post by Michael Landenberger
for I := 0 to Liste.Count - 1 do
if TComponent (Liste [I]).Tag = GesuchterWert then begin
Result := Liste [I];
Exit
end;
Result:=NIL;
i:=0;
while (Result=NIL) and (i<Liste.Count) do
if Bedingung
then Result:=Liste[i]
else inc(i);
Also für Dein Beispiel: Abgelehnt.
for-Schleifen sollen schneller sein als while-Schleifen, habe ich mir
mal sagen lassen.
Spielen in deinem Code wirklich Mikrosekunden eine Rolle? Falls Nein,
dann mach es mit While... Falls Ja: Man kann die Optimierte For-Schleife
auch nachbauen. Der Einzige vorteil dieser ist, dass die Schleife in
jedem Fall auf 0 läuft und dann ein Branch If Zero ausgeführt wird. Ein
Compare muss nicht mehr durchgeführt werden. Aber dafür vielleicht noch
ein Inkrementator dazu parallel geführt werden. Soviel langsamer ist
eine optimierte For-Schleife zu einer nicht optimierten auch nicht...
Post by Michael Landenberger
Post by Marian Aldenhövel
Ein komplexeres Beispiel könnte allenfalls ein break verdienen, dann
eben die Defaultzuweisung NIL am Anfang.
Dieser Vorschlag kam auch schon von anderen Schreibern. Mir stellt sich
allerdings die Frage: warum eigentlich? Die Funktion kann auch bei
meiner Lösung nicht mit undefiniertem Result verlassen werden.
In Deinem Beispiel, wenn kein Fehler auftritt, stimmt die Aussage. Aber
meistens sind die realen Codes nicht auf 5 Zeilen reduziert... Da kann
es dann schnell mal passieren, dass result eben einen undefinierten
Zustand behalten kann. Der Compiler warnt dann wenigstens...
Post by Michael Landenberger
Post by Marian Aldenhövel
Exits sind so endgültig. In einer langen Methode kann man bei
Änderungen hinten was anhängen und wenn dann in der Mitte ein Exit
die Ausführung dieser Änderung in zwei Promille der Fälle verhindert
gibt das Tränen.
Das gilt aber auch für if...then. Wenn deine if-Bedingung 500 Zeilen
weiter oben im Code steht, weißt du manchmal auch nicht mehr, warum der
neu hinzugefügte Code nicht ausgeführt wird.
Exit ist das einzige dieser Befehle die ich auch brauche, aber nur an
Prozeduranfängen. Wenn festgestellt wird, dass Grundvoraussetzungen für
die Prozedurausführungen nicht gegeben sind, folgt ein Exit. Z.B:

procedure Berechnen;
begin
if not FInitialized then
exit;

... ganz viel Code
end;

Aber Exit in mitten von viel Code? Niemals!

cu
Mario
Stefan M. Huber
2007-03-05 11:18:13 UTC
Permalink
On Mon, 05 Mar 2007 12:02:45 +0100, Mario Rothacher
Post by Mario Rothacher
In all meinem Code ist bisher noch nie ein Continue benutzt worden. Und
ich will es auch nie benutzen.
Ich verwende EXIT, CONTINUE und BREAK (großgeschrieben) schon, aber immer
nur am Anfang eines Blockes:

procedure TuWas(Par: integer);
begin
// Hier stehen so gut wie nie Bedingungen mit OR, AND.
// Zumindest nicht, wenn sie semantisch nicht zusammengehören.
// Ich würde niemals mehr folgende beiden OR-verknüpfen,
// weil sie inhaltlich nicht zusammenpassen.

if not Assigned(dings) then EXIT;
if Par < 0 then EXIT;
// [...]
end;

oder bei Schleifen, wenn sie so aussehen:

for i := 0 to Length(dings) - 1 do
begin
if not dings[i].aktiv then CONTINUE;
// [...] Hier vielleicht viel Code, aber sehr unwahrscheinlich,
// dass darin noch ein EXIT, CONTINUE, ... vorkommt.
end

Stefan
--
He is spending a year dead for tax reasons.
--- Douglas Adams about Hotblack Desiato
"The Restaurant at the End of the Universe"
Arno Garrels
2007-03-05 11:51:16 UTC
Permalink
Post by Michael Landenberger
Post by Marian Aldenhövel
Ein komplexeres Beispiel könnte allenfalls ein break verdienen, dann
eben die Defaultzuweisung NIL am Anfang.
Dieser Vorschlag kam auch schon von anderen Schreibern. Mir stellt
sich allerdings die Frage: warum eigentlich? Die Funktion kann auch
bei meiner Lösung nicht mit undefiniertem Result verlassen werden.
Sehe ich auch so, in SysUtils wird's ebenfalls so gemacht.

Arno Garrels
Joe Galinke
2007-03-05 12:11:01 UTC
Permalink
Hallo Michael,
Post by Michael Landenberger
Das gilt aber auch für if...then. Wenn deine if-Bedingung 500 Zeilen weiter
oben im Code steht, weißt du manchmal auch nicht mehr, warum der neu
hinzugefügte Code nicht ausgeführt wird.
Bei if...then habe ich aber eine Einrückung. Die macht deutlich, dass ich
mich in einem separaten Block befinde. 500 Zeilen werde ich bestimmt nicht
nach oben wandern müssen um die Bedingungsprüfung zu lesen. Wenn es mal zu
viele Zeilen für meinen Geschmack werden sollten, was bei mir schon _weit_
unter 500 der Fall ist, so gehört dieser Teil ausgelagert. Ich
berücksichtige jetzt mal nicht evtl. notwendige Optimierungen. Der Zwang
dazu mag manche Unschönheit rechtfertigen

Ansonsten halte ich es ähnlich wie Mario. Das "Exit" zum frühen Ausstieg
aus einer Prozedur erlaube ich mir schon, wenn auch nicht immer mit gutem
Gewissen. :-)

Die "anderen" habe ich bisher noch nicht verwendet und auch nicht vermisst.
Nein, ich halte meinen Code nicht für schlechter lesbar.


Gruß, Joe
--
Arno Garrels
2007-03-05 11:46:07 UTC
Permalink
Post by Marian Aldenhövel
Exits sind so endgültig. In einer langen Methode kann man bei
Änderungen
hinten was anhängen und wenn dann in der Mitte ein Exit die
Ausführung dieser
Änderung in zwei Promille der Fälle verhindert gibt das Tränen.
Das ist wirklich Geschmacksache. Exits, Breaks und Continues ersparen
oft eine begin/end Klammer, was wie ich finde zur besseren Lesbarkeit
beträgt.

Arno Garrels
Soeren Muehlbauer
2007-03-05 12:46:37 UTC
Permalink
Hi,
Post by Marian Aldenhövel
Post by Michael Landenberger
for I := 0 to Liste.Count - 1 do
if TComponent (Liste [I]).Tag = GesuchterWert then begin
Result := Liste [I];
Exit
end;
Result:=NIL;
i:=0;
while (Result=NIL) and (i<Liste.Count) do
if Bedingung
then Result:=Liste[i]
else inc(i);
Also für Dein Beispiel: Abgelehnt.
Gegen die while-Variante spricht, daß das Inkrementieren explizit erfolgt. Es kann leicht vergessen werden. Der Compiler beschwert sich auch nicht. Nur der Kunde wird sich beschweren, daß das Programm so unendlich lange
braucht:). Ich bin daher, wenn etwas aufgezählt werden soll, für ein for. Schade das die Sprache nicht mehrere Abbruchkriterien wie das for in c kennt.

Ich finde daher das Enumeratorprinzip nicht schlecht.
also in etwa so

Enum := Liste.GetEnumerator;

while (Result = nil) and Enum.MoveNext do
begin
Curr := TComponent(Enum.GetCurrent);
if Curr.Tag = GesuchterWert
then Result := Curr;
end;

Hier gibt es nämlich weder einen Zähler (i) noch das Problem eines vergessenen Inkrements.

Bye, Sören
Mario Rothacher
2007-03-05 13:56:43 UTC
Permalink
Post by Soeren Muehlbauer
Gegen die while-Variante spricht, daß das Inkrementieren explizit
erfolgt. Es kann leicht vergessen werden. Der Compiler beschwert sich
auch nicht. Nur der Kunde wird sich beschweren, daß das Programm so
unendlich lange braucht:).
Also bei mir kriegt der Kunde eigentlich nie ein Exe direkt nach einem
Compile.

So ein bischen Testen gehört dazu. Und eine solche Endlosschleife
entdeckt man dabei selber früh genug, bevor es beim Kunden ist.

Zum Rest hab ich nix zu meckern ;-)

cu
Mario
Soeren Muehlbauer
2007-03-05 14:02:56 UTC
Permalink
Hi,
Post by Mario Rothacher
So ein bischen Testen gehört dazu. Und eine solche Endlosschleife
entdeckt man dabei selber früh genug, bevor es beim Kunden ist.
Sehe ich ebenso. Aber bei einem einigermaßen großen Projekt kann man nicht wirklich alles testen. Und wenn man schon beim Entwickeln Fehlerquellen ausschließen kann, umso besser.


Bye, Sören
Thomas G. Liesner
2007-03-06 16:21:47 UTC
Permalink
Post by Mario Rothacher
Post by Soeren Muehlbauer
Gegen die while-Variante spricht, daß das Inkrementieren explizit
erfolgt. Es kann leicht vergessen werden. Der Compiler beschwert sich
auch nicht. Nur der Kunde wird sich beschweren, daß das Programm so
unendlich lange braucht:).
Also bei mir kriegt der Kunde eigentlich nie ein Exe direkt nach einem
Compile.
So ein bischen Testen gehört dazu. Und eine solche Endlosschleife
entdeckt man dabei selber früh genug, bevor es beim Kunden ist.
Nicht unbedingt. Fall aus der Praxis: Tests laufen, beim Kunden hängt
es. Ursache: Next beim Tabellendurchgehen vergessen, bei eigenen
Testdaten triggerte der erste Datensatz schon die Abbruchbedingung, beim
Kunden leider nicht.

So long,
Thomas G. Liesner
--
Neue Hamster-stable 2.1.0.11 seit 28.03.2006
http://www.tglsoft.de (Unterpunkt Freeware)
Thomas G. Liesner
2007-03-06 16:19:26 UTC
Permalink
Post by Soeren Muehlbauer
Gegen die while-Variante spricht, daß das Inkrementieren explizit
erfolgt. Es kann leicht vergessen werden. Der Compiler beschwert
sich auch nicht. Nur der Kunde wird sich beschweren, daß das
Programm so unendlich lange braucht:). Ich bin daher, wenn etwas
aufgezählt werden soll, für ein for. Schade das die Sprache nicht
mehrere Abbruchkriterien wie das for in c kennt.
Es gibt in C & Co keine For-Schleife a la Basic/Pascal, sondern nur eine
falsch benannte While-Schleife, welche mittels explizit aufgeführtem
Iterator auch die Nachbildung einer echten For-Schleife erlaubt.
Post by Soeren Muehlbauer
Ich finde daher das Enumeratorprinzip nicht schlecht.
also in etwa so
Enum := Liste.GetEnumerator;
while (Result = nil) and Enum.MoveNext do
begin
Curr := TComponent(Enum.GetCurrent);
if Curr.Tag = GesuchterWert
then Result := Curr;
end;
Hier gibt es nämlich weder einen Zähler (i) noch das Problem eines vergessenen Inkrements.
Und wenn man doch den Index braucht, muss man auf den Iterator
verzichten.

So long,
Thomas G. Liesner
--
Neue Hamster-stable 2.1.0.11 seit 28.03.2006
http://www.tglsoft.de (Unterpunkt Freeware)
Soeren Muehlbauer
2007-03-06 18:19:12 UTC
Permalink
Hi,
Post by Thomas G. Liesner
Es gibt in C & Co keine For-Schleife a la Basic/Pascal, sondern nur
eine falsch benannte While-Schleife, welche mittels explizit
aufgeführtem Iterator auch die Nachbildung einer echten For-Schleife
erlaubt.
Ich sehe da keinen großen Unterschied. Das for im Pascal ist doch auch
nur ein while.
Post by Thomas G. Liesner
Und wenn man doch den Index braucht, muss man auf den Iterator
verzichten.
Diesen Fall habe ich extrem selten. In meinen Datenstrukturen verwende
ich nur noch selten Zugriffe über Count und Items oder sowas. Möchte
ich ein Element löschen teile ich dies der übergeordneten Instanz mit.
So ist es später problemlos möglich das innere zu ändern. Das
verringert ganz extrem die Kopplung zwischen den Objekten.

Bye, Sören
Thomas G. Liesner
2007-03-06 19:09:29 UTC
Permalink
Post by Soeren Muehlbauer
Post by Thomas G. Liesner
Es gibt in C & Co keine For-Schleife a la Basic/Pascal, sondern nur
eine falsch benannte While-Schleife, welche mittels explizit
aufgeführtem Iterator auch die Nachbildung einer echten For-Schleife
erlaubt.
Ich sehe da keinen großen Unterschied. Das for im Pascal ist doch auch
nur ein while.
Ein spezielles.

C-For: for (Init-Anweisung(en); While-Bedingung; Schleifenend-Anweisung(en)) Body;

In Delphi:

Init-Anweisunge(en);
While While-Bedingung do begin
Body;
Schleifenend-Anweisung(en);
end;

Dass man das C-For auch als For benutzen kann, ist logisch, da die
Konstruktion unglaublich allgemein gehalten ist, aber mit einem
klassischen For iSv Anfangswert, Endwert, (Schrittweite) hat das
schlicht nichts zu tun. In C ist die eigentliche While-Schleife im
Prinzip auf Fälle beschränkt, wo die For-Variante nur noch die Bedingung
beinhaltet, wenn man auf kompakten Code Wert legt.
Post by Soeren Muehlbauer
Post by Thomas G. Liesner
Und wenn man doch den Index braucht, muss man auf den Iterator
verzichten.
Diesen Fall habe ich extrem selten. In meinen Datenstrukturen verwende
ich nur noch selten Zugriffe über Count und Items oder sowas. Möchte
ich ein Element löschen teile ich dies der übergeordneten Instanz mit.
So ist es später problemlos möglich das innere zu ändern. Das
verringert ganz extrem die Kopplung zwischen den Objekten.
Delete & Co delegiere ich auch an die Liste der Elemente, innerhalb der
Listenfunktionen ist Count dann natürlich in regem Gebrauch.

Mit freundlichen Grüßen,
Thomas G. Liesner
--
Neue Hamster-stable 2.1.0.11 seit 28.03.2006
http://www.tglsoft.de (Unterpunkt Freeware)
Hans-Peter Diettrich
2007-03-06 19:52:51 UTC
Permalink
Post by Soeren Muehlbauer
Ich sehe da keinen großen Unterschied. Das for im Pascal ist doch auch
nur ein while.
Nicht wenn man die Optimierungsmöglichkeiten betrachtet!

DoDi
Michael Landenberger
2007-03-06 20:37:46 UTC
Permalink
Das for im Pascal ist doch auch nur ein while.
Mit dem ganz großen Unterschied, dass der Endwert bei for nur einmal
berechnet wird (falls es sich dabei um einen Ausdruck handelt), bei while
jedoch bei jedem Schleifendurchlauf. Ich verwende while daher vorwiegend
dann, wenn sich während der Abarbeitung der Schleife der Endwert ändert, so
wie in folgendem Beispiel:

var

Liste : TStringList;
I : Integer;

begin
I := 0;
while I < Liste.Count do
if Liste [I] = 'abc' then
Liste.Delete (I) //hier ändert sich Liste.Count
else
Inc (I)
end;

Gruß

Michael
Thomas G. Liesner
2007-03-06 21:06:17 UTC
Permalink
Post by Michael Landenberger
Das for im Pascal ist doch auch nur ein while.
Mit dem ganz großen Unterschied, dass der Endwert bei for nur einmal
berechnet wird (falls es sich dabei um einen Ausdruck handelt), bei while
jedoch bei jedem Schleifendurchlauf. Ich verwende while daher vorwiegend
dann, wenn sich während der Abarbeitung der Schleife der Endwert ändert, so
var
Liste : TStringList;
I : Integer;
begin
I := 0;
while I < Liste.Count do
if Liste [I] = 'abc' then
Liste.Delete (I) //hier ändert sich Liste.Count
else
Inc (I)
end;
Meine Standardvariante für sowas:

var
Liste : TStringList;
I : Integer;
begin
For i := Liste.Count-1 downto 0 do begin
if Liste [I] = 'abc' then Liste.Delete (I)
end;
end;

Kürzer und kein fehlerhaftes Incrementieren möglich.

So long,
Thomas G. Liesner
--
Neue Hamster-stable 2.1.0.11 seit 28.03.2006
http://www.tglsoft.de (Unterpunkt Freeware)
Hans-Peter Diettrich
2007-03-06 17:54:30 UTC
Permalink
Post by Thomas G. Liesner
Post by Soeren Muehlbauer
Ich finde daher das Enumeratorprinzip nicht schlecht.
also in etwa so
Enum := Liste.GetEnumerator;
while (Result = nil) and Enum.MoveNext do
begin
Curr := TComponent(Enum.GetCurrent);
if Curr.Tag = GesuchterWert
then Result := Curr;
end;
Hier gibt es nämlich weder einen Zähler (i) noch das Problem eines vergessenen Inkrements.
Und wenn man doch den Index braucht, muss man auf den Iterator
verzichten.
Wie man an obigem Beispiel sieht, braucht man garkeinen Index, sondern
kann direkt auf den aktuellen Datensatz zugreifen, egal ob in oder auch
nach der Schleife.

DoDi
Thomas G. Liesner
2007-03-06 21:02:22 UTC
Permalink
Post by Hans-Peter Diettrich
Wie man an obigem Beispiel sieht, braucht man garkeinen Index, sondern
kann direkt auf den aktuellen Datensatz zugreifen, egal ob in oder auch
nach der Schleife.
Das ist klar. Wenn man allerdings die Position innerhalb der Liste aus
welchen Gründen auch immer benötigt, ist das über einen Iterator nicht
machbar.

So long,
Thomas G. Liesner
--
Neue Hamster-stable 2.1.0.11 seit 28.03.2006
http://www.tglsoft.de (Unterpunkt Freeware)
Hans-Peter Diettrich
2007-03-06 22:56:13 UTC
Permalink
Post by Thomas G. Liesner
Post by Hans-Peter Diettrich
Wie man an obigem Beispiel sieht, braucht man garkeinen Index, sondern
kann direkt auf den aktuellen Datensatz zugreifen, egal ob in oder auch
nach der Schleife.
Das ist klar. Wenn man allerdings die Position innerhalb der Liste aus
welchen Gründen auch immer benötigt, ist das über einen Iterator nicht
machbar.
Kommt auf den Iterator an - C++ ist da auch nicht gerade ein Ausbund an
Flexibilität ;-)

Bei Datenbanken und anderen Konstrukten, in denen die Ermittlung einer
Recordnummer oder Anzahl zeitaufwendig ist, oder von äußeren Einflüssen
(Multiuser-Datenbank...) abhängen kann, sind Indizes völlig unbrauchbar.
Das sieht man dann aber schon an der Aufgabenstellung, und muß sich eben
entsprechend einrichten.

Ich habe gerade so ein Problem (gelöst), was z.B. mit Bookmarks
passieren soll, wenn in einer Datei Zeilen eingefügt oder gelöscht
werden. Aber vielleicht hat ja jemand eine Idee, wie sich das auch ohne
eine Korrektur der Zeilennummern bewerkstelligen läßt? (Mir dämmert
gerade was...)

DoDi
Soeren Muehlbauer
2007-03-05 13:26:30 UTC
Permalink
Hi,
Post by Michael Landenberger
var
StringListe : TStringList;
while Zaehler < MaxWert do begin
if StringListe [Zaehler] = 'abc' then begin
MachIrgendwas;
Continue
end;
if StringListe [Zaehler] = 'def' then begin
MachIrgendwasAnderes;
Continue
end;
(...)
Inc (Zaehler)
end;
Ich mache in solchen Fällen eine Tabelle, welche den Stringwert auf einen ordinalen Wert mappt. Danach kann man schön mit case auswerten:

[...]

implementation


const
cabc = 1;
cdef = 2;
StringMap: array[0..1] of record
sVal: String;
iVal: Integer;
end = (
(sVal: 'abc'; iVal: cabc),
(sVal: 'def'; iVal: cdef)
);

function Find(const S: String; out iVal: Integer): Boolean;
var
I: Integer;
begin
Result := False;
for I := 0 to Length(StringMap) - 1 do
if StringMap[I].sVal = S
then begin
iVal := StringMap[I].iVal;
Result := True;
end;
end;

[...]
if Find(StringListe[Zaehler], Val)
then begin
case Val of
cabc: MachIrgendwas;
cdef: MachIrgendwasAnderes;
end;
end;

Bye, Sören
Hans-Peter Diettrich
2007-03-06 02:06:05 UTC
Permalink
Post by Soeren Muehlbauer
Ich mache in solchen Fällen eine Tabelle, welche den Stringwert auf
Warum nicht mit TStringList? Die kann bei eingeschalteter Sortierung
sogar binär suchen - man muß dann nur auf die richtige Numerierung der
Konstanten achten.

DoDi
Soeren Muehlbauer
2007-03-06 06:10:53 UTC
Permalink
Hi,
Post by Hans-Peter Diettrich
Post by Soeren Muehlbauer
Ich mache in solchen Fällen eine Tabelle, welche den Stringwert auf
Warum nicht mit TStringList? Die kann bei eingeschalteter Sortierung
sogar binär suchen - man muß dann nur auf die richtige Numerierung der
Konstanten achten.
Das geht auch. Kommt halt drauf an, um wieviele Einträge es sich handelt und ob es eine bestimmte Anzahl ist. Eigentlich ist das ein typischer Fall für eine Map. Zu jedem String wird ein Ordinalwert zugeordnet. Mir ging
es nur darum zu zeigen, wie man viele geschachtelte if then else umgehen kann.

Bye, Sören
Matthias Frey
2007-03-06 07:13:46 UTC
Permalink
Post by Soeren Muehlbauer
Hi,
Hi
Post by Soeren Muehlbauer
Ich mache in solchen Fällen eine Tabelle, welche den Stringwert auf
Nette Idee - dauert aber länger. Bei mir habe ich oft, den Fall, das
die Strings recht unterschiedlich in den Wahrscheinlichkeiten sind.


Grüße
Matthias
Hans-Peter Diettrich
2007-03-06 17:57:06 UTC
Permalink
Post by Matthias Frey
Post by Soeren Muehlbauer
Ich mache in solchen Fällen eine Tabelle, welche den Stringwert auf
Nette Idee - dauert aber länger. Bei mir habe ich oft, den Fall, das
die Strings recht unterschiedlich in den Wahrscheinlichkeiten sind.
Das ändert aber nichts daran, daß eine Stringsuche O(log n) sein kann,
während eine sequentielle Abfrage immer O(n) ist.

DoDi
Thomas G. Liesner
2007-03-06 16:23:51 UTC
Permalink
Post by Soeren Muehlbauer
function Find(const S: String; out iVal: Integer): Boolean;
var
I: Integer;
begin
Result := False;
for I := 0 to Length(StringMap) - 1 do
if StringMap[I].sVal = S
then begin
iVal := StringMap[I].iVal;
Result := True;
Exit
Post by Soeren Muehlbauer
end;
end;
IndexOf von TStringlist und Wert in Objects gesteckt ist bei vielen
Werten noch deutlich performanter.

So long,
Thomas G. Liesner
--
Neue Hamster-stable 2.1.0.11 seit 28.03.2006
http://www.tglsoft.de (Unterpunkt Freeware)
Soeren Muehlbauer
2007-03-06 18:24:07 UTC
Permalink
Hi,

[..]
Post by Thomas G. Liesner
Exit
[..]

:-) Das habe ich doch tatsächlich vergessen.
Post by Thomas G. Liesner
IndexOf von TStringlist und Wert in Objects gesteckt ist bei vielen
Werten noch deutlich performanter.
Sicher. Ich habe bei soetwas immer etwas Bauchweh, da das gut
dokumentiert sein will. Weiterhin vagabundieren diese StringListen
herum. Wie ich schon schrieb, kommt es meiner Meinung nach auf den
Umfang des ganzen an. Bei feststehender Anzahl würde ich immer den
Tabellenansatz vorziehen. Aber so hat wahrscheinlich jeder seine
eigenen Vorlieben.

Bye, Sören
Ralf Mimoun
2007-03-06 18:19:00 UTC
Permalink
Moin!
Post by Michael Landenberger
Hallo,
ich habe mir ja schon lange die GoTos abgewöhnt ;-) aber Break,
Continue und Exit setze ich immer noch gerne ein. Beispielsweise
Egal was man baut: die Dinger sind böse. Man ist wieder bei geschminkten
Gotos, man übersieht sehr schnell was usw. Aber sehr selten setze ich sie
doch ein: wenn die Routine unbedingt so schnell wie möglich sein muß, und
wenn ein Exit o.ä. dabei einen meßbaren Vorteil bringt. Entsprechend
dokumentiert natürlich.

All diese Befehle sorgen dafür, daß der Sourcecode nicht mehr
strunzlangweilig sind. Aber genau das und nichts anderes soll er sein.

Bye, Ralf
Rolf Eike Beer
2007-03-06 21:47:47 UTC
Permalink
Post by Michael Landenberger
ich habe mir ja schon lange die GoTos abgewöhnt ;-) aber Break, Continue
und Exit setze ich immer noch gerne ein. Beispielsweise wähle ich manchmal
Je nachdem was du tust sparen gotos einen Haufen doppelter Instruktionen bei
der Fehlerbehandlung. Hilfreich ist das vor allem dann wenn man eine
längere Initialisierungssequenz hat und bei Fehlern alles sauber aufräumen
will.

Ich habe das auch immer für häßlich empfungen. Irgendwann habe ich dann
angefangen Kernel zu programmieren und seitdem ist mir das in Fleisch und
Blut übergegangen. Man bekommt dann die Reihenfolge einfacher hin und
vergisst seltener einen Fall.

Eike
Hans-Peter Diettrich
2007-03-09 13:05:18 UTC
Permalink
Post by Rolf Eike Beer
Je nachdem was du tust sparen gotos einen Haufen doppelter Instruktionen bei
der Fehlerbehandlung. Hilfreich ist das vor allem dann wenn man eine
längere Initialisierungssequenz hat und bei Fehlern alles sauber aufräumen
will.
Das entspricht etwa dem Automaten-Modell. Wenn ein Fehler auftritt,
wechselt der Automat in einen anderen Zustand, der genau den Namen des
zugehörigen Labels hat. In diesem Programmier-Modell ist gegen GoTo
nicht viel einzuwenden, die Programmstruktur ist dann eben von Haus aus
unstrukturiert. Man kann aber beides bis zu einem gewissen Grad unter
einen Hut bekommen, wenn man den Automaten als Schleife um ein Case
herum implementiert. Womit wir wieder bei den maskierten GoTos wären:
state := NewState; continue;
Post by Rolf Eike Beer
Ich habe das auch immer für häßlich empfungen. Irgendwann habe ich dann
angefangen Kernel zu programmieren und seitdem ist mir das in Fleisch und
Blut übergegangen. Man bekommt dann die Reihenfolge einfacher hin und
vergisst seltener einen Fall.
Mir ist diese Technik durchaus vertraut, seltsamerweise habe ich aber in
meinen Delphi-Programmen kaum jemals eine Chance gesehen, solchen Code
tatsächlich vorteilhaft einzusetzen. Ich würde sie daher eher unter die
höheren Weihen der Programmier-Kunst einsortieren (quod licet Iovi, non
licet bovi ;-)

DoDi

Loading...