Kriterien für eine gute Programmiersprache
Es gibt natürlich eine Reihe von Kriterien. Sicherlich wird der eine oder andere die Codegeschwindigkeit und Größe hervorheben – bald kommt man dann aber auf hersteller- bzw. Plattformspezifische Implementierungen. Man muss dazu nur mal ein einfaches „Hello World“ mit einem C-Compiler erzeugen und hat ein Programm das um ein vielfaches größer ist als dasselbe vor 20 Jahren unter DOS.
Natürlich gibt es noch die Eignung der Sprache – es gibt Scriptsprachen für die Kommandoshell, Sprachen die im Browser ablaufen und Sprachen mit denen man EXE Dateien oder andere Binarys erzeugt. Aber gehen wir mal von der technischen Seite weg, auf die Sprachdefinition. Für mich ist an einer Sprache folgendes wichtig:
Eine gute Sprache ist logisch durchdacht. Nun sind das wird der eine oder andere sagen alle Sprachen nach der BNF oder für die es eine exakte Grammatik gibt. Das muss aber nicht logisch durchdacht sein. logisch durchdacht ist z.B. das Schlüsselworte oder verwendete Zeichen eine gleiche (oder wenn mehrfach verwendet) ähnliche Bedeutung haben.
Meine Negativbeispiele kann ich hier leicht aus der Sprache „C“ ziehen. Da ist mal das Komma ein Separator von Werten und mal ein Operator, was wirklich tolle Ergebnisse und viele Stunden mit einer spannenden Fehlersuche verursachte. z.B. ist:
a = feld [i,j];
a = feld [i][j];
nicht das gleiche…. dasselbe kann man über das Multiplikationszeichen sagen, das mal eine Multiplikation durchführt und mal eine Referentierung.
Auf der anderen Seite wird je nachdem ob man es mit einem Zeiger oder einer Variablen zu tun hat auf die Elemente eines Records mal mit „.“ und mal mit „->“ zugegriffen. Ist echt logisch.
In diesem Zusammenhang halte ich überhaupt nichts von Sprachen ohne Typisierung, weil Typen ja nicht nur Konstrukt einer Sprache sind sondern sich auch im täglichen Leben wiederfinden. Wir nennen sie dort Kategorien. Da gibt es Zahlen oder Texte, Autos oder Häuser. Zahlen kann man addieren, Texte verknüpfen. Autos haben die Eigenschaft PS, Fabrikat, Häuser die Eigenschaften Quadratmeter, Bewohner u.a.
Eine Sprache die keine Typisierung kennt, lässt es zu einer Stringvariablen eine Zahl zuzuweisen und umgekehrt. Besonders tolle Sprachen lassen so was zu:
a=“ab“
a= a+1
Ratet mal was raus kommt….
Kriterium 2: Eine Sprache soll so umfangreich sein, dass man alles damit erledigen kann, aber so klein, dass man sie möglichst schnell verstehen kann.
Was ich damit meine ist, das ein Sprache zum einen so mächtig sein soll, dass alle Sprachelemente zur Verfügung stehen die man braucht, zum anderen aber auch sie nicht unnötig kompliziert ist. Der Mittelweg zu finden ist schwierig und was nötig ist, ändert sich auch im Laufe der Zeit. So haben ältere prozedurale Sprachen noch nicht als Datentyp die Map, oder das assoziative Array. Das ist in vielen Dingen wo man auf Daten nicht mit Indexen zugreifen kann sehr nützlich. Dagegen finde ich die auch in diesen Sprachen nicht vorhandene for-each Schleife nicht so nützlich, dass sie unbedingt dazu gehören müsste.
Pascal (im Wirth Standard) mangelt es sicher an einigen nützlichen Dingen wie vernünftigen Strings. Auf der der anderen Seite hat C so viele Features die Abkürzungen sind aber nicht unbedingt notwendig für eine Sprache wie die Möglichkeit der Zuweisung in der If Anweisung, die Inkrement und Dekrement Operatoren oder die Kombination Operator mit Zuweisung. Alle diese sind durch etwas mehr Schreibarbeit ersetzbar.
Ein sehr interessanter psychologischer Aspekt ist ja das viele Programmierer glauben, dass kurzer Code, am besten noch etwas kryptisch geschrieben, schneller wäre. Siehe Alexanders Beispiel. Wie das Programm von mir beweist, das deutlich länger ist muss das nicht der Fall sein. Vieles hängt davon ab wie ein Compiler den Quelltext übersetzt, aber auch wie effizient eine Programmiersprache implementiert werden kann. Im C-Beispiel ist es per Definition so, dass das Stringende gesucht werden muss da es durch die binäre Null markiert ist. Egal wie man nun im beispiel daran einen neuen String anhängt – die Suche dauert immer länger je länger der String ist.
Ich habe schon während des Studiums und dann während der Diplomarbeit Sprachen verglichen. Bei der Diplomarbeit C#, Java und Delphi. Es zeigte sich dass bei dem elementaren Operationen ohne Ausgabe es praktisch keine Unterschiede in den Laufzeiten gab. Diese kamen erst auf als es auf die grafische Ausgabe ging, wobei die beiden interpretierten Sprachen deutlich langsamer waren, und das trotz C# Mogeltrick mit der Garbage-Collection.
Kriterium 3: Eine Sprache ist syntaktisch so aufgebaut dass man sie ohne viel Nachdenken lesen kann.
Ich muss sagen das Kriterium 3 mich bis heute abgehalten hat viele Sprachen zu lernen. Ich denke es ist möglich eine Programmiersprache so grammatikalisch auszulegen, dass der Quelltext auch für nicht Programmierer verständlich ist. Ich denke das ist bei Pascal oder Modula, aber auch andere Sprachen gegeben. Das kann geschehen durch geschickte Wahl der Schlüsselwörter und vermeiden von zu vielen Operatoren die man erklären muss. Auf der anderen Seite gibt es das Gegenbeispiel einer Sprache die zu schwafelig ist. Ich rede von COBOL: Wenn man selbst +, *, – und / durch Worte ersetzt verzichtet man auf die Grundkrenntnisse der Mathematik die jeder hat und macht den Quelltext schwer lesbar.
Doch das ist die Ausnahme. Der Trend geht heute eher dazu dass Sprachen eher wenige Schlüsselwörter haben und vieles mit Operatoren definiert wird. Perl ist so ein Beispiel. Aber auch Smalltalk hat nicht sehr viele Schlüsselwörter. Dann gehört viel Wissen dazu um einen Quelltext zu verstehen. Man kann aber auch für Profis das Lesen erschweren, z.B. so:
#include <stdio.h>
main(t,_,a)
char *a;
{return!0<t?t<3?main(-79,-13,a+main(-87,1–_,
main(-86, 0, a+1 )+a)):1,t<_?main(t+1, _, a ):3,main ( –94, –27+t, a
)&&t == 2 ?_<13 ?main ( 2, _+1, „%s %d %d\n“ ):9:16:t<0?t<-72?main(_,
t,„@n’+,#’/*{}w+/w#cdnr/+,{}r/*de}+,/*{*+,/w{%+,/w#q#n+,/#{l,+,/n{n+\
,/+#n+,/#;#q#n+,/+k#;*+,/’r :’d*’3,}{w+K w’K:’+}e#‘;dq#’l q#’+d’K#!/\
+k#;q#’r}eKK#}w’r}eKK{nl]’/#;#q#n‘){)#}w‘){){nl]’/+#n‘;d}rw‘ i;# ){n\
l]!/n{n#‘; r{#w’r nc{nl]’/#{l,+’K {rw‘ iK{;[{nl]’/w#q#\
n’wk nw‘ iwk{KK{nl]!/w{%’l##w#‘ i; :{nl]’/*{q#’ld;r‘}{nlwb!/*de}’c \
;;{nl‘-{}rw]’/+,}##’*}#nc,‘,#nw]’/+kd’+e}+;\
#’rdq#w! nr’/ ‚) }+}{rl#'{n‘ ‚)# }’+}##(!!/“)
:t<-50?_==*a ?putchar(a[31]):main(-65,_,a+1):main((*a == ‚/‘)+t,_,a\
+1 ):0<t?main ( 2, 2 , „%s“):*a==‚/‘||main(0,main(-61,*a, „!ek;dc \
i@bK'(q)-[w]*%n+r3#l,{}:\nuwloca-O;m .vpbks,fxntdCeghiry“),a+1);}
Hier das Programm zum Runterladen. Es drückt meine gesamte Begeisterung für C aus….
Ich konnte mich weder mit Smalltalk noch mit Pearl anfreunden und auch einen Artikel über Haskell in der ct fand ich interessant, aber der Einstiegsaufwand ist zu hoch. Es geht darum eine komplett neue Syntax zu erlenen und bisherige Sprachkonzepte kann man vergessen. Vor allem ist aber ein Listing nicht für einen nicht mit der Sprache vertrauten kaum verständlich, während ich behaupten würde das dies bei Pascal nicht so ist.
Wie schon abgekündigt habe ich morgen Vorlesung, sodass es keinen Beitrag gibt, sondern wahrscheinlich erst am Samstag oder Sonntag wieder.
Wow, schon fast Abend und noch keine Antworten?! – Das werde ich mal ändern. 😉
Zur Typisierung: Dazu fällt mir ein, das mich dieses Konzept zu Anfang irgendwie gestört hat. Mit der Zeit ist es mir allerdings klar geworden, aber sehe ich das lockerer. Für eine Skriptsprache, die in erster Linie zur Ablaufsteuerung von Verwaltungsaufgaben, also Batchjobs gedacht ist, halte ich sie für nicht unbedingt nötig. Allerdings sollte man damit auch keine Anweisungslisten (bzw. Programme) von mehr als ca. 100 Zeilen schreiben. Alles was länger ist, sollte dann nur aus den immer gleichen Befehlen bestehen, die lediglich andere Parameter haben.
> Besonders tolle Sprachen lassen so was zu:
>
> a=â
Irgendwie scheint der Parser, der die Kommentare entgegen nimmt, etwas gegen Plus-zeichen zu haben. so hab ich im Text mal „i=i plus 1″ geschrieben, heraus kam „i=i 1“.
Ich finde eigentlich gerade die „Modifikationsoperatoren“ (sterngleich, plusgleich etc.) aeussert logisch.
Denn es ist ja etwas voellig anderes, ob ich einer Variablen einen Wert zuweise (a gleich 5), oder sie modifizieren will (z.B. a plusgleich 5). Da finde ich die „normale“ (Pascal-)Schreibweise (a gleich a plus 5) hingegen aeusserst seltsam, und das ging mir schon immer so.
Ich will ja a keinen neuen Wert geben, sondern den bestehenden modifizieren…
Und frueher kam natuerlich noch hinzu, dass der Compiler mit dem plusgleich Operator gleich wusste, dass er keine Register oder gar Speicherzellen durch die Gegend schieben muss, sondern nur ADD EAX,5 o.ae. machen muss 🙂
Wobei ich meinen wuerde, dass es selbst heutzutage nicht trivial ist, einen Parser zu schreiben, der bei der a gleich a plus fuenf Schreibweise immer erkennt, dass man modifizieren will und nicht zuweisen…