C++ Ein paar Fragen zu C++

Du probierst es aus, wie man alles ausprobiert: Indem du es machst und siehst, was passiert. Die durchgehende Unbeholfenheit, die du in diesem Thread an den Tag legst, solltest du wirklich ablegen. Jedes Studium, ob an einer Lehranstalt oder privat ist in erster Linie Selbststudium. Du musst Dinge MACHEN, damit du etwas lernst. Und wenn du dann Erfolg hast, bekommst du sogar Verständnis dafür, was du tust. Wenn du für jede Kleinigkeit fragst, lernst du überhaupt nichts und wirst bei der nächsten Kleinigkeit wieder völlig aufgeschmissen sein, denn das Verständnis fehlt, weil du dir selbst nie die Chance gegeben hast, es zu erlangen.
 
asdfman schrieb:
Naja, man könnte vielleicht. Aber wer tut es und zieht es dann noch streng durch? Die übliche Art, in C++ zu programmieren folgt nun einmal dem imperativen Paradigma. So wird es auch in jedem Buch gelehrt und ich finde es auch völlig ok so. Man sollte sich nicht krampfhaft verbiegen um einem bestimmten Paradigma zu folgen, wenn einem ein anderes einfacher gemacht wird, oder es einfach angebracht ist. Dann endet man genauso mit Scheuklappen und guckt nicht über den Tellerrand, wie derjenige, der nun jeden noch so kleinen Furz in eine Klasse kapseln muss und lieber 890349834 Zeilen mehr schreibt, als ein böses goto zu verwenden, oder hirnlos EINE GLOBALE VARIABLE! DAS CONSIDERE ICH HARMFULL zu schreien, ohne sich einen Gedanken zu machen, ob das nicht vielleicht doch sinnvoll sein könnte.

Sorry dass ich diesen uralten Thread hier wieder zum Leben erwecke, aber hierauf wollte ich eigentlich unbedingt noch eine Antwort geben ... hatte das bloß wieder vergessen.

Ein funktionaler Programmieransatz bringt, wie du ja sicherlich weißt, einige enorm angenehme Vorteile mit sich, die ich, obwohl du sie bestimmt zu genüge kennst, noch mal durchgehen möchte ... vor allem, weil ich glaube (nein, WEISS), dass diese genau so auch auf C++ übertragbar sind.

  • Die Kapselung von Code in kleine, nach außen abgeschlossene Funktionen mit klar definierten Aufgaben (eine Funktion, eine Aufgabe), die nur Übergabe-Argumente und lokale Variablen verwenden (und keine an Gott weiß wie vielen Stellen modifizierten globalen Variablen) und ihre Ergebnisse per return an den Aufrufer zurückgeben, macht es mir ungleich einfacher, über Code zu sinnieren und seinen Sinn und Effekt zu verstehen. Eine solche Funktion kann ich in Isolation vom Rest des Programms betrachten und kann mir so ein gutes Bild davon machen, was diese Funktion tut.
  • So geschriebener Code läßt sich auch wesentlich einfacher und natürlicher parallelisieren, da er gezielt "global state" vermeidet.
  • Funktional geschriebener Code fördert "code reuse", da kleine Funktionen mit den oben genannten Eigenschaften es durch ihre begrenzen Abhängigkeiten wesentlich einfach machen, häufig benötigte Aufgaben zu identifizieren und in gemeinsam genutzte Module / Libraries / etc. zu packen.

Und wenn du meinst, es sei unnatürlich, in C++ funktional zu programmieren, dann muß ich dich enttäuschen. Modernes C++ geht immer mehr in diese Richtung. Die C++ Standard Library bietet schon seit Jahren (anfangs zugegebenermaßen recht beschränkten) Support für funktionale Programmierung, der in C++11 weiter ausgebaut wurde (Gott sei Dank für Lambdas!!) und in Zukunft nur noch stärker forciert werden wird.

Sicherlich werden C++ Programme selten oder nie "rein" funktional sein, aber ich sehe keinen Grund, weshalb man nicht, wo immer es sich anbietet, die oben genannten Vorzüge nutzen sollte. Und da ist es völlig Wurscht, wie C++ in welchen Büchern gelehrt wird, denn hunderte von Autoren (Bücher und auch vor allem online-Tutorials) stecken mit ihrem C++ anscheinend immer noch in den 1990ern fest und haben es irgend wie verpennt, dass sich Sprache und Community in den letzten Jahrzehnten weiterentwickelt haben.

Noch ein kleiner Nebenhieb zum Thema globale Variablen. Ich höre immer wieder diesen von dir gebrachten Einwand, man solle globale Variablen doch nicht pauschal verteufeln ... irgend wo könnte ihr Einsatz ja doch gerechtfertigt sein. Ich habe bisher noch nicht einen einzigen Einsatz von globalen Variablen gesehen, den man nicht besser ohne die Globale hätte lösen können (Anmerkung: globale KONSTANTEN sind ok).
 
Nicht sicher, ob ich hier antworten sollte, oder wir darüber besser per PM weiterquatschen. Du entscheidest.

Dein Verständnis von funktionaler Programmierung ist zwar ein wichtiger Teilaspekt, aber wenn das alles wäre, würde man hier kaum von einem Paradigma sprechen, das der imperativen Programmierung gegenübersteht.
Programme in C++ sind eine Abfolge von Befehlen. Tu dies. Dann das. Ein Programm in einer Funktionalen Sprache ist eine Sammlung von Ausdrücken, die die Form von Funktionen Annehmen. Zum Beispiel:

Das Hello World der Funktionalen Programmierung ist die Fakultätsfunktion:
Code:
(define (factorial n)
  (define (iter product counter)
    (if (> counter n)
        product
        (iter (* counter product)
              (+ counter 1))))
  (iter 1 1))

Man könnte sie auch in einem imperativen Stil (mit den von dir genannten lokalen Variablen) schreiben:

Code:
(define (factorial n)
  (let ((product 1)
        (counter 1))
    (define (iter)
      (if (> counter n)
          product
          (begin (set! product (* counter product))
                 (set! counter (+ counter 1))
                 (iter))))
    (iter)))

Diese Funktion ist korrekt und gibt das selbe Ergebnis, aber es gibt einen entscheidenden Unterschied. Der Wert der Variablen counter ändert sich während der Abarbeitung der Funktion. Wenn man die Ausdrücke vertauschen würde

Code:
(set! counter (+ counter 1))
(set! product (* counter product))

wäre die Funktion nicht mehr korrekt. Das klingt trivial, ist aber entscheidend. Jede Zuweisung hat nebenwirkungen und die subtilen Probleme, die dadurch erst möglich werden, gibt es in der funktionalen Programmierung nicht. Wenn in einem Funktionalen Programm erst Funktion A und dann Funktion B aufgerufen wird, macht es aufgrund der Freiheit von Nebenwirkungen keinen Unterschied für das Ergebnis. Bei imperativer Programmierung ist der Zeitliche Ablauf der Ausführung essentiell und muss immer bedacht werden. Das ist kein Nachteil, sondern einfach eine andere Herangehensweise an die Frage, was ein Programm überhaupt ist. Daher ist es meiner Meinung nach auch richtig, bei der Unterscheidung von imperativer und funktioneller Programmierung von unterschiedlichen Paradigmen zu sprechen.

Wie gesagt, man kann das in C++ machen, aber würde der Gewinn, den man durch Verzicht auf Zuweisungen und sonstige Grundsätze der imperativen Programmierung erhält, den Aufwand aufwiegen, den man dazu treiben muss? In begrenztem Umfang, wie du es vorgeschlagen hast, ist das sicher vernünftig, aber irgendwann kommt man dahin, sich zu verbiegen, wie ich es genannt habe. Und das ist dann nicht mehr nützlich.


Ich habe bisher noch nicht einen einzigen Einsatz von globalen Variablen gesehen, den man nicht besser ohne die Globale hätte lösen können
getopt(). Könnte man ohne globale Variablen machen. Könnte man auch völlig anders implementieren. Aber ob das am Ende besser oder schlechter ist, ist Geschmackssache. Dann fällt mir noch errno ein.
 
asdfman schrieb:
Wie gesagt, man kann das in C++ machen, aber würde der Gewinn, den man durch Verzicht auf Zuweisungen und sonstige Grundsätze der imperativen Programmierung erhält, den Aufwand aufwiegen, den man dazu treiben muss? In begrenztem Umfang, wie du es vorgeschlagen hast, ist das sicher vernünftig, aber irgendwann kommt man dahin, sich zu verbiegen, wie ich es genannt habe. Und das ist dann nicht mehr nützlich.

Ich sagte ja auch: funktionaler Programmieransatz. Dass das aufgrund der Zuweisungen keine 100%-ig reine funktionale Programmierung ist, verstehe ich ... hätte ich vielleicht deutlicher machen sollen. Ich würde nie auf die Idee kommen, in C++ jegliche Zuweisungen vermeiden zu wollen ... das wäre wirklich krank. ;)

asdfman schrieb:
getopt(). Könnte man ohne globale Variablen machen. Könnte man auch völlig anders implementieren. Aber ob das am Ende besser oder schlechter ist, ist Geschmackssache. Dann fällt mir noch errno ein.

Na ja, es gibt errno nun eben mal. Damit muß man leben. Aber warum konnten all diese Funktionen ihren Erfolgsstatus nicht per return value oder per in/out-Zeigervariable kundtun? :) Meiner Meinung nach ist das so ein Fall von "Hmmm, war vielleicht keine so tolle Idee .... aber ist nun mal so."
 
getopt() benutzt globale Variablen unter anderem, um sich den Stand seiner eigenen Arbeit zwischen mehreren Aufrufen zu merken. Als die Funktion erfunden wurde, gab es noch keine statischen lokalen Variablen. Wüsste nicht, wie man es damals hätte besser machen können, ohne der Aufrufenden Funktion Dinge zurückzugeben, die sie nicht zu interessieren hat. Meiner Meinung nach wäre letzteres die wesentlich schlechtere Wahl. Natürlich keine Entschuldigung, es heute noch genauso zu machen.
Die aufrufende Funktion kann die von getopt() verwendeten globalen Variablen teilweise auch selbst gebrauchen. Aber nicht immer. Und trotzdem jeden Aufruf mit vier Variablen beladen, die man häufig eben doch nicht braucht, sondern nur getopt() selbst? Naja, ich weiß nicht. Außerdem fangen alle diese Variablen mit opt an und bilden so eine Art Namensraum, der einen dabei unterstützt, nicht die selben Variablen zu verwenden. Deshalb meiner Meinung nach kein Drama, sondern insgesamt eine sinnvolle Lösung. Abweichende Meinungen können abweichen.
 
Zurück
Oben