Globale Variablen unschön?

Für Fragen von Einsteigern und Programmieranfängern...
Antworten
NoCee
Beiträge: 174
Registriert: Do 3. Mär 2011, 21:34
OS, Lazarus, FPC: WinXp/7/10 Opensuse13.2/Leap15.3 (L 2.2.0 FPC 3.2.2 )
CPU-Target: Intel 32/64Bit, ARM9
Wohnort: Ulm

Globale Variablen unschön?

Beitrag von NoCee »

Hallo zusammen,
mal eine fast peinliche (fast)Anfängerfrage :oops:

Bei meiner Sucherei im Netz steht relaiv oft, daß man Variablen nicht global deklarieren sollte
Das sei angeblich unschöner Prorammierstiel. Zumindest lese ich das so relativ oft.

Bei Funktionen, die irgendwelche temporäre Zwischenspeicher benutzen, ist mir das auch klar.
Aber wenn ich jetzt ne Procedure schreibe, die in einem loop immer wieder aufgerufen wird und einen
alten Wert braucht (Altwert <> Neuwert dann mach was... und speichere dann Neuwert in Altwert) geht das doch nur so.
Ich mach das bisher mit der Variablenübergabe einer globalen Variablen an die Procedure oder direkt in der Procedure.
Diese wird aber nirgendwo sonst benutzt. Wäre also prädestiniert für eine lokale Variable.
Diese ist doch aber temporär so daß das ja nicht geht.

Macht man das, so wie ich, mit einer globalen Variablen, oder hab ich da ne Bildungslücke?

Gruß
NoCee

Benutzeravatar
m.fuchs
Lazarusforum e. V.
Beiträge: 2813
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: Globale Variablen unschön?

Beitrag von m.fuchs »

NoCee hat geschrieben:Bei meiner Sucherei im Netz steht relaiv oft, daß man Variablen nicht global deklarieren sollte
Das sei angeblich unschöner Prorammierstiel. Zumindest lese ich das so relativ oft.

Bei Funktionen, die irgendwelche temporäre Zwischenspeicher benutzen, ist mir das auch klar.
Aber wenn ich jetzt ne Procedure schreibe, die in einem loop immer wieder aufgerufen wird und einen
alten Wert braucht (Altwert <> Neuwert dann mach was... und speichere dann Neuwert in Altwert) geht das doch nur so.
Ja, globale Variablen sind unschön. Der exzessive Gebrauch führt zu einer verwirrenden Code-Suppe (für die du dann deinen Programmierstiel zum Umrühren nutzen kannst :wink: ) Aber ganz ohne geht es auch nicht. Eigentlich benötigt jedes Programm was komplexer als "Hello World" ist, mindestens eine globale Variable.

Solltest du beim Design deines Programms bei einundzwanzig globalen Variablen angekommen sein, solltest du aber dringend über eine Kapselung in eine Klasse nachdenken. Spätestens bei einundzwanzig! Ich würde das schon bei drei machen. :)
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de

Socke
Lazarusforum e. V.
Beiträge: 3178
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Globale Variablen unschön?

Beitrag von Socke »

NoCee hat geschrieben:Aber wenn ich jetzt ne Procedure schreibe, die in einem loop immer wieder aufgerufen wird und einen
alten Wert braucht (Altwert <> Neuwert dann mach was... und speichere dann Neuwert in Altwert) geht das doch nur so.
Ich mach das bisher mit der Variablenübergabe einer globalen Variablen an die Procedure oder direkt in der Procedure.
Diese wird aber nirgendwo sonst benutzt. Wäre also prädestiniert für eine lokale Variable.
Diese ist doch aber temporär so daß das ja nicht geht.
Das geht auch mit lokalen typisierten Konstanten.

Code: Alles auswählen

function CallMe(arg1, arg2: int): integer;
const tmp: int = 0; // Konstante mit Typangabe = "typisierte Konstante"
begin
  // beim 1. Durchlauf hat tmp den Wert 0
  Result := arg1 + arg2 + tmp;
  tmp := Result;
end;
 
Wenn die Variable zuerst initialisiert werden muss:

Code: Alles auswählen

procedure CallMeToo(arg1, arg2, init: Integer);
var
  tmp: integer;
  procedure CallMeSub(arg1, arg2);
  begin
    Result := arg1 + arg2 + tmp;
  end;
begin
  tmp := init;
  while true do
    CallMeSub(arg1, arg2);
end;
m.fuchs hat geschrieben:Aber ganz ohne geht es auch nicht. Eigentlich benötigt jedes Programm was komplexer als "Hello World" ist, mindestens eine globale Variable.
Wenn du dein Programm wie oben aufbaust, geht das wunderbar.

Es gibt aber auch gute Gründe für globale Variablen. Beispielsweise enthält die Variable Application aus der Unit Forms ein global gültiges Objekt, über das die gesamte Anwendung kontrolliert werden kann. Da man das nicht in jeder Funktion benötigt, lohnt sich nicht der Aufwand dieses als Parameter zu übergeben (Ausführungsgeschwindigkeit des Programms und Fehlermöglichkeit beim Coding).
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

Benutzeravatar
m.fuchs
Lazarusforum e. V.
Beiträge: 2813
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: Globale Variablen unschön?

Beitrag von m.fuchs »

Hm, deine typisiert Konstante verhält sich jetzt (abgesehen vom Sichtbarkeitsbereich) schon wie eine globale Variable. Da aber genau diese Sichtbarkeit ein häufiger Grund für Probleme mit globalen Variablen sind, sieht das nach einer guten Lösung aus. Einzig die Bezeichnung const stört mich. Da hätten die Borländer damals lieber etwas namens static einführen sollen.
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de

Eb
Lazarusforum e. V.
Beiträge: 240
Registriert: Di 5. Feb 2008, 15:32
OS, Lazarus, FPC: Linux Mint - Laz 2.2.0
CPU-Target: 64Bit
Wohnort: Stuttgart

Re: Globale Variablen unschön?

Beitrag von Eb »

m.fuchs hat geschrieben:Spätestens bei einundzwanzig! Ich würde das schon bei drei machen.
Ich muss gestehen, dass ich schon über einundzwanzig bin (und das nicht nur bei den globalen Variablen) ...

Und zwar deshalb weil ich es nicht hinbekomme, dass eine prozedur den Inhalt einer Variable beim nächsten Aufruf noch weiss und !
sie beim ersten Aufruf von außen initialisiert werden kann.
Dies sollte ja dein zweites Beispiel machen.
Socke hat geschrieben:Wenn die Variable zuerst initialisiert werden muss:

Code: Alles auswählen

  procedure CallMeToo(arg1, arg2, init: Integer);
    var
      tmp: integer;
      procedure CallMeSub(arg1, arg2);
      begin
        Result := arg1 + arg2 + tmp;
      end;
    begin
      tmp := init;
      while true do
        CallMeSub(arg1, arg2);
    end;
Das läuft aber irgendwie nicht ...

Könntest du das vielleicht noch lauffähig posten und kurz erklären wie es funktioniert?
Eine prozedur in einer prozedur ist für mich neu und 'while true' ist mir auch nicht verständlich.

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

Re: Globale Variablen unschön?

Beitrag von theo »

Das ist irgendwie Pseudocode, weiss auch nicht, warum Socke das so geschrieben hat.

Die innere Prozedure ist schon am richtigen Ort, aber sie muss den Regeln der normalen Deklarationen folgen.

Also bei den arg muss natürlich hinten auch der Typ stehen, und nur eine Funktion hat ein "Result".

"while true" bedeutet eine ewige Schleife. Wenn du mehr wissen willst, frag Socke, ich kapier auch nicht was das soll.

Socke
Lazarusforum e. V.
Beiträge: 3178
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Globale Variablen unschön?

Beitrag von Socke »

theo hat geschrieben:Das ist irgendwie Pseudocode, weiss auch nicht, warum Socke das so geschrieben hat.

Die innere Prozedure ist schon am richtigen Ort, aber sie muss den Regeln der normalen Deklarationen folgen.

Also bei den arg muss natürlich hinten auch der Typ stehen, und nur eine Funktion hat ein "Result".

"while true" bedeutet eine ewige Schleife. Wenn du mehr wissen willst, frag Socke, ich kapier auch nicht was das soll.
Ja, das ist nur ein Beispiel zur Demonstration der Syntax und soll kein (sinnvolles!) lauffähiges Programm darstellen. Bei lauffähigen Programmen würde doch jeder Lerneffekt verschwinden :oops:

Bei der inneren Funktion habe ich tatsächlich die Typangabe vergessen; Result ist sicherlich auch den Folgen der Uhrzeit zuzurechnen.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

Eb
Lazarusforum e. V.
Beiträge: 240
Registriert: Di 5. Feb 2008, 15:32
OS, Lazarus, FPC: Linux Mint - Laz 2.2.0
CPU-Target: 64Bit
Wohnort: Stuttgart

Re: Globale Variablen unschön?

Beitrag von Eb »

Hallo socke,

Ehrlich gesagt, wollte ich mich damit jetzt nicht intensiv beschäftigen - ich habe den Thread mitgelesen und dachte, dass hier einen Ansatz zu einer verbesserten Programmierlogik diskutiert wird, den ich gerne einsetzen würde.
An dem Codeschnipsel habe ich natürlich schon rumprobiert (Typdeklaration der Variablen und das ersetzen von procedure durch function...) bevor ich gepostet habe.
Da mir aber die dahinterstehende Logik nicht klar ist, konnte ich es nicht sinnvoll zum Laufen bringen ...

Wenn es dir also nicht ausmachen würde, den Grundgedanken zu erklären, könnte ich mich dann wieder mit dem Code befassen und eventuell auch noch einen positiven Lerneffekt erzielen.

Eb

Socke
Lazarusforum e. V.
Beiträge: 3178
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Globale Variablen unschön?

Beitrag von Socke »

Eb hat geschrieben:Wenn es dir also nicht ausmachen würde, den Grundgedanken zu erklären, könnte ich mich dann wieder mit dem Code befassen und eventuell auch noch einen positiven Lerneffekt erzielen.
Das Ziel ist es, Variablen dort zu deklarieren, wo sie benötigt werden. Sie sollen in anderen Programmteilen nicht sichbar sein.

Wenn sich eine Prozedur einen Wert aus der letzten Ausführung merken soll, kann man dazu lokale typisierte Konstanten verwenden. Typisierte Konstanten verhalten sich viel mehr wie Variablen, das heißt man kann ihnen zur Laufzeit neue Werte zuweisen. Der Wert bleibt über den Aufruf der Prozedur hinaus erhalten und kann später wieder abgefragt werden. Der Vorteil ist: die typisierte Konstante ist nur in dieser Prozedur sichtbar. Sie kann daher von außen nicht für andere Dinge misbraucht werden.

Ist eine Initialisierung erforderlich bietet sich die Schachtelung an. Die äußere Prozedur enthält die Variable, in der der Wert gemerkt wird. Befor der Prozedurrumpf (begin ... end) beginnt, deklariert man noch eine (die innere) Prozedur. Diese kann auf alle Variablen (und ggf. andere Prozeduren/Funktionen) der äußeren Prozedur zugreifen, die bereits deklariert wurden. Man kann nach der inneren Prozdur einen weiteren var-Block einleiten, dann aber nicht mehr von der inneren Prozedur auf die dort deklarierten Variablen zugreifen.

Einfacher zu lesen wäre, wenn man den zu merkenden Wert per Parameter übergibt. Dann muss sich die aufrufenden Prozedur um das zwischenspeichern des Wertes kümmern.

Code: Alles auswählen

procedure myproc(arg1, arg2: Integer; var arg3: Integer);
begin
  arg3 := arg1 + arg2; // Änderungen an arg3 sind dank var in der aufrufenden Prozedur sichtbar
end;
Solltest man zu dem Punkt kommen, dass eine Prozedur mehrere Werte zwischenspeichern muss, darf man ernsthaft an objektorientierung denken. Ein Kernkonzept dessen ist es, Daten und zugehörigen Programmcode zusammen zu halten.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

Eb
Lazarusforum e. V.
Beiträge: 240
Registriert: Di 5. Feb 2008, 15:32
OS, Lazarus, FPC: Linux Mint - Laz 2.2.0
CPU-Target: 64Bit
Wohnort: Stuttgart

Re: Globale Variablen unschön?

Beitrag von Eb »

Danke für die Erklärung.
Da es in meinem speziellen Fall um einige Variablen in geht, die gemerkt werden müssen, und da ich mehrere Prozeduren habe,
wird das wohl dann etwas unübersichtlich ...
Werde wohl langfristig um das Thema Objektorientierung nicht rum kommen ...
Eb

NoCee
Beiträge: 174
Registriert: Do 3. Mär 2011, 21:34
OS, Lazarus, FPC: WinXp/7/10 Opensuse13.2/Leap15.3 (L 2.2.0 FPC 3.2.2 )
CPU-Target: Intel 32/64Bit, ARM9
Wohnort: Ulm

Re: Globale Variablen unschön?

Beitrag von NoCee »

Hallo,

ich schließe mich dem Danke für die Erklärung an.

Veränderbare Konstanten , wäre ich nie drauf gekommen. Für mich waren bisher Konstanten einfach mal "konstant".

Dafür gibt es sogar einen Kompilerschalter
Emarcadero schreibt unter anderem dazu:
In den früheren Versionen von Delphi und Embarcadero Pascal konnten typisierte Konstanten immer geändert werden (wie im Status {$J+}). Deshalb muss älterer Quelltext, der änderbare typisierte Konstanten enthält, im Status {$J+} compiliert werden.
Gruß
NoCee

Socke
Lazarusforum e. V.
Beiträge: 3178
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Globale Variablen unschön?

Beitrag von Socke »

NoCee hat geschrieben:Veränderbare Konstanten , wäre ich nie drauf gekommen. Für mich waren bisher Konstanten einfach mal "konstant".

Dafür gibt es sogar einen Kompilerschalter
Emarcadero schreibt unter anderem dazu:[...]
Zu Zeiten von Turbo-Delphi hat Borland damals wohl keine (einfache) Möglichkeit gefunden, Variablen zu initialisieren. Daher sind die typisierten Konstanten entstanden.

In Free Pascal kann man dieses Verhalten auch umstellen. Im Gegensatz zu Delphi ist das immer noch Standard.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

Antworten