#1 12.07.2011 15:01:46

DerPeer
GodlikeMember
Ort: Berlin
Registriert: 04.02.2005
Beiträge: 1291

Guter Programmierstil

Was bei mir abundzu mal vorkommt, ist sowas: Eine Funktion/Prozedur (A) innerhalb einer Funktion/Prozedur (B). Da die erstere NUR innerhalb der zweiten aufgerufen wird, pack ich sie halt in die zweite mit rein. Soweit so gut.

Jetzt gibt es einige lokale Variablen in B, auf die ich lesend und schreibend mit A zugreifen möchte. Allerdings ist es mir zu blöd, die an A zu übergeben, denn A kann sowieso "global" drauf zugreifen. Meint ihr, das kann man so machen? Oder ist das hässlich?

Beispiel:

Code: delphi

procedure prozedurb;
var x,y,z: single;
    i: integer;

  procedure prozedura;
  begin
    x:=...
    y:=...
    z:=...
  end;

begin
  for i:=1 to 10 do begin
    x:=globalesfeld[i];
    prozedura;
    anderesglobalesfeld[i]:=x+y+z;
  end;
end;


Achja, und wenn wir schon dabei sind:
Wenn ihr ein Array of book_typ habt - nennt ihr dieses Array dann book oder books?

Ach mensch, da fällt mir grad noch was ein:
Nehmen wir an, ich lasse sehr oft eine bestimmte Berechnung durchführen. Dieser Berechnung stehen aber sehr viele Bedingungen im Weg, die ich jedesmal abprüfen muss.
Dadurch erhalte ich oft so nen schönen Rattenschwanz:

Code: delphi

if bed1 then begin
  if bed2 then begin
    if bed3 then begin
      if bed4 then begin 
        berechnung;
      end;
    end;
  end;
end;


Gibts das auch hübscher?

DerPeer

Beitrag geändert von DerPeer (12.07.2011 15:03:49)

Offline

 

#2 12.07.2011 15:12:49

Gnietschow
ProMember
Ort: Berlin
Registriert: 20.06.2007
Beiträge: 237

Re: Guter Programmierstil

Beim ersten würd ich sagen, es ist besser nicht auf den quasi globalen Variablen zu arbeiten, sondern mit Parametern. Ich habe mir durch solche direkten Zugriffe, schon häufiger viele Bugs erzeugt und Fehlersuche einfach viel länger als Fehlerprevention. Ich schreib daher meist die Procedure vorher darüber, wenn das kompilierbar ist, kopiere ich sie zum strukturieren hinein. Aber ist denke ich mal Geschmackssache smile

Zitat:

Wenn ihr ein Array of book_typ habt - nennt ihr dieses Array dann book oder books?

Bücher wink (ich nehm immer den Plural)

Statt

Code: delphi

if bed1 then begin
  if bed2 then begin
    if bed3 then begin
      if bed4 then begin 
        berechnung;
      end;
    end;
  end;
end;

mach ich meist (Zeilentrennung der ands für die Übersichtlichkeit)

Code: delphi

if bed1 and
   bed2 and
   bed3 and
   bed4 then
begin
  berechnung;
end;

Wenns die Bedingungen und Berechnung kurz sind auch

Code: delphi

if bed1 and bed2 and bed3 and bed4 then berechnung;

Es gibt 10 Gruppen von Menschen - die die das Binärsystem verstehen und die anderen.  :-)
Vegetarier essen meinem Essen das Essen weg ;)
-------------------------------------------------------------------------------------------------------------------
Der Community-Hub für Videospiele: gameloop.io

Offline

 

#3 12.07.2011 15:57:17

DerPeer
GodlikeMember
Ort: Berlin
Registriert: 04.02.2005
Beiträge: 1291

Re: Guter Programmierstil

Bei mir sind die Bedinungen (bed1, bed2, ...) oft sehr rechenaufwändig. Stelle dir z.B. ein Ausschlussverfahren beim Rendern vor. Soweit ich weiß, werden bei einem AND alle Teilterme ausgewertet.

Zu der ersten Sache stimme ich dir aber zu; das kann zu Bugs führen.

Und bei den Büchern: Ich finde, es ist gut zu lesen, wenn man sowas hat:
Buch[3].seitenAnzahl:=576;
anstatt
Bücher[3].seitenAnzahl:=576;

Aber egal :-)

DerPeer

Offline

 

#4 12.07.2011 19:14:55

Gnietschow
ProMember
Ort: Berlin
Registriert: 20.06.2007
Beiträge: 237

Re: Guter Programmierstil

Zitat:

Soweit ich weiß, werden bei einem AND alle Teilterme ausgewertet.

Nur wenn du es explizit im Compiler angeschalten hat. Standardmäßig gilt lazy Evaluation, also nur solange auswerten bis das Ergebnis feststeht (beim and ist bei einem false Schluss smile ).

Zitat:

Buch[3].seitenAnzahl:=576;

Stimmt, beim Zugriff auf das Array sieht es so schlüssiger aus. Über sowas hab ich mir noch nie viele Gedanken gemacht (meist heißt alles einfach temp1,temp2,usw. roll)


Es gibt 10 Gruppen von Menschen - die die das Binärsystem verstehen und die anderen.  :-)
Vegetarier essen meinem Essen das Essen weg ;)
-------------------------------------------------------------------------------------------------------------------
Der Community-Hub für Videospiele: gameloop.io

Offline

 

#5 12.07.2011 19:15:32

DragonFlyOfGold
ProMember
Ort: Berlin
Registriert: 09.11.2005
Beiträge: 139

Re: Guter Programmierstil

Ich stimme Gnietschow zu, schön deine Bedingungen verunden. Vergess dabei nicht, dass Ausdrücke die nicht boolsch sind geklammert werden müssen:

Code: delphi

if (x = 1) and
   true and
   (y = 5) and
   (i = x) then
begin
  berechnung;
end;


Zum Thema mit den Prozeduren:

Ich finde es äußerst gefährlich, wenn eine Prozedure Globale Werte verändert, ohne das sie als Parameter übergeben werden. Lesen finde ich gerade noch ok, aber nicht schön. Das Problem ist einfach, dass  es zwar für einfachen Code wie dein Beispiel vollkommen ok ist, aber sobald der Code etwas unübersichtlicher wird, kann es schnell passieren, dass man vergisst welche Seiteneffekte der Aufruf einer Prozedure mit sich bringen. Dann wundert man sich, warum Variablen etwas anderes beinhalten, als gedacht.
Daher mein Vorschlag. Nutze Funktionen oder Prozeduren mit Var-Parametern, um Werte zu ändern.
In deinem Fall wäre es dann:

Code: delphi

procedure prozedurb;
var x,y,z: single;
    i: integer;

  function funca:integer;
  begin
    result := ...
    result := result + ...
    result := result + ...
  end;

begin
  for i:=1 to 10 do begin
    x:=globalesfeld[i];
    anderesglobalesfeld[i]:=funca;
  end;
end;

Beitrag geändert von DragonFlyOfGold (12.07.2011 19:17:08)

Offline

 

#6 12.07.2011 21:43:26

Coolcat
ProGuru
Ort: Aachen, NRW
Registriert: 24.01.2005
Beiträge: 2780
Web-Seite

Re: Guter Programmierstil

Zitat:

Code:

if bed1 then begin
  if bed2 then begin
    if bed3 then begin
      if bed4 then begin 
        berechnung;
      end;
    end;
  end;
end;

Häufig hat man das Problem das etwa die Berechnung von bed2 von bed1 abhängt. In dem Fall kann man nicht beides in eine If-Bedingung packen. Es kommt immer auf die Situation an, aber um die Verschachtelung zu vermeiden kann man die Bedingung negieren und Sprunganweisungen benutzen, continue, break und return.

Code:

if not bed1 then return;
if not bed2 then return;
if not bed3 then return;
if not bed4 then return; 
berechnung;

Sinnvolleres Realworld-Beispiel:
http://martin-weusten.de/uni/informatik/progra/erweiterte-programmierkonventionen/ -> Abschnitt "Vermeiden von Verschachtelung"

Alternativ, wenn Sprunganweisungen nicht möglich sind:

Code:

if not bed1 then begin
    // fehlerbehandlung
end
else if not bed2 then begin
    // fehlerbehandlung
end
else if not bed3 then begin
    // fehlerbehandlung
end
else if not bed4 then begin
    // fehlerbehandlung
end
else begin
    berechnung;
end;

My software never has bugs. It just develops random features.

Offline

 

#7 13.07.2011 09:15:12

DerPeer
GodlikeMember
Ort: Berlin
Registriert: 04.02.2005
Beiträge: 1291

Re: Guter Programmierstil

Na gut, dann werd ich eben brav alles übergeben, und versuchen, nur auf lokalen Variablen zu arbeiten :-)

@Coolcat: Ja, sowas hab ich gemeint. Return beendet die Prozedur/Funktion, in der ich bin? Eigentlich interessant, dass sowas erlaubt ist, ein Goto aber verpöhnt ist :-)

DerPeer

Offline

 

#8 13.07.2011 11:06:18

DragonFlyOfGold
ProMember
Ort: Berlin
Registriert: 09.11.2005
Beiträge: 139

Re: Guter Programmierstil

In Delphi heißt es aber nicht return, sondern exit smile Man kann in Funktionen Exit auch das Ergbnis direkt als Parameter geben (z.B. Exit(true), seit Delphi 2009).

Offline

 

#9 13.07.2011 11:40:54

Lotipats
UltraMember
Registriert: 17.05.2005
Beiträge: 395

Re: Guter Programmierstil

Ich für meinen Teil verwende nie continue, break nur bei Case in Sprachen, bei denen es notwendig ist und ein return habe ich nur und ausschließlich genau einmal am Ende einer Funktion als aller letzte Anweisung, sofern dies in der Sprache notwendig ist.
Spagetti-Code habe ich als äußerst negativ und verpöhnt kennen gelernt, da fällt goto genauso rein, wie continue et cetera. Ich habe im Laufe der Zeit auch durch andere erfahren wieso, es ist ein pot. Herd von Fehler und ein debuggen ist dann äußerst unschön, vor allem, wenn die Funktion nicht von einem selber geschrieben wurde und er dann z.B. unerwarteter Weise nicht zu bestimmten Zeile kommt, bei der man "gehe bis Cursor"-debuggt; und all solche Spielchen.

In Folge dessen habe ich, falls notwendig, auch tiefe Bedingungs-Einschübe, irgendwann ist dann halt eine neue Funktion notwendig, nur in seltenen Fällen ist dies nicht möglich.

Variablen von Arrays haben bei mir i.d.R. die Mehrzahl als Bezeichnung. Hier bin ich allerdings nicht strikt und konsequent, sondern unentschlossen. Beides hat seine Vorteile. tongue

Offline

 

#10 13.07.2011 14:27:09

Coolcat
ProGuru
Ort: Aachen, NRW
Registriert: 24.01.2005
Beiträge: 2780
Web-Seite

Re: Guter Programmierstil

Zitat:

Spagetti-Code habe ich als äußerst negativ und verpöhnt kennen gelernt, da fällt goto genauso rein, wie continue et cetera.

break und continue und auch return/exit sind eigentlich nicht verpönt. Im Gegenteil, solcher Code kann unter Umständen wesentlich verständlicher sein. Dort ist ja klar definiert wohin gesprungen wird. Spagetti-Code ist es nur wenn man zuerst die Sprungmarke/Label suchen muss und dieses weit entfernt ist.

Beispiel:
Du hast eine Schleife und möchtest diese abbrechen. Ohne break würdest du ein Flag benötigen welches ständig in der Schleifenbedingung mit geprüft wird. Alternativ kannst du auch den Schleifenindex zu verändern das die Schleifenbedingung nicht mehr erfüllt ist. Bei einer Doppel- oder Dreifachschleife musst du das sogar für jede der Schleifen machen. Beim lesen von fremdem Quellcode braucht man relativ lange um zu realisieren wozu da jetzt ein Flag gesetzt oder der Schleifenindex gesetzt wird. So etwas könnte ja auch andere sinnvolle/gewollte Nebenwirkungen haben. Wenn da einfach break steht, weiß jeder SOFORT was gemeint ist und wo die Ausführung weiter geht. Auch einem goto bzw. einem break mit Label (je nach Sprache) weiß man recht schnell was passiert wenn das Label innerhalb von wenigen Zeilen zu finden ist. Will ich z.B. in C++ ein continue auf eine äußere Schleife einer Doppelschleife anwenden, setze ich ans Ende der entsprechenden Schleife eine Sprungmarke mit dem Namen CONTINUE_OUTER_LOOP und benutze an der gewünschten Stelle ein goto auf diese Marke. Da ist auch sehr schnell ersichtlich was passiert, kein Spagetti-Code....


My software never has bugs. It just develops random features.

Offline

 

#11 14.07.2011 10:24:29

Lotipats
UltraMember
Registriert: 17.05.2005
Beiträge: 395

Re: Guter Programmierstil

Finde ich nicht.

Offline

 

#12 14.07.2011 19:36:32

DerPeer
GodlikeMember
Ort: Berlin
Registriert: 04.02.2005
Beiträge: 1291

Re: Guter Programmierstil

Bisher habe ich immer, wenn ich aus einer Schleife herausspringen muss, keine For- sondern eben eine repeat- oder until-Schleife genommen. Ist aber bei ineinander verschachtelten, zählenden Schleifen sicher nicht so hübsch wie bei einer For-.

Offline

 

#13 15.07.2011 18:34:53

Coolcat
ProGuru
Ort: Aachen, NRW
Registriert: 24.01.2005
Beiträge: 2780
Web-Seite

Re: Guter Programmierstil

Zitat:

Finde ich nicht.

Ok. Ein RealWorld-Beispiel in C++. Sag mir wie du es ohne GOTO lösen würdest.

Code:

CGAL::Vertex_const edgeVerts[2];
CGAL::Polyhedron::Edge_const_iterator
    itrEdge = polyhedron.edges_begin(),
    endEdge = polyhedron.edges_end();
for ( ; itrEdge != endEdge; ++itrEdge) {
    edgeVerts[0] = itrEdge->vertex();
    edgeVerts[1] = itrEdge->opposite()->vertex();
    for (int i=0; i<2; ++i) {
        for (int j=0; j<3; ++j) {
            if (triangleVerts[j] == edgeVerts[i]) {
                goto CONTINUE_NEXT_EDGE;
            }
        }
    }

    if (edgeIntersectTriangle3D(triangle[0], triangle[1], triangle[2],
                                toVector3<double>(edgeVerts[0]->point()),
                                toVector3<double>(edgeVerts[1]->point()) ))
    {
        return false;
    }

    CONTINUE_NEXT_EDGE: ;
}
return true;

My software never has bugs. It just develops random features.

Offline

 

#14 15.07.2011 20:32:23

Lotipats
UltraMember
Registriert: 17.05.2005
Beiträge: 395

Re: Guter Programmierstil

Ich habe jetzt wirklich nur einmal deinen Code-Ausschnitt genommen und ihn konvertiert. Es ist halt die Frage, ob er bei mir überhaupt so zustande gekommen wäre. wink

Code:

//Var init
CGAL::Vertex_const edgeVerts[2];
CGAL::Polyhedron::Edge_const_iterator
    itrEdge = polyhedron.edges_begin(),
    endEdge = polyhedron.edges_end();
bool res = true;

for ( ; res && itrEdge != endEdge; ++itrEdge) {
    edgeVerts[0] = itrEdge->vertex();
    edgeVerts[1] = itrEdge->opposite()->vertex();
    for (int i=0; i<2; ++i) {
        for (int j=0; j<3; ++j) {
            if (triangleVerts[j] == edgeVerts[i]) {
                i=3;
                j=3;
            }
        }
    }

    if (i<3 && edgeIntersectTriangle3D(triangle[0], triangle[1], triangle[2],
                                toVector3<double>(edgeVerts[0]->point()),
                                toVector3<double>(edgeVerts[1]->point()) )){
        res = false;
    }
}

return res;

ich habe deinen Code mal hauptsächlich so gelassen. Aus historischen Gründen nehme ich nie eine for-Schleife, Demnach würde das bei mir sogar eher so aussehen:

Code:

//Var init
bool res = true;
int i;
int k;
CGAL::Vertex_const aaEdgeVerts[2];
CGAL::Polyhedron::Edge_const_iterator aItrEdge = polyhedron.edges_begin();
CGAL::Polyhedron::Edge_const_iterator aEndEdge = polyhedron.edges_end();

//Kommentar
while(res && aItrEdge != aEndEdge ){
  
  aaEdgeVerts[0] = aItrEdge ->vertex();
  aaEdgeVerts[1] = aItrEdge ->opposite()->vertex();
  
  //...
  i = 0;
  while(i<2){
    
    k=0;
    while(k<3){
      //falls ...
      if( triangleVerts[k] == aaEdgeVerts[i] ){
        //dann kann abgebrochen werden, da ...
        i=3;
        k=3;
      }
      
      k++;
    }
    
    i++;
  }
  
  //falls ...
  if( i<3 && edgeIntersectTriangle3D( triangle[0], triangle[1], triangle[2],
                                      toVector3<double>(aaEdgeVerts[0]->point()),
                                      toVector3<double>(aaEdgeVerts[1]->point())) ){
    //dann ... und damit auch die Ueberpruefung beendet werden
    res = false;
  }
  
  ++aItrEdge ;
}

return res;

PS: bei VS 2010 ist i++ genau das gleiche wie ++i, schon ohne Optimierung. wink
Bei aItrEdge  bin ich mir nicht sicher, deshalb habe ich es da so belassen. O:-)

EDIT: ich hatte es erst als cpp, mit Syntax-Highlighting, allerdings hat er da alles klein geschrieben. sad

Beitrag geändert von Lotipats (15.07.2011 20:34:57)

Offline

 

#15 15.07.2011 21:00:39

Coolcat
ProGuru
Ort: Aachen, NRW
Registriert: 24.01.2005
Beiträge: 2780
Web-Seite

Re: Guter Programmierstil

Zitat:

Bei aItrEdge  bin ich mir nicht sicher, deshalb habe ich es da so belassen. O:-)

CGAL hat das Post-Inkrement wahrscheinlich gar nicht implementiert, da stellt sich die Frage gar nicht wink


My software never has bugs. It just develops random features.

Offline

 

Brett Fußzeile

Powered by PunBB
© Copyright 2002–2005 Rickard Andersson