Panke hat geschrieben:Goto ist ja sehr wohl definiert.
"hier", "da" und "dort" sind Variablen.
Vergleiche nun:
und
Früher hieß das "Spaghetticode", heute sagt man "State of the Art".
----------------
PS (heißt, diesen Text schreibe ich nach dem Text weiter unten, weil es mir erst mit diesem Posting aufgefallen ist)
Das mit Goto passt nicht richtig. On ExceptionID goto ... ist eigenlich noch zu sauber. Fällt mir jetzt erst richtig auf: die richtigere Formulierung wäre eigentlich an ein Intercal-Statement angelehnt:
Code: Alles auswählen
static char const * exceptionDataWhat;
double sqrt( double value )
{
if( value -1 )
{
exceptionDataWhat = "Wurzel aus negativer Zahl gezogen";
SQRT_NEGATIVE_VALUE:
// entspricht throw NegativeValue();
}
...
return result;
}
int main()
{
sqrt(-1);
goto BEYOND;
please come from SQRT_NEGATIVE_VALUE:
{
// Das Label SQRT_NEGATIVE_VALUE wurde erreicht, also geht der Code hier weiter.
printf( "Exception: %s\n", exceptionDataWhat );
}
BEYOND:
return 0;
Ja, wie geil ist das denn!? ^^
Alles da, das ExceptionObjekt - hier zwar nur ein String - im eigentlichen Code gibt es zwischen catch und came from keinen nennenswerten Unterschied (es gibt einen, der bei der Auswertung der Exceptions auch aufwendig ausformuliert wird und Exceptions so teuer macht).
Exceptions lassen sich wunderbar abbilden mit einem Konzept, dass 1972
SPASSESHALBER entwickelt wurde, um aufzuzeigen, wie man schlecht programmiert.
Und jetzt machen wir das und die Unis lehren das als gute Programmierung... jetzt ich find' das erst richtig geil. Ich fand schon damals, dass vieles im Studium nicht wirklich ernst gemeint gewesen sein konnte... aber das verblüfft mich jetzt auch ein wenig.
Hoffentlich kommen wir bald wieder in der Fehlerbehandlung der 80er an. Wir befinden uns gerade in den frühen 70ern und selbst da hat man das nicht ernst gemeint.
Wikipedia hat geschrieben: INTERCAL wurde mit dem Ziel entwickelt, das Programmieren schwierig zu gestalten und die entstehenden Programme effektiv unlesbar zu machen. Insofern ähnelt INTERCAL keiner der bekannten Programmiersprachen, hat sehr wenige Sprachkonstrukte und ist schwer zu erlernen. Besonders berühmt ist der „ComeFrom“ Befehl, der invers an den Goto-Befehl vieler Programmiersprachen angelehnt ist.
---------------- </PS>
Panke hat geschrieben:Was ist, wenn du den Fehler nur an die aufrufende Funktion weiterreichen willst? Dann reicht die Prüfung einer einzigen Funktion eben nicht aus.
Jede Funktion prüft, ob sie Fehlercodes der gerufenen Funktionen bearbeitet.
Panke hat geschrieben:Außerdem kannst du eh nicht prüfen, ob etwas sinnvolles machst, sondern nur ob du überhaupt etwas machst. Das ist ja gerade der Irrweg, der bei Java zu den fang-alles- und fangen-aber-verwerfen-Fehlern führt.
Das ist korrekt. Ich will aber auch keinen Fehler oder eine Warning geben. Ich will eine Debug-Version, die automatisch protokolliert und mir sagt "Funktion X, File Y, Zeile Z erhielt bei Aufruf von F() Fehlercode "GehtNicht" und Du Depp kümmerst Dich nicht drum."
Und diese Information ist automatisiert beschaffbar, auch dann, wenn der Entwickler den Fehlercode nicht explizit abfragt.
Das Ganze ist sogar zum Teil während der semantischen Analyse während des Compilierens machbar.
Im Sprachdesign heißt das, dass Fehler, die ich nicht erwarte, auch nicht behandelt werden (statt(!) catch all, dass explizit alle Fehler behandelt) und ich vor allem nicht gezwungen werde sie zu behandeln. Treten sie doch auf, kann ich sie automatisiert loggen lassen oder eine Exception werfen
lassen, die das Programm in einen Fehlerzustand versetzt und anschließend beendet.
Wenn ich Fehler behandle, dann muss ich sie vor Ort behandeln oder explizit aussagen, dass ich sie durchreiche.
Panke hat geschrieben:Und wenn ein Fehler auftritt, den ich noch nicht behandelt habe, will ich dass mein Programm mit einer hoffentlich halbwegs guten Fehlermeldung abschmiert. Das garantieren - bei Beachtung simpler Programmierregeln - Exceptions.
Die Programmierregeln sind simple und unrealistisch. Sie werden nicht eingehalten.
Das muss man so akzeptieren. Man kann per Gesetz Mord verbieten, aber das garantiert einem nicht, dass man nicht ermordet wird. Und die Regeln, damit Exceptions Vorteile bringen, werden zu selten eingehalten. Und wie beim Mord, reicht von 80 Millionen BRD-Bürgern einer aus, der Dich um die Ecke bringt.
Sobald einer Mist baut, knallt's.
Einer baut immer Mist und das ist selbst in einem Zwei-Mann-Team schon recht optimistisch.
Der Gesetzgeber reagiert darauf: Er verbietet nicht nur Mord, er stellt es unter Strafe. Die Programmiersprache nicht.
Also muss die Sache anders angegangen werden: Das Defaultverhalten der Sprache muss so sein, dass sie nicht kompiliert, wenn der Benutzer nicht exakt formuliert hat, was er will.
Das will der Benutzer bei Fehlerfällen oftmals nicht. Also muss die Sprache eine Möglichkeit bieten, beim Fehlerfall den Entwickler zu nerven.
Panke hat geschrieben:Fehlercodes stützen sich darauf, dass vielleicht der folgende Code abstürzt, das ist aber nicht garantiert.
Das kann man garantieren.
In C kann man dafür Assert() benutzen. Machen aber wenige. Macht die Sprache das automatisch, werden die Entwickler sich klar ausdrücken.
Panke hat geschrieben:Ich schrieb neulich einen kleinen Server. Der stürzte relativ häufig ab mit
what() : Port already in use
Kein Problem, hatte halt eine andere Instanz laufen. Wäre er mit
segmantation fault
oder etwas ähnlichem abgestürzt,
hätte ich einen eher schwierig zu reproduzierenden Fehler gehabt, den
ich erstmal hätte suchen müssen. So hat mich das nicht eine Sekunde gekostet.
Das ist
keine Ausnahme!
Das ist genau der Punkt, an dem Ausnahmen ÜBERHAUPT GARNICHTS zu suchen haben.
Du fragst nach einem Port, also gibt es zwei Möglichkeiten: Ja, Du bekommst ihn und Nein, Du bekommst ihn nicht. Da hast Du einfach nur scheiße programmiert.
Mit dem Segmentation-Fault hast Du vielleicht nicht den Text, aber die Zeile, die geknallt hat.
Dort geht Dein ungültiger Socket rein und Du musst Dich fragen, wieso der eigentlich nicht gültig ist.
Dann wirst Du kapieren, dass Du Mist programmiert hast in dem Du einen Regelfall - keine Ausnahme - ignoriert hast und für die Zukunft hoffentlich wissen, dass man Regelfälle sofort abdecken muss. Man findet sie nicht experimentell heraus und gibt das Programm dann weiter, wenn es auf der heimischen Umgebung zufälligerweise keine Exceptions wirft.
Sorry, aber Du konzentrierst Dich auf den Wunschverlauf, den Du behandeln willst und nicht auf den Verlauf, den Dein Programm nehmen kann. Das ist wie bei der Ostereiersuche große Hinweisschilder zu verlangen, damit man sich nicht verläuft und keine Süßigkeit übersieht. Das hat einfach nichts mit Programmierung zu tun. Da kannst Du gleich "programmDasTutWasIchWill();" in main aufrufen und hoffen, dass irgendwer die Funktion schon fertig implementiert hat.
Panke hat geschrieben:Du hast noch gar nicht dargelegt, wie der Fehlercode-Mechanismus von dir aussehen soll. Vielleicht reden wir auch aneinander vorbei.
Im Prinzip wie Exceptions, nur dass man eben maximal bis zur aufrufenden Funktion kommt und nicht weiter.
Panke hat geschrieben:
Folgendes Szenario: Ich habe einen relativ komplexen Algorithmus, der viel Speicher frisst. Sagen wir aus dem Bereich KI und Planung. Die sind ja immer im Grunde Suchverfahren mit Backtracking mit kleveren Heuristiken. Ich kann eine gewisse Suchtiefe angeben und der Speicherverbrauch ist exponentiell zur Tiefe. Jetzt will ich folgendes machen können:
Code: Alles auswählen
catch(std::bad_alloc e)
{
// tja, nicht genug Speicher für depth=20. Zum Glück sind Exceptions
// mehr als ein goto und "search" garantiert mir, dass es im Falle einer
// Ausnahme einen konsistenten, aufgeräumten Zustand hinterlässt durch
// Stack Unwinding und RAII. Also kann ich hier einfach weitermachen.
}
Wenn search jetzt die Funktionen foo, fart, faz, bar, bart, batz aufruft, möchte ich nicht
in so einem Callstack
foo
----fart
-------- faz
------------ bar
---------------- bart
-------------------- batz
In jeder Funktion den Fehlercode bei jeder Allocation prüfen und eventuell reagieren müssen. Mit Exceptions knallt mir mein
Bad-Alloc -- ohne, dass ich mich in foo, fart, faz, bar, bart, batz drum kümmern muss -- einfach bis nach
oben durch. Das ist doch der Vorteil von Exceptions. Das können Fehlercodes leider nicht.
Wenn Du auf Unwinding und RAII vertraust, wieso bekommst Du ein bad_alloc?
Und da Du offenbar doch Speicher alloziierst musst Du sowieso in foo, fart, faz, bar, bart und batz auf den Fehler reagieren, indem Du dort den Speicher und die Handles wieder freigibst, bevor Du die Exception durchreichst.
Ich glaube, ich habe den Vorteil der Exceptions gerade verpasst.
Panke hat geschrieben:
Umgekehrt krieg ich mit Exceptions alles hin, was Fehlercodes auch können.
Folgender Code:
Mit Exceptions kein Problem. Mit Fehlercodes? Entweder immer ein Aufruf mehr oder man macht nicht triviale Initialisierung in einer
init-Methode. Auch nicht schön.
Hier stimme ich Dir zu. Das ist eine Schwachstelle in C++.
Panke hat geschrieben:Ich behaupte nicht, dass Exceptions der Weisheit letzter Schluss sind, aber jeder Ersatz muss mindestens den gleichen Komfort bieten. Die Alternative ist nicht, zu Fehlerbehandlung der 80iger Jahre zurückzukehren. Die ist eben nicht gleichwertig.
Nein, es ist höherwertig, denn das Prinzip ist automatisiert prüfbar.
Java hat auf Exceptions gesetzt, C++ nicht wirklich. C# ist von Java abgekupfert. Java wurde als der Gral der Weisheit verkauft. Ich habe von Professoren (quasi das, was Professionelle ausbilden soll) erfahren, wie toll Java ist, dass man keine Pointer braucht, dass Exceptions toll sind und ich habe Rückfragen gestellt.
Ich weiß wie Exceptions funktionieren. Und ich gehöre auch noch zu der Generation, die selbst Spaghetti-Code geschrieben hat, sich im Debuggen verheddert hat und die Erfahrung hat, den Mist zu debuggen.
Darum vermeide ich sowas aus Erfahrung.
In echten Java-Programmen (nicht sowas, was man an der Uni schreibt), konnte ich die Spaghetti-Code-Erfahrungen wieder gut gebrauchen.
Panke hat geschrieben:Und der Hauptkritikpunkt an Exceptions scheint ja >catch-all, weil faul< zu sein. Das ist aber kein Problem von Exceptions an und für sich, sondern daran, dass Java es einfacher macht, leere catch-Klauseln von Exclipse generieren zu lassen, als erst gar keine hinzuschreiben.
Das ist der Fehler im Konzept. Die Sprache fordert dazu auf, darum wollen die Benutzer es schreiben und darum nimmt ihnen die IDE die Arbeit ab.
---- späteres Posting
Das Beispiel mit der Suche kann ich nicht wirklich nachvollziehen. Eine Suche sucht in vorhandenen Daten, sie produziert keine Daten. Suchfunktionen sind in der Regel Const-Methods. Wenn Du eine CD im Schrank suchst und Du den Fehler "Konnte neue CD nicht in Schrank stellen" erhältst, dann solltest Du das Suchkonzept überarbeiten.
Panke hat geschrieben:Ein anderes Beispiel wäre, dass man versucht eine Kripke-Struktur (ein großer Graph) für ein Model-Checking-Problem in den Speicher zu laden. Das kann auch mal schief gehen, weil zu groß. Und dann? Muss jeder Fitzelchen Code wissen, dass ich eine Kripke-Struktur in den Speicher lade und da durchaus mal der Speicher ausgehen kann. Damit der "low-level" Code das Problem lösen kann, weil der "high-level" Code dazu eh nicht in der Lage ist?
Jeder Knoten ist ein Objekt. Beim Laden stellt ein Knoten fest, dass er den Unterknoten nicht anlegen kann. Er meldet das Problem. Da das ganze Rekursiv läuft, durchläuft die Fehlermeldung den Graphen. Der erste Knoten stellt fest, dass der Graph nicht ladbar ist und ruft die Destruktoren seiner Umgebung. Der Graph ist weg und der Konstruktor (der in dem Fall eine statische Load-Funktion wäre) meldet dem Aufrufer den Fehlercode "PasstNichtInDenSpeicher".
Es sind zwei Fitzel Code, die das wissen müssen - genau wie bei den Exceptions: Die Graph-Knoten legen nur weitere Unterknoten an, wenn die vorherigen Knoten angelegt werden konnten und die Ladefunktion unterscheidet zwischen "alle Knoten angelegt" und "passt nicht".
--------------
Intercal-Website:
http://www.catb.org/~esr/intercal/
Die Startseite ist lesenswert...
Merke: Wer Ordnung hellt ist nicht zwangsläufig eine Leuchte.
Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.