Ich habe nicht vor, in naher Zukunft einen Compiler zu schreiben. Trotzdem interessiere ich mich sehr für Compilertechnologien und wie dieses Zeug besser gemacht werden könnte.
Beginnend mit kompilierten Sprachen haben die meisten Compiler zwei Fehlerstufen: Warnungen und Fehler, wobei die erste meistens nicht schwerwiegende Probleme sind, die Sie beheben sollten, und Fehler, die meistens darauf hinweisen, dass es unmöglich ist, Maschinen- (oder Byte-) zu erzeugen. Code von der Eingabe.
Dies ist jedoch eine ziemlich schwache Definition. In einigen Sprachen wie Java können bestimmte Warnungen ohne Verwendung der @SuppressWarning
Direktive einfach nicht entfernt werden . Außerdem behandelt Java bestimmte nicht schwerwiegende Probleme als Fehler (z. B. löst nicht erreichbarer Code in Java einen Fehler aus einem Grund aus, den ich gerne wissen möchte).
C # hat nicht die gleichen Probleme, aber einige. Es scheint, dass die Kompilierung in mehreren Durchgängen erfolgt und ein fehlgeschlagener Durchgang die Ausführung der weiteren Durchgänge verhindert. Aus diesem Grund wird die Fehleranzahl, die Sie erhalten, wenn Ihr Build fehlschlägt, häufig stark unterschätzt. Bei einem Durchlauf könnte es heißen, dass Sie zwei Fehler haben, aber wenn Sie diese behoben haben, erhalten Sie möglicherweise 26 neue.
Das Graben in C und C ++ zeigt einfach eine schlechte Kombination der Schwachstellen bei der Kompilierungsdiagnose von Java und C # (obwohl es genauer sein könnte zu sagen, dass Java und C # jeweils nur die Hälfte der Probleme gelöst haben). Einige Warnungen sollten eigentlich Fehler sein (zum Beispiel, wenn nicht alle Codepfade einen Wert zurückgeben), und dennoch sind sie Warnungen, da die Compilertechnologie zum Zeitpunkt der Erstellung des Standards vermutlich nicht gut genug war, um diese Art von zu erstellen Schecks obligatorisch. In der gleichen Weise prüfen Compiler häufig, ob mehr als der Standard angibt, verwenden jedoch für die zusätzlichen Ergebnisse die Warnfehlerstufe "Standard". Und oft melden Compiler nicht alle Fehler, die sie finden könnten, sofort. Es kann einige Kompilierungen erfordern, um alle zu entfernen. Ganz zu schweigen von den kryptischen Fehlern, die C ++ - Compiler gerne ausspucken.
Wenn wir nun hinzufügen, dass viele Build-Systeme konfigurierbar sind, um Fehler zu melden, wenn die Compiler Warnungen ausgeben, erhalten wir nur eine seltsame Mischung: Nicht alle Fehler sind schwerwiegend, aber einige Warnungen sollten; Nicht alle Warnungen sind verdient, aber einige werden ausdrücklich unterdrückt, ohne dass ihre Existenz weiter erwähnt wird. und manchmal werden alle Warnungen zu Fehlern.
Nicht kompilierte Sprachen haben immer noch ihren Anteil an beschissenen Fehlerberichten. Tippfehler in Python werden erst gemeldet, wenn der Code tatsächlich ausgeführt wird, und Sie können nie mehr als einen Fehler gleichzeitig auslösen, da das Skript nicht mehr ausgeführt wird, nachdem es einen Fehler erfüllt.
PHP hat auf seiner Seite eine Reihe von mehr oder weniger signifikanten Fehlerstufen und Ausnahmen. Analysefehler werden einzeln gemeldet, Warnungen sind oft so schlecht, dass sie Ihr Skript abbrechen sollten (aber nicht standardmäßig), Benachrichtigungen zeigen sehr oft schwerwiegende logische Probleme, einige Fehler sind wirklich nicht schlimm genug, um Ihr Skript zu stoppen, aber dennoch tun, und wie bei PHP üblich, gibt es dort unten einige wirklich seltsame Dinge (warum zum Teufel brauchen wir eine Fehlerstufe für schwerwiegende Fehler, die nicht wirklich schwerwiegend sind? E_RECOVERABLE_E_ERROR
Ich spreche mit Ihnen).
Es scheint mir, dass jede einzelne Implementierung der Compiler-Fehlerberichterstattung, die mir einfällt, fehlerhaft ist. Das ist eine echte Schande, denn alle guten Programmierer bestehen darauf, wie wichtig es ist, mit Fehlern richtig umzugehen, und können dennoch keine eigenen Tools dafür bekommen.
Was sollte Ihrer Meinung nach der richtige Weg sein, um Compilerfehler zu melden?
Antworten:
Ihre Frage scheint nicht wirklich zu sein, wie wir Compilerfehler melden, sondern es geht um die Klassifizierung von Problemen und was zu tun ist.
Wenn wir zunächst davon ausgehen, dass die Dichotomie zwischen Warnung und Fehler korrekt ist, wollen wir sehen, wie gut wir darauf aufbauen können. Einige Ideen:
Unterschiedliche "Warnstufen". Viele Compiler implementieren dies sozusagen (zum Beispiel hat GCC viele Schalter, um genau zu konfigurieren, worüber gewarnt wird), aber es muss noch gearbeitet werden - zum Beispiel, um den Schweregrad einer gemeldeten Warnung zu melden und um "Warnungen" festzulegen sind Fehler "nur für Warnungen über einem bestimmten Schweregrad.
Vernünftige Klassifizierung von Fehlern und Warnungen. Ein Fehler sollte nur gemeldet werden, wenn der Code nicht der Spezifikation entspricht und daher nicht kompiliert werden kann. Nicht erreichbare Anweisungen, obwohl wahrscheinlich ein Codierungsfehler, sollten eine Warnung sein , kein Fehler - der Code ist immer noch "gültig", und es gibt legitime Fälle, in denen man mit nicht erreichbarem Code kompilieren möchte (z. B. schnelle Änderungen zum Debuggen). .
Nun Dinge, mit denen ich nicht einverstanden bin:
Machen Sie zusätzliche Anstrengungen, um jedes Problem zu melden. Wenn ein Fehler auftritt, wird der Build unterbrochen. Der Build ist kaputt. Der Build funktioniert erst, wenn dieser Fehler behoben ist. Daher ist es besser, diesen Fehler sofort zu melden, als "weiterzumachen", um zu versuchen, alles andere "falsch" mit dem Code zu identifizieren. Vor allem, wenn viele dieser Dinge wahrscheinlich sowieso durch den anfänglichen Fehler verursacht werden.
Ihr spezifisches Beispiel für eine Warnung, die ein Fehler sein sollte. Ja, es ist wahrscheinlich ein Programmiererfehler. Nein, es sollte den Build nicht brechen. Wenn ich weiß, dass die Eingabe für die Funktion so ist, dass sie immer einen Wert zurückgibt, sollte ich in der Lage sein, den Build auszuführen und einige Tests durchzuführen, ohne diese zusätzlichen Überprüfungen hinzufügen zu müssen. Ja, es sollte eine Warnung sein. Und noch dazu eine verdammt schwere. Aber es sollte den Build an und für sich nicht brechen, es sei denn, das Kompilieren mit Warnungen ist Fehler.
Gedanken?
quelle
Ein Problem, das Sie angesprochen haben, war die unvollständige Meldung von Fehlern - z. B. die Meldung von zwei Fehlern. Wenn Sie diese beheben, erhalten Sie eine Menge mehr.
Dies ist (größtenteils) ein Kompromiss seitens des Compiler-Writers. Abhängig davon, welchen Fehler Sie gemacht haben, kann der Compiler sehr leicht falsch verstehen, was Sie haben, so dass er Fehler meldet, die sehr wenig mit der Realität zu tun haben. Stellen Sie sich zum Beispiel einen einfachen Tippfehler vor, bei dem Sie so etwas wie
itn x;
anstelle von habenint x;
. Sofern Sie nichts anderes getan haben, dasitn
etwas bedeutet, wird dies als Fehler gemeldet. Das ist in Ordnung so weit wie es geht, aber jetzt überlegen , was als nächstes passiert - die Compiler schaut viel Code, der versucht, die Verwendungx
als Variable. Sollte es A) aufhören und Sie das beheben lassen, oder B) 2000 Fehlererror: "x": undeclared identifier
oder etwas in dieser Reihenfolge ausspucken ? Betrachten Sie eine andere Möglichkeit:Dies ist ein weiterer ziemlich offensichtlicher Tippfehler - offensichtlich sollte es ein
{
statt eines sein[
. Der Compiler kann Ihnen diesen Teil ziemlich leicht sagen - aber sollte er dann einen Fehler melden, wenn Sie beispielsweise etwasx=1;
sagenerror: statement only allowed inside a function
?Beachten Sie, dass dies sogar ziemlich triviale Probleme sind - viel schlimmere sind leicht zu finden (insbesondere, wie die meisten von uns wissen, wenn Sie in C ++ - Vorlagen einsteigen). Das Fazit ist, dass der Compiler-Writer normalerweise nicht in der Lage ist, Kompromisse zwischen der Meldung falscher Fehler (dh der Meldung eines Fehlers, obwohl dies in Ordnung ist) und der Nichtmeldung realer Fehler einzugehen. Es gibt einige Faustregeln, die die meisten befolgen, um zu verhindern, dass sie in beide Richtungen zu weit falsch laufen, aber fast keine davon ist annähernd perfekt.
Ein weiteres Problem, das Sie erwähnt haben, war Java und
@SupressWarning
. Dies ist ganz anders als oben - es wäre ziemlich trivial zu beheben. Der einzige Grund, warum es nicht behoben ist, ist, dass dies nicht zum grundlegenden "Charakter" von Java passt - dh ihrer Meinung nach "das ist kein Fehler, es ist eine Funktion". Obwohl es normalerweise ein Witz ist, sind die beteiligten Personen in diesem Fall so irregeführt, dass sie wirklich glauben, dass es wahr ist.Das Problem, das Sie in C und C ++ mit Codepfaden erwähnen, die keinen Wert zurückgeben, besteht nicht darin, primitive Compiler zuzulassen. Es soll Jahrzehnte vorhandenen Codes zulassen , von denen einige niemand reparieren, berühren oder sogar lesen möchte. Es ist uralt und hässlich, aber es funktioniert, und niemand möchte etwas anderes, als dass es weiter funktioniert. Ob gut oder schlecht, die Sprachkomitees sind ziemlich fest entschlossen, diese Abwärtskompatibilität aufrechtzuerhalten, und erlauben daher weiterhin Dinge, die niemand wirklich mag - aber einige Leute (zumindest denken sie, dass sie es brauchen).
quelle
csc
aufgibt.