[lang_en]Actually, I have known this for some time, but today, it has bitten me again: Interpreted languages ((like Python)) are not suited for application development. Period. Use them for quick hacks, or for prototyping, or in lieu of a shell script. But never for real applications.
People tend to say Computers are so fast today the overhead does not really matter, and if it does for a few inner loops, no problem: our language can interface with C. But that is beside the point. The real disadvantage of these languages is not their (somewhat inferior) execution speed, but their lack of static checking. If you write bogus in a compiled language, chances are the compiler will catch it. Some stricter languages ((like Ada)) will catch more kinds of bogus than more lenient ones ((like C)), but there are surprisingly many ways to write bogus that every compiler will catch. Interpreted languages do not have a compile phase, they just throw an exception when encountering bogus at runtime. If they encounter it: There are many execution paths through a program, and some may not be followed very often, making it easy to write, install, and use completely broken software. You may say Well, write tests then, but as useful tests are, they come with large disadvantages when relied upon as the only means of detecting errors: Firstly, they have to be written. A compiler knows about the language, but the developer has to write all necessary testcases by hand. It is easy to overlook something, and it is also very easy to be lazy and write too few tests (or none at all). Secondly, executing tests takes machine time (probably more than what was saved by not compiling), and writing tests takes developer time (lots of it). Finally, the static analysis a compiler provides tends to catch different errors than tests do, so combining the two will simply catch more problems than either method on its own.
Oh, and then there is the problem of external code. Libraries, modules, whatever. APIs should not change (needlessly), but sometimes they do. With ordinary binary code, there is an established way to keep around different versions of a given library, so older programs using an older API can still function. I am not aware of a similar mechanism for Python, so getting ImportErrors from a module that installed just fine is not that unusual. In fact, implementing such a method for an interpreted language would be somewhat more involved than for a compiled one: When a programmer links to a shared library, the linker will take that to mean the latest installed version of that library. The version number is then encoded into the application binary, so the correct library will be used whenever the application is started. However, the very nature of an interpreted language means that the program is not touched by anyone but the developer. So if the developer does not demand a particular version, nothing else does, either. Seriously: use a tool that fits the job rather than clutching a hammer and trying to see nails everywhere.[/lang_en]
[lang_de]Eigentlich weiß ich das ja schon länger, aber heute ist es mir wieder schmerzhaft bewußt geworden: Interpretierte Sprachen ((z.B. Python)) sind zur Entwicklung ernsthafter Programme ungeeignet. Für Prototypen, einen schnellen Hack, oder als Shell-Skript-Ersatz sind sie eine feine Sache, aber nicht für echte Programme.
Man hört oft, Computer sind heutzutage so schnell, daß das schlechtere Laufzeitverhalten nicht ins Gewicht fällt, und falls doch ein paar Stellen kritisch sind, so ist das auch kein Problem: die Sprache kann C-Routinen aufrufen. Aber darum geht es nicht. Die echten Nachteile liegen nicht in der Ausführungsgeschwindigkeit, sondern in der fehlenden statischen Prüfung des Codes. Wenn man in einer kompilierten Sprache Quatsch schreibt, dann kann man darauf hoffen, daß der Compiler das bemerkt. In manchen strengeren Sprachen ((z.B. Ada)) läßt der Compiler weniger Quatsch durchgehen als in nachgiebigeren ((z.B. C)), aber es gibt erstaunliche viele Sorten Quatsch, die jeder Compiler findet. Interpretierte Sprachen kennen keinen Compiler, deswegen finden sie den Quatsch erst zur Laufzeit. Wenn sie ihn finden: Es gibt viele Pfade durch ein Programm, und einige davon werden nur selten benutz; deshalb ist es einfach, völlig vergurkte Programme zu schreiben, zu installieren, und zu benutzen. Es heißt dann oft Deshalb brauchen wir Tests, aber so nützlich Tests auch sind, so haben sie doch gewichtige Nachteile (jedenfalls wenn sie die einzige Möglichkeit sind, Fehler zu finden: Zuerst müssen sie überhaupt geschrieben werden. Ein Compiler versteht die Sprache, aber der Entwickler muß alle nötigen Testcases von Hand schreiben. Dabei kann man leicht etwas übersehen, und noch leichter aus Bequemlichkeit zu wenige (oder gar keine) Tests schreiben. Zweitens braucht das Abarbeiten der Tests Rechenzeit — wahrscheinlich mehr, als man durch den fehlenden Compilerlauf gespart hat; und das Schreiben kosts Entwicklerzeit, und zwar eine Menge. Schließlich findet der Compiler oft einfach andere Fehler als Tests, und wenn man beides einsetzt, findet man mehr Fehler.
Ja, und dann gibt es noch das Problem mit externem Code. Bibliotheken, Module, oder wie man ihn auch nennen will. APIs sollten sich nicht ändern (jedenfalls nicht ohne guten Grund), aber manchmal tun sie es eben doch. Für gewöhnliche, binäre Programme gibt es wohldefinierte Mechanismen, um verschiedene Versionen einer Bibliothek gleichzeitig vorzuhalten, damit ältere Programme immer noch laufen. Einen entsprechenden Mechanismus für Python kenne ich nicht, und so ungewöhnlich ist es nicht, wenn ein sauber installiertes Modul mit ImportErrors um sich wirft. Wenn man eine solche Methode entwickeln wollte, hätte man auch mit einem zusätzlichen Problem zu kämpfen: Wenn ein Programmierer eine shared library verlinkt, dann nimmt der Linker automatisch die neueste installierte Version dieser Bibliothek. Die Versionsnummer wird dann in dem kompilierten Programm verewigt, und wenn man es irgendwann später startet, wird die richtige Bibliothek benutzt. Es liegt aber gerade im Wesen einer interpretierten Sprache, daß der Programmcode nur vom Programmierer verändert wird. Wenn dieser also nicht von Hand eine bestimmte Bibliotheksversion anfordert, dann tut das auch keine andere Instanz.
Im Ernst: man sollte Werkzeuge verwenden, die für die Aufgabe geeignet sind, anstatt sich verzweifelt an seinen Hammer zu klammern und überall Nägel zu sehen.[/lang_de]