Java |
Ich habe lange mit Java entwickelt (u.a. meine Diplomarbeit). Das
Kompilieren zu Bytecode ist umständlich. Außerdem ist Java nur
kostenlos, aber nicht frei. Da es mehrere Java Compiler und
Interpreter gibt, kommt es immer wieder zu Problemen. Während sich
SUN damit beschäftigt Interfaces zu definieren, die dann von
kommerziellen Anbietern implementiert werden, erstellen die
Entwickler freier Programmiersprachen eine lauffähige
Bibliothek.
|
C |
C ist rasend schnell in der Ausführung. Die Entwicklungszeit ist
jedoch so langsam, dass ich nicht freiwillig in dieser Sprache
programmiere. Der Einsatz von C ist nur bei betriebssystemnahen
und zeitkritischen Aufgaben sinnvoll. Jeder, der sich ernsthaft
mit Computern beschäftigt sollte dieser Sprache kennen. Debugging
mit valgrind kann einem sehr viel Zeit
sparen: Jeder Speicherzugriff wird von valgrind interpretiert und
ggf. werden Warnungen auf stderr geschrieben.
|
C++ |
C++ hat gegenüber C mehrere Vorteile: Durch die Objektorientierung
sind große Programme besser zu strukturieren. Exceptions
(Ausnahmen) vereinfachen die Behandlung von Fehlern
enorm. Trotzdem ist die Programmierung im Vergleich zu anderen
Sprachen umständlich. Ein Grund dafür ist z.B., dass es keinen
Garbage Collector gibt.
|
Lisp |
Lisp hat einige interessante Aspekte. Lisp hat den Nachteil, dass
es viele verschiedene zueinander inkompatible Implementierungen
gibt. Die auf Klammern beruhende und einfache Syntax ist eher für
Maschinen als für Menschen geeignet.
|
Perl
|
Perl ist Python sehr ähnlich. Da Perl-Code vieleSonderzeichen
enthält, ist der Code nicht so leicht lesbar. Komplexe Programme
werden in Perl unweigerlich "hässlich". Objektorientierung ist
möglich, aber die Syntax ist grausam.
|
Ruby
|
Als ich mit Sommer 2001 mit Perl und Java unzufrieden war, und
eine neue Programmiersprache suchte, betrachtete ich Ruby und
Python. Ruby fehlt bis heute integrierte Unicode
Unterstützung. Außerdem ist Ruby nicht so verbreitet wie Python
und es gibt weniger Module. Nachteilig find ich, dass der beim
Aufruf einer Methode die Klammern weggelassen werden können. Das
macht es schwierig zwischen der Methode und dem Methodenaufruf zu
unterscheiden (aka Funktionspointer).
|
PHP |
PHP ist sehr verbreitet. Es wird hauptsächlich verwendet um auf
einem Webserver HTML-Seiten für Browser zu erstellen. Bei PHP
sehen Anfänger sofort einen Fortschritt: In wenigen Minuten ist
eine einfaches Web-Formular erstellt. Der Einsatz außerhalb von
Web-Anwendungen ist zwar auch möglich (z.B. gibt es eine Anbindung
an die GUI-Bibliothek gtk), aber hier sieht man schnell, dass der
Einsatz einer universellen Sprache sinnvoller ist.
|
TCL/TK |
TCL ist eine Scriptsprache, mit der hauptsächlich portable
grafische Benutzeroberflächen programmiert werden. Die Syntax von
TCL errinnert etwas an Shell-Scripte. Die Bibliothek TK kann auch
mit Python programmiert werden (tkinter). TCL/TK wird kaum mehr
weiterentwickelt. Für grafische Oberflächen empfehle ich PyGTK.
|
Shell |
Mittels Shell-Scripten lassen sich in wenigen Zeilen komplexe
Aufgabenstellungen lösen. Werden die Scripte jedoch länger als 30
Zeilen, werden sie schnell unübersichtlich. Die meisten Scripte
"fliegen einem um die Ohren" wenn Leer- oder Sonderzeichen in
Dateinamen vorkommen. Man muss sich jedoch immer bewusst sein,
dass es keine portablen Shell-Scripte gibt. Was mit der Bash unter
Linux funktioniert, muss mit der Standard-Shell von Solaris noch
lange nicht funktionieren.
Einige Gründe warum ich Shellscripte meide:
- Keine Exceptions: Bei einem Fehler wird eine Meldung nach
Standard-Error ausgegeben und mit der nächsten Zeile des Scripts
weitergemacht.
- Shellscripte sind selten portabel: Bash vs. ash/zsh, Linux
vs. BSD, ...
- Werden in einem Shellscript viele externe Programme gerufen
(grep, cut, sort, sed, ...) werden die Scripte schnell
langsam. Die Systemlast steigt, da viele neue Prozesse gestartet
werden müssen.
Für den Embedded-Bereich (z.B. OpenWRT (Linux auf
einem WLAN-Router)), sind Shellscripte gut geeignet, da
z.B. Python zu groß ist. Ein einziges Binary (BusyBox) stellt eine
Shell, und alle für ein Unix üblichen Befehle (awk, cat, chmod,
chown, cp, crond, cut, date, dd, df, diff, ...) bereit.
|
Python
|
Die Syntax ist sauber und einfach. Quelltext ist auch nach Jahren
noch leicht lesbar. Die Objektorientierung ist pragmatisch
gelöst. Nur in Ausnahmefällen greife ich zu einer anderen
Sprache. Beispiel für eine Ausnahme: Ein Script soll nur einmal
eingesetzt werden und lässt sich mit wenigen Zeilen mit der Shell
(Bash) erledigen.
|
- In Python werden die geläufigen Begriffe verwendet. Gibt es für
etwas einen festen Begriff im ANSI-C oder POSIX Standard, dann wird
dieser Begriff verwendet. Erfahrene Programmierer finden im Index sofort die
benötigten Funktionen. In Perl werden oft andere Worte verwendet.
- Mit der Funktion "length" bestimmt nur die Länge einer
Zeichenkette bestimmen, aber nicht die Länge eines Arrays oder
Hashes. Dies geht so:
# -- Perl --
# Zeichenkette
length($mystring);
# Array (Liste)
scalar @array;
$#array; # oder: Index des letzten Elements im Array (Länge - 1)
# Hash (Dictionary)
scalar keys %hash;
In Python ist die Syntax um die Länge zu bekommen immer gleich:
# -- Python --
mystring="abc"
len(mystring)
mylist=[1, 2, 3, 4]
len(mylist)
mydict={1: "eins", 2: "zwei", 3: "drei"}
len(mydict)
- Perl: Keine Warnung, falls man zuviele Argumente bei printf angibt:
printf "%s\n", "eins", "zwei";
In Python erhält man ein Exception, falls die Anzahl der Argumente
nicht stimmt:
print "%s" % ("eins", "zwei")
Traceback (most recent call last):
File "/home/guettli/test.py", line 6, in ?
main()
File "/home/guettli/test.py", line 4, in main
print "%s" % ("eins", "zwei")
TypeError: not all arguments converted during string formatting
- Zeichenketten können in Perl nicht wie Listen behandelt
werden. In Python schon:
# -- Perl --
$value = substr($string, $offset, $count);
$value = substr($string, $offset);
# -- Python --
value = mystring[start:end]
-
In Perl können die Klammern bei einem Funktionsaufruf fehlen. Das
verschlechtert die Lesbarkeit des Quelltextes. Wie will man da
einen Funktionsaufruf von einem Funktionspointer unterscheiden?
#Perl
$obj->foo;
|
#Python
obj.foo() # Funktionsaufruf
obj.foo # Referenz zu der Funktion. (Funktionspointer)
|
print "5" + 3;
Obiges Beispiel führt in Perl zu keiner Fehlermeldung. Wenn eine
Zahl zu einem String addiert wird, handelt es sich um einen
Programmfehler. Perl konvertiert automatisch den String "5" zu
einer Zahl. Dieses Verhalten führt jedoch dazu, dass Programmfehler
übersehen werden. Die explizite Schreibweise in Python
print int("5") + 3
sagt mir mehr zu.
Was ergibt int("zeichenkette")
in Perl? Eine
Integer-Null. In Python erhält man eine Exception, was aus meiner
Sicht mehr angebracht ist. Vergleich zum "wirklichen Leben": Wenn
man beim Fleischer ein Stück Kuchen kaufen möchte, wird er einem
nicht wortlos eine leere Tüte (Integer-Null) geben, sonder darauf
hinweisen: "Nein, hier bekommen Sie keinen Kuchen!"
$_
Perl verwendet viele "magische" Variablen ($_, @_,
$!, $&, ...), was den Quelltext sehr unverständlich macht.
- Builtin Regular Expresssions: In Python sind Reguläre Ausdrücke
mittels einer Bibliothek verfügbar. In Perl sind sie Teil der Syntax der
Sprache. Ich finde den Ansatz von Python sauberer.
-
Zeichenketten werden in Perl mit dem "eq" Operator und nicht mit
"==" verglichen. In Python gibt es nur einen Vergleichsoperator, was
besonders für Anfänger einfacher ist.
- Die Print-Anweisung in Python zeigt meist sinnvollere Informationen:
#Perl:
@array=(9, 10, 11);
print @array;
---> 91011
#Python:
array=[9, 10, 11]
print array
---> [9, 10, 11]
- Variablen brauchen in Perl nicht initialisiert zu werden:
@array=undef;
push(@array, 1);
print @array;
#oder:
$myint=undef;
$myint++;
In Python müssen Variablen mit einer Zuweisung
initialisiert werden. Fehler im Quelltext fallen so früher auf:
array=[]
array.append(1)
-
Wird auf nicht existierende Elemente in einem Hash zugegriffen,
erhält man in Python eine Exception, in Perl jedoch nicht:
#Perl:
my (%myhash);
$var=$myhash{"nicht existent"};
print "meine Variable: $var\n";
Durch dieses Verhalten werden Fehler übergangen. Zum
Programmabsturz kommt es dann erst an einer späteren Stelle im
Quelltext. Dort lässt sich der Fehler jedoch schlecht lokalisieren,
verstehen und beheben.
Perl verhält sich hier ähnlich wie ein Shellscript. Falls
ein Befehl fehlschlägt, wird ggf. eine Fehlermeldung auf
Standarderror ausgegeben und die nächste Zeile abgearbeitet als
wäre nichts gewesen.
Mir ist eine Exception wie in Python lieber als ein
amoklaufendes Programm.
-
Möchte man in Perl zwei Listen mit return als Funktionsergebnis
zurückgeben, so muss man eine andere Syntax verwenden, als wenn man
zwei Strings oder Integerwerte zurückgibt:
# Perl
sub return_two_lists{
my @list1;
my @list2;
# .... Listen füllen
return (\@column_alignments, \@widths);
}
my ($list1_ref, $list2_ref) = return_two_lists();
my @list1 = @$list1_ref;
my @list2 = @$list2_ref;
In Python ist die Syntax einheitlich: Es ist gleich ob man Listen,
Dictionaries, Integers, Methoden oder sonstige Objekte zurückgibt.
# Python
def return_two_lists():
list1=[]
list2=[]
# .... Listen füllen
return (list1, list2)
(list1, list2) = return_two_lists()
- Exceptions sind in Python ein fester Teil der
Programmiersprache, in Perl nicht. Objektorientierte Exceptions sind
in Perl auch möglich, doch einiges umständlicher. Siehe Object
Oriented Exception Handling in Perl.
Die Standards ISO-C und POSIX definieren sehr häufig, dass
bei einem Fehler eine Funktion -1 zurückgibt. Perl übernimmt das
leider und überlässt es dem Programmierer, den Rückgabewert fast
aller Funktionen abzufragen. Siehe "perldoc -f" von read, print,
open, ...
In Python wird im Fehlerfall (Festplatte voll, Datei nicht
vorhanden, kein Speicher mehr verfügbar, Broken Pipe) eine Exception
(Ausnahme) erstellt.
- Folgender Perl-Schnipsel existiert häufig in Skripten:
open (FD,"$FILENAME") or die "Can't open file $!";
Mir gefällt die Python-Variante besser:
fd=open(filename)
Man kann sich das 'or die "Can't open file $!";'
sparen. Wenn die Datei nicht geöffnet werden kann, erhält man
außerdem nicht nur die aktuelle Zeile angezeigt, sondern einen
Stacktrace, der auch die Zeilen der aufrufenden Funktionen
beinhaltet.
- Das zeilenweise Lesen von einem Filedescriptor ist nur scheinbar einfach.
# Perl Variante 1
# Naive Variante: IO-Fehler werden nicht bemerkt:
open FD, "test.txt" or die $!;
while ($line=<FD>) {
print "line $line";
}
close FD;
# Perl Variante 2
# IO-Fehler werden bemerkt, aber falls die letzte Zeile
# nicht mit einem Newline Zeichen endet, kommt es zu einem
# Fehler
open FD, "test.txt" or die $!;
for (;;) {
undef $!;
unless (defined( $line = <FD> )) {
die $! if $!;
last; # reached EOF
}
print "line $line";
}
close FD;
Leider funktioniert obiges Beispiel nicht, wenn die letzte Zeile nicht mit einem Newline endet ...
In Python ist das einfach:
# Python
# Bei IO-Fehlern erhält man eine Exception
fd=open("test.txt")
for line in fd:
print "line %s" % line
fd.close()
- Unicode ist ein fester Bestandteil von Python. In Perl ist
Unicode erst über externe Module verfügbar. Beispiel: Die im
üblichen Methoden zum Bearbeiten von XML-Dateien (SAX/DOM) geben
nicht Unicode Zeichenketten sondern als UTF8 kodierte Bytefolgen
zurück.
- Zwei Operatoren für die Negation:
if (! "a" eq "b") {
print "a!=b !\n";
}
if (not "a" eq "b") {
print "a!=b not\n";
}
Beide If-Anweisungen sehen ähnlich aus. Da "not" und "!" jedoch
andere Prioritäten haben, verhält sich die erste Anweisung nicht
wie man es vermutet.
-
Der in-Operator von Python ist kinderleicht:
zutat="Käse"
pizza=["Teig", "Tomatenmark", "Käse", "Salami", "Thunfisch"]
if zutat in pizza:
print "lecker!"
In Perl gibt es den in-Operator nicht. Die Lösung ist umständlich
(entsprechender
FAQ Eintrag):
$zutat="Käse";
@pizza=qw(Teig Tomatenmark Käse Salami Thunfisch);
if (grep $_ eq $zutat, @pizza) {
printf("lecker!\n");
}
- Die open Funktion in Perl ist unsicher. In vielen Perl-CGI
Programmen kann auf dem Server beliebiger Code ausgeführt werden,
in dem z.B. folgender Dateiname übergeben wird:
"dummy.config | rm -rf /"
Die Funktion open öffnet "magischerweise" auch Pipes. In Python hat
das Öffnen von Pipes den Namen, den auch die POSIX-Spezifikation
verwendet: popen.
- Das Python Modul cgitb (CGI
Traceback) ist genial. Beim Entwickeln von Webanwendungen, will man
bei einem Fehler sofort sehen wo dieser Fehler aufgetreten ist, und
mit welchen Werten die Variablen belegt sind.
Hier ein
Beispiel: cgitb Beispiel
Ein schwacher Trost für Perlanwendungen:
use CGI::Carp qw(fatalsToBrowser);
BEGIN {
# Stacktrace anzeigen.
$SIG{__DIE__} = sub { CGI::Carp::confess @_ };
}
- Das Auflisten/Auslesen eines Verzeichnisses ist in Perl umständlich:
# Perl
opendir(DIR, $mydir) || die $!;
my @files=readdir(DIR); # Leider inklusive "." und ".."
closedir(DIR);
# Python
files=os.listdir(mydir) # Sinnvollerweise ohne "." und ".."
- Eine Datei auf einmal auf einen String einzulesen ist in Python einfach:
#Python
fd=open('datei.txt')
content=fd.read()
# Perl
open FD, 'datei.txt';
my $file = do { local $/; <FD> };
Es wird der input record seperator indirekt auf 'undef' gesetzt.
Somit wird die gesamte Datei und nicht nur die erste Zeile eingelesen.
Siehe 'man perlvar'. Ich gebe zu, dass es ein Nachteil von Python ist,
dass der input record seperator nicht geändert werden kann.
- Der Zugriff auf den Zeitstempel einer Datei ist in Python einfacher:
# Python
import os
mtime=os.path.getmtime(file)
# Perl
$mtime = (stat $file)[9];
# Oder besser, mit CPAN Modul
use File::stat;
$mtime=stat($file)->mtime
- Falls es sinnvoll ist, weicht Python von dem POSIX-Standard ab:
<time.h>
tm_mon The number of months since January, in the range 0 to 11.
tm_year The number of years since 1900.
Perl übernimmt das 1:1.
Bei Python:
time.localtime():
tm_year for example, 1993
tm_mon range [1,12]
- Die bei Perl mitgelieferte Dokumentation sind man-Pages. Die
Dokumentation für Python ist als HTML und PDF verfügbar.
- Bricht man ein Perl-Script mit STRG-C ab, erfährt man nicht, an
welcher Stelle das Script beendet wurde. Bei Python erhält man einen
aussagekräftigen Traceback. Das ist besonders sinnvoll, wenn ein
Script in einer Endlosschleife hängt oder unerwartet lange für eine
Schleife benötigt.
- Python kommt mit "Batteries included". Das soll heißen, dass die
mitgelierte Standardbibliothek den Programmierer in die Lage
versetzt sofort Anwendungen zu entwickeln. Der Funktionsumfang von Perl
ist einiges geringer. Die meisten Bibliotheken von Perl muss man
sich erst von CPAN besorgen.
- Die Entwickler von Perl arbeiten kräftig an der nächsten Version:
Perl6. Mit dieser Version soll vieles anders werden. Doch wenn damit
vieles anders werden soll, ist doch an dem derzeitgen Perl vieles
falsch, oder?
Mit "use strict;" lassen sich einige der Schwachstellen von Perl
abschalten. Man kann jedoch nicht davon ausgehen, dass fremder
Quelltext "use strict" verwendet.