Hadmut Danisch

Ansichten eines Informatikers

Suche

Kategorien

Spenden

Wer mein Blog unterstützen möchte, kann spenden:


Per Überweisung:
Hadmut Danisch
Berliner Bank
Konto 305193500
BLZ 10070848
IBAN DE45100708480305193500
BIC/SWIFT DEUTDEDB110


Per Paypal:


(Paypal zieht Provision ab)

Kritik an der Programmiersprache Scala

Hadmut
15.5.2011 21:34

Die von Professor Martin Odersky (derzeit Swiss Federal Institute of Technology in Lausanne (EPFL)) entwickelte Programmiersprache Scala wird derzeit als Nachfolger von Java heiß gehandelt.

Hier meine Einschätzung zu Scala, ein Review.

Vorbemerkung:

Die meisten Teile dieses Blog-Artikels habe ich im Sommer/Herbst 2010 geschrieben (oder inhaltlich erarbeitet). Aufgrund anderer, dringlicherer Aufgaben und einer Reise ist die Sache dann etwas liegengeblieben. Zudem habe ich überlegt, den Artikel nicht auf deutsch, sondern in meinem geplanten englischsprachigen Blog aufzunehmen, was aber noch eine Weile dauern wird.

Aufgrund einer aktuellen Meldung auf dem Heise Newsticker (vgl. auch diese ältere Meldung der iX zur EU-Förderung) ist mir eingefallen, daß ich da ja noch was liegen habe, was ins Blog will. Da ich nun nicht alles neu nachlesen und ausprobieren möchte, sind einige Aussagen hier auf dem Stand von Herbst 2010 und möglicherweise nicht mehr so ganz aktuell, zumal inzwischen gegenüber der von mir verwendeten Version 2.7.7 zwei neuere Versionen von Scala verfügbar geworden sind, 2.8 und 2.9.

Warum eine Kritik an Scala?

Sprach-Hintergrund und Maßstab

Ich bin Informatiker und habe vor über 30 Jahren mit dem Programmieren angefangen. Mit wievielen Programmiersprachen ich mich bisher befasst habe, weiß ich nicht mehr, über 30 werden es gewesen sein, davon habe ich mit mehr als einem Dutzend konkret programmiert. Ad hoc fallen mir da C, C++, Basic, Pascal, Algol, Modula-2, Occam, Fortran, Cobol, Smalltalk, PL/I, APL, Ada, Occam, Perl, PHP, Java, JavaScript, Tcl, Shell, Postscript, Ruby, Forth, Lisp, Scheme, Prolog ein, dazu Assembler Z80, 6502, 65000, VAX, Sparc, T800, 68000, 56001, MiniMa. (Die Lust am Assembler ist mir allerdings mit dem chaotischen und un-orthogonalen x86-Befehlssatz nachhaltig vergangen.)

Die meisten dieser Sprachen halte ich historisch und evolutionär für sehr wichtig, aber inzwischen für veraltet und eigentlich obsolet – wenn wir denn was besseres hätten. Ihr Nutzen besteht heute darin zu lernen, was man besser machen kann und muß.

Beispielsweise war C damals eine ganz tolle Sprache, die für mich erste, in der man knackig programmieren konnte. Ohne C hätte es kein Unix und damit kein Linux gegeben. Aber C war und ist auch primitiv, kaum mehr als ein verallgemeinerter Assembler. C war eben ein Produkt des Zeitalters der knappen Resourcen – Rechenzeit, Speicher, Compilerzeit, Entwicklungszeit – und der Frühzeit der Programmiersprachen. Was damals ein Riesenfortschritt war, ist heute eine Sicherheitskatastrophe, und die meisten Sicherheitsprobleme gehen auf die in C völlig fehlenden Sicherheitsmechanismen zurück. Die Standardbibliothek ist voller Entwurfsfehler und Sicherheitslücken, und die von C++ ist katastrophal schlecht.

Dummerweise konzentriert man sich heute aber nicht darauf, eine gute Sprache zu produzieren, sondern viele schlechte (Nischen-)Sprachen. Wer was auf sich hält, produziert heute irgend eine Sprache für irgendein Problem und bringt irgendein Buch darüber in den Buchhandel. Allein zum Design von Webseiten müßte man im Prinzip PHP, Java und JavaScript beherrschen, die alle zueinander inkompatibel sind und alle ihre Spracheigenheiten haben. Wenn ich heute in eine gut sortierte Buchhandlung gehe und mir das Bücherregal zu Programmiersprachen anschaue, dann habe ich von vielen der Sprachen, über die da Bücher stehen, noch nie was gehört – und will auch nichts darüber hören.

Außerdem habe ich die Universität 1998 verlassen und bin seither in der Industrie tätig, und habe dadurch eine andere Sichtweise und andere Anforderungsmaßstäbe erlangt (gewonnen). Scala ist dagegen ein Produkt aus dem akademischen Universitätsbereich.

Java

1997 habe ich die damals neue Programmiersprache Java ausprobiert und war von der Idee begeistert, im Browser Mini-Applikationen laufen zu lassen. Damit wollte ich meine Krypto-Vorlesung an der Uni mit Animationen und Experimenten zur Nachbereitung für die Hörer aufpeppen: Handchiffren, die Enigma, Kryptoanalyse usw. wollte ich nicht als dröges Skript, sondern gleich zum Ausprobieren anbieten.

Nach den ersten Applets habe ich mich jedoch mit Grausen abgewandt und Java seither nicht mehr angerührt – viel zu ungelenk, plump, umständlich war Java. Zu deutlich merkte man, daß die Entwickler von Java kein Sprachgefühl und sich nur an C orientiert hatten, und daß nicht der Compiler nach der Sprache gebaut war, sondern umgekehrt die Sprache auf das beschränkt war, was die Macher damals als Compiler zustandebrachten. Schon für einfache und kleine Algorithmen programmmierte man sich in Java die Finger wund, und sehr unleserlich war es obendrein.

Java war keine ordentliche Programmiersprache, sondern ein proof of concept, der zu früh und unreif dem Labor entlaufen war. Ich habe nie verstanden, warum so viele Leute, Firmen, Universitäten auf Java gesprungen sind. Lag es vielleicht daran, daß die meisten Informatiker und Programmierer auf einem so niedrigen Ausbildungsstand sind, daß sie solche stark auf das nötigste beschränkten und simplen Sprachen bevorzugen (was durchaus der Fall zu sein scheint und den Erfolg von C und den sehr fragwürdigen Erfolg von PHP erklärt)? Beruht der Erfolg von Java allein in der Anspruchslosigkeit der Anwender?

Ruby

Die Sprache, mit der ich aktuell am zufriedensten bin, ist Ruby. Ruby ist sehr leistungsfähig, man kann unglaublich dicht und knapp, und trotzdem einfach und sehr lesbar, fehlerarm, beeindruckend elegant, schnell und schön programmieren. Ruby ist in meinen Augen die derzeit mit Abstand geilste Programmiersprache. In Ruby kann man Software so unglaublich prägnant und elegant hinschreiben, daß es eine Freude ist. Dazu kommt eine wirklich gut durchdachte und sehr gut strukturierte und umfangreiche Laufzeitbibliothek. Ruby macht einfach Spaß. Aber Rubys Konzept bringt leider auch deutliche Nachteile mit sich:

  • Ruby ist eine Interpretersprache und dadurch sehr langsam.
  • Ruby hat keine Typbindung und keine Deklaration, sondern macht alles dynamisch unbekümmert und setzt auf das sog. Duck-Typing. Damit kann man zwar unglaubliche Dinge tun – aber auch deftige Fehler bauen, die jeder Compiler sofort erkennen würde.
  • Es gibt keine API-Definitionen (Java: Interfaces). Man schreibt einfach was hin und hofft auf die eigene Disziplin.

Und deshalb „skaliert” Ruby nicht. Zur Man kann keine großen Projekte schreiben. Man klopft irgendwas zusammen und zur Laufzeit zeigt sich dann, ob es geht oder nicht. Grenzenlosigkeit als Philosophie.

Deshalb bin ich auf der Suche nach einer Sprache, die Ruby möglichst nahe kommt, besonders was die Syntax und die Laufzeitbibliothek angeht, aber Rubys Nachteile vermeidet. Also quasi Ruby mit fester Typbindung und API-Definitionen als Compilersprache. Eine ordentliche Sprache, die auch für größere Projekte taugt. Das wär’s.

Odersky gibt zu Scala bisweilen an, sich auch an Skriptsprachen wie Ruby orientiert zu haben, wovon ich allerdings wenig bis gar nichts bemerkt habe. Das scheint mehr eine Marketing-Aussage zu sein. Im Vorgriff auf meine Bewertung muß ich sagen, daß es hier deutlich besser gewesen wäre, gut von Ruby zu plagiieren, als es schlecht selbst zu machen.

Warum nun doch zur Java Virtual Machine und warum Scala?

Im Sommer/Herbst 2010 stand ich vor drei Problemen, die alle auf eine Programmierung unter der JVM hinausliefen:

  • Ich wollte mich mit der Android-Programmierung befassen, die auf der JVM aufbaut (genauer gesagt wird dort eine andere Maschine verwendet, aber der Code aus JVM-Code erzeugt, man braucht eine Sprache für die JVM).
  • Ich habe überlegt, mein Blog auf einen Java Servlet Container wie Tomcat zu portieren, weil mir das in PHP geschriebene WordPress auf den Wecker geht.
  • Ich habe damals als Security Manager Schulungen für Webapplikationsprogrammierer geplant, die in Java für Servlet Container programmierten, und mir überlegt, wie ich denen bessere und sicherere Programmierwerkzeuge anbieten kann.

So kam ich trotz meiner Abneigung zwangsläufig wieder zur JVM zurück.

Welche Sprachen bleiben für die JVM? Java selbst finde ich grauslich. Groovy? Nicht ganz schlecht, aber der irgendwie mißlungene Versuch, Ruby mit Java-Syntax zu kreuzen. Ein Nischenprodukt ohne große Zukunftsaussicht, als langsam berüchtigt. JRuby? Käme mir sehr gelegen, weil Ruby auf der JVM, es erzeugt aber keine Java-Klassencode, ist nur schwierig mit anderen Java-Bibliotheken zu verbinden, gilt als langsam und hat wieder die benannten Ruby-Schwächen. Clojure? Ein Lisp-Dialekt. Schauderhaft. Bleibt derzeit also nur Scala.

Scala wird als der Nachfolger von Java hochgejubelt. Was nicht viel heißt, denn fast dieselben Leute haben vorher schon über Java gejubelt, obwohl Java keinen Anlaß zu Jubel gab.

Verwendete Dokumentation zu Scala

Ich habe zum Testen Scala 2.7.7 unter Ubuntu 10.04 und 11.04 und folgende Doku herangezogen (es gibt inzwischen aber weitere freie und käufliche Werke):

Kostenlos zum Herunterladen

Martin Odersky u.a.: Programming in Scala

Ich hatte mir zuerst die erste Auflage (als PDF) gekauft, meine Kritik hier beruht wesentlich auf dieser Auflage. Nach dem Schreiben der meisten Teile dieses Artikels habe ich mir auch die zweite Auflage gekauft, aber keine Lust gehabt, das alles nochmal durchzuarbeiten, weshalb sich die Kritik, die Hinweise und die Seitenzahlen noch auf die alte, erste Auflage beziehen.

Allgemeine Kritik

Hier zunächst eher allgemeine Kritikpunkte.

Absurde Komplexität

Für gewöhnlich lese ich ein Buch über eine neue Programmiersprache an einem Wochenende durch. Dazu schaue ich mir zunächst die Syntax-Beschreibung und die Grundelemente der Syntax an, wie „sieht” die Sprache so aus. Dann lese ich mir in der Dokumentation die Beschreibungen der einzelnen Syntaxelemente durch, die für gewöhnlich in den Büchern zu den Programmiersprachen nach einer Einführung und manchmal einem Kurzüberblick („Hello World!”) hintereinander dargestellt werden. Dazu schaue ich mir dann die Beispiele an und probiere diese aus. Wenn ich das im Griff habe, schaue ich mir die verfügbaren Standardbibliotheken an. Normalerweise habe ich dann nach ein paar Stunden oder Tagen eine neue Programmiersprache so weit drauf, daß ich schon mal anfangen kann, darin zu programmieren. Wenn ich dann mal zwei oder drei Wochen oder Monate in der Sprache programmiert habe, hat sich das Gehirn dann soweit auf den neuen Sprachstil eingestellt (falls es denn überhaupt einen neuen gibt und es nicht der 147. Aufguß einer einfachen prozeduralen Sprache ist, die sich durch nichts als neue Syntax-Varianten von den anderen 146 unterscheidet), daß ich das, was ich bisher in der Sprache geschrieben habe, als nicht richtig zum Stil passend auffassen und korrigieren oder neu schreiben kann oder will.

Bei Scala war das ganz anders.

An dem Scala-Buch von Odersky habe ich wochenlang herumgelesen, immer mal so ein paar Seiten, ohne wirklich voranzukommen. Dadurch bin ich in die dumme Situation gekommen, daß ich im hinteren Ende noch nicht so viel über die Sprache wußte, um beim Programmieren loslegen zu können, während ich schon wieder vergessen habe, was ich vorne gelesen habe, weil ich es noch nicht einsetzen konnte.

Das hat im wesentlichen zwei Ursachen. Einmal die grottenschlechte und vermurkste Dokumentation Oderskys über „seine” Programmiersprache, dazu aber unten mehr.

Und zum anderen eben die Komplexität – nein, eigentlich muß man sagen Kompliziertheit – der Sprache. Scala enthält diverse Sprachkonstruktionen, die nicht nur schwer zu verstehen sind (was auch daran liegt, daß die Komplexität von Scala weitaus höher als die didaktischen Fähigkeiten von Odersky sind, Scala verständlich darzustellen), sondern die in ihrer Denkweise so komplex sind, daß sie für eine Programmiersprache kontraproduktiv wirken.

Ich habe nichts gegen komplexe Programmelemente. Aber sie müssen sich als Vorteil und nicht als Nachteil erweisen. Das heißt,

  • Eine allgemeine Sprache sollte auch für allgemeine Anwendungen gebaut sein. Sprachelemente sollten nicht zur Lösung bestimmter Nischenaufgaben aufgenommen werden – oder zumindest nur zusätzlich zu einem allgemeinen Sprachstock.
  • Es sollte eine klare Trennung zwischen der eigentlichen Syntax und Semantik der Sprache selbst, und der Standardbibliothek geben, auch wenn letztere zur Sprache gehört.
  • Der Arbeitsaufwand zur Nutzung der komplexen Elemente muß niedriger sein, als wenn man es als geübter Programmierer von Hand mit einfachen Standardelementen ausprogrammiert. Es muß die Arbeit erleichtern, und nicht belasten.
  • Es muß so übersichtlich und verständlich sein, daß die komplexen Elemente gegenüber den einfachen Standardelementen das Programm leichter lesbar machen und die Gefahr von Programmfehlern vermindern.
  • Der Aufwand zum Erlernen – und damit die Schwelle – darf nicht zu hoch sein, denn eine Programmiersprache darf nicht nur dem akademischen Lustgewinn dienen, sondern muß auch betriebswirtschaftlichen Anforderungen genügen.
  • Der Portierungsaufwand zwischen den Sprachen – also von und zur Sprache X – darf nicht zu hoch sein. Eine Sprache sollte nicht auf Sprachelementen beruhen, die nur mit großem Aufwand in anderen Sprachen nachzubilden wären, damit man keine Programme schreibt bzw. Algorithmen entwickelt, die nur in genau dieser einen Sprache funktionieren.

Scala erfüllt diese Anforderungen in meinen Augen nicht. Scala macht aus mehreren Gründen auf mich nicht den Eindruck einer systematischen, geschlossenen Programmiersprache, sondern den eines Compilergerüstes, in das man verschiedene Sprachkonstrukte unterschiedlicher Herkunft eingehängt hat, die eher dem Laborversuch, als dem professionellen Programmieren dienen, und die dem zwanghaften (Forschungs-)Druck entstammten, unbedingt Neuigkeiten statt Bewährtem bieten zu müssen. Ich werde dies weiter unten in einigen Details aufgreifen und näher beleuchten.

Generell halte ich Scala deshalb derzeit für nicht wirklich einsetzbar. Nicht, weil man als Informatiker Scala nicht lernen könnte. Kann man schon. Sondern weil es im großen Maßstab, für Industrieanwendungen, im Bereich des bezahlten Massenprogrammierens, nicht effektiv und kosteneffizient einsetzen kann. Den Schulungs- und Kapier-Aufwand schätze ich als betriebswirtschaftlich zu hoch ein, und ich glaube, daß so manche Programmiertruppe (und die bestehen ja meist nicht aus studierten Universitätsinformatikern) damit überfordert ist. Nicht umsonst gehören ganz einfache Sprachen wie C, Java, PHP zu den meistverwendeten. Man braucht daher schon eine gewisse Rechtfertigung, um eine so komplexe Sprache zu bauen.

Schlechte Dokumentation

Oderskys u.a. Buch: Programming in Scala

Eine wesentliche Ursache für meine schlechte Meinung von Scala ist das Buch über Scala, das von Odersky selbst (und anderen) stammt. Das Buch ist herzlich schlecht.

Ich habe hier weit über ein Dutzend Bücher über verschiedene Programmiersprachen im Regal stehen. Die folgen mehr oder weniger alle demselben Schema: Einführung mit „Hello World!”, Kurzüberblick, Vorstellung der Sprachelemente und Grunddatentypen, eins nach dem anderen, mitunter noch eine Sprachreferenz, und eine Übersicht oder Referenz der zur Sprache fest gehörenden Standard-Bibliothek. Das ist schnöde, einfach, billig, ausgelutscht, einfallslos – und sehr bewährt. Es funktioniert einfach. Man kann es schnell lesen, man kann direkt dahin springen, wonach man sucht, man findet sich zurecht.

Das Buch von Odersky hingegen ist anders aufgebaut. Und es funktioniert so nicht. (Ich habe zwar auch die zweite Auflage, aber ich fand schon das Lesen der ersten so zäh, langatmig, schwergängig, daß ich mir das nicht ein zweites Mal antun wollte und mich daher hier auf die erste Auflage beziehe. Die zweite scheint aber nicht besser, sondern nur 100 Seiten länger zu sein.)

Ein Hauptproblem des Buches ist seine Struktur. Das sieht nicht wie ein Lehrbuch oder eine Einführung aus, sondern als ob es aus Vorlesungsfolien oder einem Vorlesungsskript entstanden wäre, wie man am Inhaltsverzeichnis sieht. Da wird ein Thema nach dem anderen in etwa 30 Kapiteln behandelt, und das dann auf jeweils 20-30 Seiten durchgekaut, gerade so, als wäre das Buch eine Mitschrift aus einer 15-wöchigen 4-SWS-Vorlesung. Und innerhalb der Kapitel wird dann ein Thema in zäher Prosa zerrieben, eben als ob man eine 90-Minuten-Vorlesung mit Blabla zu füllen hätte.

Will man sich mit diesem Buch in Scala einarbeiten, muß man den ganzen Schmonzes von vorne bis hinten lesen – 700 Seiten in der ersten Auflage, 800 in der zweiten. Wer soll denn das alles lesen? Man findet auch nicht wirklich was in dem Buch, weil das alles irgendwo in diesem riesigen Sprachschwall versteckt ist. Eine Sprachreferenz? Eine Übersicht der Syntax? Fehlanzeige. (Kann man allerdings separat und kostenlos runterladen.) Oder mal eine saubere, nach Klassen geordnete Übersicht der Standardbibliothek? Is nich.

Das zweite Problem des Buches ist, daß Odersky, bzw. die Autoren, sich nicht entscheiden konnten, ob sie eine Einführung in die Programmiersprache Scala oder ein Evangelium für einen gewissen Programmierstil schreiben wollten. Das ganze ist ein fürchterliches Gemisch aus einer kaum strukturierten, nur aufzählerischen Beschreibung von Scala und ständigen Ermahnungen und Erleuchtungen, wie gutes Programmieren nach Meinung der Autoren aussehen sollte. Das wirklich Dumme daran ist, daß das nicht wirklich gut ist (dazu unten mehr). Diese Vermischung aus zwei völlig unterschiedlichen Themen und Büchern macht dieses Buch so unglaublich langatmig und schwer zu lesen. Die hätten viel besser daran getan, das auf zwei Bücher aufzuteilen, eines über Scala und eines über den von ihnen favorisierten Programmierstil. Dann könnte man das erste flott lesen und das zweite einfach wegwerfen.

Das dritte Problem hängt mit dem zweiten zusammen. Was mich beim Lesen unheimlich genervt hat, war der immer wieder aufflammende missionarische und oberlehrerhafte Stil, der einem einen bestimmten Programmierstil aufdrängen will. Nun habe ich zwar nichts dagegen, wenn jemand guten Programmierstil lehren will, das tut tatsächlich not. Aber ich hatte den beständigen Eindruck, daß weder Scala, noch die Programmierfähigkeiten der Autoren auf einem Niveau sind, bei dem man sich dieses belehrende und besserwisserische Auftreten leisten könnte.

Oder anders gesagt: Die Autoren – wohl vor allem Odersky – leiden unter dem „Schaden”, den sie sich durch den dauerhaften Aufenthalt im Elfenbeinturm geholt haben. Man merkt überaus deutlich, daß die sich hier einen universitätstypischen Vorlesungsstil vor einem Zwangspublikum, das weder fliehen noch kritisieren oder in Frage stellen kann, angewöhnt haben. Wie jemand, der schon so lange aus dienstlicher Stellung heraus Recht hat (weil er in Prüfungen willkürlich selbst beurteilt, was richtig und was falsch ist), daß er inzwischen schon fest glaubt, wirklich Recht zu haben. Wie Vogonen, die vogonische Dichtkunst vortragen.

Dieses Buch entspricht ganz dem Stil der Universitätsbücher, die man nicht kauft, weil sie gut sind oder man will, sondern weil sie auf der Literaturliste der Vorlesung stehen, man sie für die Prüfung braucht (und vielleicht einen Hörerschein bekommt).

Ich kenne die alternativen Bücher der einschlägigen Verlage nicht, aber würde einfach mal blind tippen, daß die viel besser sind, weil die auf normales Publikum ausgerichtet sein müssen.

Das vierte Problem ist nicht spezifisch, sondern ein Problem, was ich im Bereich der IT-Bücher und auch der Open-Source-Szene immer häufiger beobachte: Die Leute können nichts mehr erklären. Stattdessen werden immer mehr und fast nur noch Beispiele gebracht.

Das scheint seinen Ursprung einmal in der amerikanischen Publikationsmode zu haben, bei denen man durch viele Beispiele die Bücher immer fetter aufblähte, während man immer billigere Autoren einstellt, denen die Erklärfähigkeiten fehlen, aber auch in dem anspruchsloseren Massenpublikum. Und in Windows. Seit Windows sind diese Lehrmaterialen groß in Mode gekommen, in denen man gar nichts mehr erklärt (wie auch bei Windows…), sondern nur noch seitenweise Screenshots zeigt, wo man hinklicken soll.

Auch im Scala-Buch von Odersky u.a. fällt mir immer wieder auf, daß sie Strukturen aus Scala nicht erklären, sondern nur vorführen. Hier, so sieht die Struktur aus, probier mal das und jenes, achte auf dieses, das und das sollst Du tun. Ich hatte immer wieder das Problem, daß ich mehrfach vor- und zurücklesen mußte, weil die da im Buch irgendwas vorturnen ohne zu erklären, was da genau abläuft. Entweder soll der Leser anhand des Beispiels selbst erahnen, was da abläuft (was etwa bei den Case Classes so nicht funktioniert), oder er soll es nicht verstehen, sondern einfach tun, was man ihm sagt.

Ich habe – gerade auch wegen der inkonsistenten und überladenen Struktur von Scala – den schweren Verdacht, daß die das bisweilen selbst nicht so richtig verstanden haben und erklären können, weil Scala wohl nicht systematisch, sondern organisch gewachsen ist und sie den Status Quo, aber nicht die Konstruktionsgedanken beschreiben können.

Gerade bei einer komplexen Struktur wie den Case Classes hätte ich erwartet, daß die einfach mal hinschreiben und verbal erklären, was das Ding eigentlich genau macht. Nöh. A simple example, dann wird alles mal vorgeführt, am Schluß ein larger example. Und das Einführungspaper „Scala by Example”. Auch im Reference-Manual gibt es jede Menge Syntax-Bäume und Examples. Aber keine Erklärung, was das System da eigentlich treibt.

Scala by Example

Völlig vom Stuhl gehauen hat mich dann das Paper Scala by Example von Odersky selbst. Sowas abgedreht Bizarres ist mir da noch nicht untergekommen. Als ich das gelesen habe, ging mir unwillkürlich durch den Kopf, daß so ein Autist schreiben würde.

Tatsächlich ist es aber eher so, daß das Paper nicht an die Öffentlichkeit gerichtet ist, sondern auf eine sehr kleine Zahl von Lesern aus einer spinnerten Professorenschaft ausgerichtet ist, von denen jeder so sein persönliches Steckenpferd hat, deshalb irgendeine Exotensprache favorisiert und damit sein Studentenschaft zu dieser Sprache zwingt.

Irgendwo anders stand, daß Scala diesen Zoo aus Akademiker-Sprachen ablösen und durch eine Standardsprache ersetzen soll (was ich als zentralen Entwurfsfehler von Scala ansehe). Man merkt beim Lesen des Papers förmlich, wie Odersky so reihum einzelne Wissenschaftler damit anspricht und jedem darlegt, daß auch sein persönliches Steckenpferd und Hobby in Scala aufgenommen wurde und er deshalb von seiner bisherigen Lieblingssprache zu Scala wechseln kann.

Anstatt einfach mal ein paar vernünftige Beispiele zu bringen (wie der Titel verheißt), kommt nur theorielastiges Zeug.

Da wird gleich zu Anfang mit Actors und Messages herumhantiert, was für mich beim ersten Lesen schlichtweg nicht nachvollziehbar war. Zudem war für mich nicht klar, was der Vorteil dessen gegenüber einer herkömmlichen Objekthierarchie sein soll.

Später kommt ein lausiges Beispiel dafür, wie Scala die (angebliche) Rekursion für factorial (Fakultät) von Scala in eine Endrekursion aufgelöst und abgewickelt wurde. Was Bockmist ist, denn die Funktion für die Fakultät ist eigentlich keine Rekursion sondern eine Iteration. Und diese durch funktional-dämliches Programmieren erst zur Rekursion zu machen um sie dann vom Compiler per Endrekursion wieder aufwickeln zu lassen, ist blöde. Aber da mußte wohl auf Teufel komm raus ein Beispiel für Endrekursionsauflösung rein, um irgendwen von Scala zu überzeugen, der auf sowas steht.

Ein anderes schlechtes Beispiel ist 5.2 Currying. Schon mal gehört, den Begriff? Ich bis dahin jedenfalls nicht. Odersky schafft es, ein ganzes Kapitel über Currying zu schreiben, ohne ein einziges Mal zu sagen (bzw. erst am Ende anzudeuten), was das eigentlich genau ist. Woran man schon merkt, welche enormen didaktischen Probleme Odersky haben muß. Ich hab’s damals mal nachgelesen. Ist nicht wichtig, braucht man im Normalfall nie. Es hat mit mathematischen Funktionenklassen zu tun und erfüllt folgende drei Zwecke:

  • Akademische Selbstbefriedigung
  • Die Verwirrung zu heben und die Lesbarkeit zu senken, auf Kosten der Fehleranfälligkeit
  • Programme zu schreiben, die man nicht in andere Sprachen portieren kann

Was soll der allgemeine Leser mit so einem Beispiel wie dem zu Currying anfangen können? Das ist ganz offensichtlich auf einen ganz eng beschränkten Anwenderkreis – vornehmlich der Mathematik – und vermutlich auf ein oder zwei Zielpersonen ausgerichtet, die von Currying feuchte Träume bekommen und deshalb bisher auf irgendeine Spezialsprache abfahren.

Dazu kommt eine ziemlich verquaste Wissenschaftssprache, die vor lauter Exaktheit kaum in der Lage ist zu sagen, was sie will. Da steht jemandem seine eigene „Wissenschaftlichkeit” im Weg, von der dann auch nicht mehr viel übrig bleibt als nur die Unfähigkeit, sich noch normal auszudrücken. Dieses Paper hinterläßt bei mir außerdem den nachhaltigen Eindruck, daß Odersky nicht zwischen Theoretischer Informatik, akademischer Softwaretechnik und einer realen Programmiersprache unterscheiden kann (und will).

An welches Publikum schreibt der eigentlich?

Den Zweck, jemanden vom Gebrauch der Sprache zu überzeugen, dürfte das Paper wohl nur bei einer Hand voll akademischer theoretisch orientierter Käuze erfüllen. Auf die Mehrzahl der Leser dürfte das Paper ziemlich abstoßend wirken. Nicht mal mir macht sowas Spaß, obwohl ich Informatiker bin und mich früher durchaus sehr für theoretische Informatik begeistert habe.

Wenn ich mir allerdings vorstelle, daß ich mit diesem Paper in eine Firma gehen und gewerbliche Programmierer davon überzeugen sollte, auf Scala umzusteigen – die würden mich auslachen und für verrückt erklären. Ich habe eingangs geschrieben, daß einer der Gründe, mich mit Scala zu befassen, war, daß ich damals eine Reihe von Sicherheitsschulungen für ein Rudel Java-Programmierer in einer Firma geplant hatte. Hätte ich denen sowas vorgeschlagen, wäre der Workshop geplatzt.

Als nützlich erscheint mir dieses Paper nur in einer Hinsicht. Man bekommt anhand der Beispiele ein sehr deutliches Gefühl dafür, welche Sichtweisen und Motivationen hinter der Entwicklung von Scala stehen – und warum Scala daran leidet, woran es leidet. Insofern ist der Titel „Scala by Example” gar nicht mal so verkehrt. Nur anders, als der Autor sich das dachte.

Fragwürdige Standard-Bibliothek

Zwar betonen die Autoren im Buch mehrfach, daß viele Sprachelemente in Wirklichkeit nicht Teil der Syntax seien, sondern nur Teil der Standard-Bibliothek, die unter Ausnutzung von Scala so wirkt, als wären es Syntax-Elemente.

Aus technischer Sicht ist das keine schlechte Idee. Irgendwelche Sonderlocken in die Bibliothek zu packen ist immer besser, als in die Sprache selbst irgendwelche Spirenzchen einzbauen.

Schlecht daran ist aber, daß im Buch dann nicht klar dargestellt und vor allem nicht inhaltlich unterschieden wird, was nun Sprache und was Standard-Bibliothek ist. Denn aufgrund der unsystematisch-aufzählenden Struktur des Buches und der Komplexität (um nicht zu sagen Undurchsichtigkeit) der Sprache, kann man das nicht ohne weiteres selbst ersehen, wenn man die Sprache noch nicht ganz genau kennt.

Und dann kommt eben dazu, daß die Autoren nicht erst die Sprache und dann die Bibliothek, sondern nach Kraut und Rüben schreiben (bzw. sich an ihrer Programmierstilmission hochziehen). Insofern ist es ziemlich schwer, sich da ein Bild über die Standard-Bibliothek zu machen. Die Autoren machen jedenfalls kein schlüssiges Bild.

Insgesamt macht das, was ich nun für diese Bibliothek halte, auf mich einen ziemlich aufaufgeräumten, inkonsistenten, unlogischen und damit vermurksten Eindruck. (Vor allem, wenn man die exzellente und hervorragend strukturierte Bibliothek von Ruby gewöhnt ist.)

So gibt es vom Datentyp der linearen Sammlung nicht ein oder zwei, sondern sage und schreiben mindestens (evtl. mehr) 10 verschiedene Datentypen, nämlich

  • array
  • list
  • listbuffer
  • arraybuffer
  • mutable queue
  • immutable queue
  • mutable stack
  • immutable stack
  • strings
  • tuples

und alle sind sie zueinander inkompatibel. Mal fügt man neue Elemente mit += an, mal mit enqueue und mal mit ::. Und man findet sie nicht einmal beieinander oder im Vergleich im Handbuch, sondern das eine ist mal da und so, das nächste woanders und anders beschrieben, und so weiter. Man muß das ganze Buch lesen, um an allen mal vorbei zu kommen, und dann ist man auch nicht schlauer, sondern nur verwirrt. Daß man die vielleicht mal alle in einem Kapitel zusammenstellt und tabellarisch deren Eigenschaften und Operatoren vergleicht, das kommt denen wohl nicht in den Sinn. Es riecht danach, als ob diese diversen Datentypen von verschiedenen Leuten implementiert wurden, die sich nicht miteinander abgesprochen haben (die Sache mit den Köchen und dem Brei).

Als Informatiker würde ich sagen, daß das so richtiger Murks ist. Vor allem sollte man die Implementierung immer von der Schnittstelle trennen, das heißt, daß man nur eine Art hat, einen Array zu benutzen, und dann beim Anlegen über einen Parameter auswählt, welche Implementierung dahinterstecken soll. Aber nicht so, das ist einfach nur Mist. Das ist, als hätte jemand im Labor verschiedene Dinge experimentell ausprobiert und hinterher nicht saubergemacht, sondern den Dreck liegen lassen.

Daß man hier mehrere Datentypen braucht, ist unvermeidlich, denn man muß ja auch die alten Datentypen zur Kompatibilität mit Java unterstützen. Aber so viele neue Typen müssen es nicht sein. Und daß jede dieser Listen andere Operatoren verwendet, ist unvertretbar.

Wie inkonsisent das alles ist, merkt man auch an vielen Unlogiken. So haben sie Listen wie in LISP, wo man mit :: zusammenkleistert und mit car und cdr herumhantiert, einen erheblichen Aufwand treiben muß, um das vorderste Element zu entfernen, oder nicht trivial am Ende anhängen kann. (Sie empfehlen allen Ernstes, die Liste verkehrtherum aufzubauen und dann am Ende zu invertieren, weil das einfacher wäre. Solche Listen besser zu implementieren ist eine Übungsaufgabe für das Vordiplom.) Auch hier wieder das Problem, daß sie Datentyp und Implementierung nicht auseinanderhalten können.

Man muß allerdings dazusagen, daß ich auf der Scala-Webseite letzten Herbst irgendwo eine kurze Notiz gesehen habe (ein ganz kurzes Paper), wonach man selbst damit unzufrieden sei, das Problem erkannt habe und an einer Verbesserung arbeite. Leider finde ich das Paper gerade weder bei meinen Downloads, noch auf dem Server wieder.

Aber so programmiert man das nicht. Das ist Pfusch.

Seltsamkeiten

Was ich im Zusammenhang mit diesen Datentypen auch nicht verstanden habe: Eine immutable Map braucht kein Import, sondern ist der Sprache allgemein bekannt. Eine mutable Map braucht einen Import. Beide heißen aber Map. Wie kommt man an die immutable Map, falls man einmal die mutable Maps importiert hat? (vgl. Buch 1. Auflage Seite 84)

LISP

Scala stinkt an zu vielen Stellen nach LISP. LISP ist nicht gesund. Und LISP ist auch nicht toll.

Rechtslage

Was mir auch nicht klar ist, weil ich mehrfach danach gesucht aber nichts gefunden habe, ist die Urheber-, Nutzungs- und Lizenzlage.

Wenn man in Scala Software schreibt, hat man zwangsläufig Code-Stücke aus dem Compiler, der Laufzeit- und der Standard-Bibliothek im Code. Brauche ich eine Lizenz, um das kommerziell zu nutzen?

Ich habe nichts dazu gefunden. Zwar hab ich irgendwo gelesen, das wäre Open Source. Das sagt aber nicht viel, und greifbar gefunden habe ich es auch nicht.

Gefunden habe ich, daß man den Compiler selbst weitergeben darf, man darf ihn also etwa auf eine Linux-Distribution mit draufpacken.

Darf ich aber Scala beruflich nutzen und das Kompilat dann verkaufen? Muß ich den Quelltext dann beilegen? Dazu habe ich bisher gar nichts gefunden. Und so ist das dann nicht ernsthaft nutzbar.

Und wie das mit der Java Virtual Machine und den Rechten am Java Code nach der Übernahme von Sun durch Oracle weitergeht, und ob man das weiterhin frei benutzen kann, ist auch unklar.

Unter diesen Rahmenbedingungen erscheint es mir als riskant, Software unter Scala zu entwickeln, die dann nur schwer auf andere Sprachen portierbar ist.

Akademisch

Das größte Problem von Scala ist die Herkunft aus dem akademischen/universitären Bereich und die negativen Auswirkungen, die das hatte. Scala ist viel zu sehr an der Denkweise der theoretischen Informatik und der wissenschaftlichen „Softwaretechnik” ausgerichtet, um eine zum allgemeinen Programmieren taugliche Sprache zu sein (was als Widerspruch paradox wirkt). Daß sich diese Universitätsherkunft auf die Dokumentation negativ auswirkt, habe ich schon angesprochen. Daß es sich auch auf die Sprache selbst negativ auswirkt, will ich hier und den nachfolgenden Abschnitten (wie dem zum Funktionalen Programmieren) erläutern.

Ein Brei, entworfen von vielen Köchen verdorben zu werden

Scala macht in dreierlei Hinsicht auf mich den Eindruck, daß es ein Brei ist, der von vielen Köchen verdorben wurde.

Der erste Eindruck ergab sich schon aus der Dokumentation und dem oben beschriebenen Anbiedern an verschiedene Lehrstühle oder „Schulen”, um als Substitut für möglichst viele derer speziellen Nischenprogrammiersprachen dienen zu können und akzeptiert zu werden. Scala ist gebaut, um von allen diesen fremden Köchen mit ihren unterschiedlichen Stilen akzeptiert zu werden, und verzettelt sich damit in unterschiedlichen Paradigmen. Scala will alles sein und alles machen, aber das Ergebnis ist leider, daß es nichts davon richtig macht. Obwohl Scala eigentlich keine Gremiensprache ist, wird es so quasi zu einer gemacht (nur daß die Gremienmitglieder nichts davon wissen, weil jemand anderes ihre Vorlieben nachbaut). Sowas hatten wir schon mal, es hieß Ada und sollte hundreds of programming languages then used by the DoD ersetzen. Ada lebt noch, aber führt ein Nischendasein, und seine Sprachelemente wurden nie ganz genutzt.

Der zweite Eindruck ergibt sich aus der inkonsistenten und unsystematischen Zusammenstellung von Sprachelementen und Bibliotheksfunktionen in Scala. Ich habe oben schon das Problem der zehn verschiedenen Typen von Sammlungen angesprochen. Sowas wirkt, als hätten da mehrere Leute unabgesprochen verschiedene aber ähnliche Sachen windschief implementiert und das dann halt alles mit reingeworfen.

Der dritte Eindruck ergibt sich daraus, daß der Scala-Compiler erweiterbar ist, daß man neue Sprachelemente (sogar selbst) hinzufügen kann. Das erschien mir anfangs wie eine sehr gute Idee. Als ich aber mal gemerkt habe, wie zusammengewürfelt Scala ist, kam mir dann doch der Verdacht, daß da der Chef nur das Gerippe, das Grundkonzept hingestellt hat, und dann – wie das an Uni-Instituten eben so läuft, vor allem, wenn der Chef von Uni zu Uni durch mehrere Länder reist – und dann viele Mitarbeiter damit beschäftigt sind, und die – wie das an der Uni eben so läuft – keine Projekterfahrung haben, sondern jeder so für sich vor sich hinpuzzelt. Das wirkt auf mich, als habe da jemand zentral nur das Compilergerüst vorgegeben, und dann hätten Hinz und Kunz drin eingehängt, was sie gerade cool fanden. Das würde erklären, warum der Compiler erweiterbar ist – so ist er von Anfang an gebaut. Als Labor- und Experimentalplattform für den Compilerbau, nicht als Programmiersprache für die Welt. Und dann lief das womöglich, wie mit den Büchern der Professoren: Der Professor gibt den Titel und die Rückenbindung vor, die Mitarbeiter machen die Arbeit Kapitelweise, ohne sich abzusprechen, und am Schluß erscheint es unter dem Namen des Professors.

Akademische statt realer Ziele

Je mehr ich mich in Scala eingelesen habe, desto stärker kamen mir Assoziationen aus dem Universitätsbetrieb an einer Informatik-Fakultät. Man kann förmlich spüren, welche Aufgaben und Tätigkeiten eines typischen Informatik-Instituts mit den Eigenschaften von Scala korrespondieren:

  • Viele Eigenschaften von Scala und viele Beispiele aus dem Handbuch schreien geradezu danach, für Übungsaufgaben in Informatik-Vorlesungen des Vordiploms Bachelors verwendet zu werden. Dieses Muster aus kleinen nutzlosen realitätsfernen Knobelaufgaben wird da immer wieder erkennbar. Und ich hatte immer wieder den Eindruck, daß Scala auch nicht für viel mehr als diese kleinen Programmieraufgaben taugt, sondern genau daran entlangentwickelt wurde.
  • Die schon oben erwähnte Modularität und Erweiterbarkeit des Compilers ist zwar an sich schön, brachte aber einen heterogenen Brei hervor. Im Zusammenhang damit drängt sich mir der Eindruck auf, daß Scala als Experimentalplattform, nicht als Programmiersprache entwickelt wurde, und das Ziel hat, für möglichst viele Papers, Diplomarbeiten, Dissertationen Themen zu generieren. Da sind Sachen in Scala, bei denen ich nicht weiß, was die in einer Programmiersprache zu suchen haben und wozu sie gut sind. Vielleicht sind sie nur das Thema eines Papers?
  • Wie oben ebenfalls schon erwähnt, soll Scala offensichtlich (und erklärtermaßen) einige andere Sprachen ablösen und dazu eine Art Obermenge der charakteristischen Eigenschaften bilden, damit jeder Verfechter der anderen Sprachen seine Pläsierchen wiederfindet und zu wechseln bereit ist. So war ich ziemlich (aber nicht positiv) überrascht, als da plötzlich LISP-artige verlinkte Listen auftauchten.
  • Ein wesentliches Konstruktionsmerkmal von Scala dürfte auch gewesen sein, daß der Compiler sich selbst übersetzen kann bzw. den Compiler selbst in Scala zu schreiben. Wenn ich mir die Case Classes und Pattern Matches anschaue, dann fällt mir nicht so allzuviel ein, wofür das gut ist. Gut allerdings für die Optimierung im Compilerbau und Formelevaluatoren wie etwa in Algebrasystemen.
  • Einwerben von Drittmitteln

Wär ja alles schön und gut. Nur eine gute, allgemeine, leicht verständliche, für ein großes Anwenderpublikum zugängliche, robuste, fehlerarme Programmiersprache zu bauen, das scheint nicht Entwurfsziel gewesen zu sein.

Schlechte Lesbarkeit

Ich halte Scala für schlecht lesbar, was ich als schweren Nachteil betrachte.

Geschweifte und andere Klammern

Ich hasse geschweifte Klammern. Aus zwei Gründen.

Der erste ist, daß sie auf der deutschen Tastatur (und übrigens auch vielen anderen nicht-amerikanischen) nur schwer erreichbar sind, man so einen Affengriff einsetzen muß und das den Schreibfluss hemmt. Ich schreibe schneller begin oder end als eine geschweifte Klammer.

Der zweite ist, daß ich es für sehr schlecht lesbar und für unübersichtlich halte. Klammern bilden kein optisches Gleichgewicht zur Anfangsanweisung einer Klammer, und das Auge muß lange suchen (und womöglich noch anfangen zu zählen), bis man zu einer Klammer das Ende findet.

Scala produziert ziemliche Klammernhaufen. Nicht so schlimm wie Java oder LISP, aber immer noch zu schlimm. Viel zu schlimm.

Dazu kommt, daß Scala auch die anderen Klammern in ungünstiger Weise verwendet. Die eckigen Klammern dienen im wesentlichen dazu, Typparameter zu übergeben. Damit bleiben für alles andere nur die runden Klammern. Egal ob man Formeln klammert, parametrisiert, indiziert, Listen, Arrays, Maps oder Tupel bildet, alles mit runden Klammern. Von einem gewissen funktionalen Standpunkt aus ist das durchaus logisch, weil das ja alles Parameter sind. Aber ich finde es scheußlich zu lesen. Ich empfinde es als viel angenehmer, Indexe und Listen mit eckigen Klammern zu bauen, so wie etwa die deutsche Grammatik auch nicht durchgehend logisch ist, aber die Unlogiken das Lesen erleichtern. Man braucht viel zu lange, um den Aufbau eines Programmstückes optisch zu erfassen.

Ich verstehe nicht, warum so viele an diesen Klammernhaufen hängen. C hat das eingeführt, C++ weitergeführt, Java hat es von C abgekupfert und verschlimmert, und Scala orientiert sich daran. Ruby zeigt, daß das alles deutlich einfacher und lesbarer (und damit viel weniger fehlerträchtig) funktioniert.

Keine einfache Syntax

Im Buch wird behauptet, Scala habe eine ganz einfache Syntax, und alles würde sich daraus ergeben. Ich halte die Syntax nicht für einfach. Im Buch gibt es diverse Beispiele, bei denen man eine ziemliche Weile braucht, bis man sie syntaktisch verstanden hat. Es ist ein Unterschied, ob eine Syntax für den Compiler oder für den Menschen leicht zu analysieren ist.

Was mir vor allem negativ auffällt ist, daß sich manche syntaktische Konstruktionen an mathematischen Formeln orientieren und darauf ausgelegt sind, dieser Sichtweise möglichst nahe zu kommen. Ein typischer Denkfehler.

Gute Programmiersprachen orientieren sich – und das wird an den Universitäten so eben nicht gelehrt – eher an der Darstellung, die das Gehirn bei einer natürlichsprachlichen Beschreibung wählen würde. Im Buch findet sich etwa das Beispiel

args.foreach ( arg => println(arg) )

Ich bevorzuge eher etwas der Art

for arg in args ; println(arg) ; end

Auch so eine von Java übernommene Krankheit ist, daß es keine Zuweisungsprozeduren gibt. man kann also nicht sowas wie

a.val=5 als Prozedur schreiben, sondern muß dann sowas wiea.setVal(5) definieren.

Daß sie mit ihrer eigenen Syntax nicht klar kommen, sieht man an solchen Krücken wie der Match-Anweisung, bei der Scala nicht unterscheiden kann, ob man eine Konstante oder eine Laufvariable angibt und es deshalb dann plötzlich darauf ankommt, ob der Variablenname mit kleinem oder großem Buchstaben anfängt.

Umbenennerei

Wie das eben in der Universitäts-Wissenschaft so ist, steht Scala unter dem Existenzberechtigungs- und Rechtfertigungsdruck, auf Teufel komm raus Neues zu bringen. Sie täuschen aber mehr Neues vor, als sie tatsächlich haben, indem sie alles neu benennen, obwohl es nicht neu ist. Das erschwert das Lernen, Verstehen und Lesen unnötig, ist aber typisch akademisch, wo man man sich gerne zusammendefiniert, wie es einem gerade einfällt.

Was ist beispielsweise ein Trait? Hat man eine Chance, das zu verstehen ohne vorher das Buch ausgiebig gelesen zu haben? Warum nennt man es nicht Modul oder Mixin, wie in anderen Sprachen?

Warum deklariert man Variablen mit name:typ und nicht typ name?

Was würde der unbefangene Leser erwarten, wenn eine Funktion als Typ für den Rückgabewert Unit angibt? Warum nicht void oder irgendwas, wo man versteht, daß sie gar nichts zurückgibt, also eine Prozedur ist?

Was würde der Leser unter „Pattern Matching” verstehen? In den meisten Sprachen versteht man darunter, ob ein regulärer Ausdruck auf einen String paßt. In Scala ist es eine wüste Konstruktion, die Datenstrukturen vergleicht, und die ich – ehrlich gesagt – nach dem ersten Lesen nicht richtig verstanden und bis zum zweiten Lesen jedesmal wieder vergessen habe, also immer neu nachlesen muß.

Operatoren-Eldorado

Man merkt sehr deutlich, daß die Leute, die an Scala mitentwickelt haben, eher mathematisch, als praktisch-informatisch orientiert sind. Scala wimmelt von Operatoren wie <:>: /: :\ // \\ . Und nun merkt Euch das mal alles, damit Ihr das auch lesen könnt. Hat mich manchmal an die Programmiersprache APL erinnert, die man auf einer normalen Tastatur nicht eingeben konnte, weil sie ziemlich viele Operatoren hatte, die nur aus einem Phantasiesymbol bestanden.

Kuriosität dabei: Die Operatoren ? und : sind in vielen anderen Sprachen längst als Quasi-Standard für bedingte Ausdrücke akzeptiert, etwa in der Form wie a = (b > 5) ? 7 : 8

Kurioserweise machen sie trotz ihrer Liebe zu wilden Operatoren gerade das aber nicht, sondern setzen da auf if/else in der form a = if (b>5) 7 else 8, was für das Auge meines Erachtens schon wieder schwer zu erfassen ist, weil man dazu neigt, if für eine Kontrollanweisung und nicht für einen Ausdruck zu halten.

Lacher zum Schluß

Auf Seite 54 des Buches findet man folgendes Zitat:

Typically, useful documentation is what readers of a program cannot easily derive by themselves.

Scala macht es dem Leser leider an vielen Stellen besonders schwer. In guten Programmiersprachen kann man durchaus „selbstdokumentierende” Programme schreiben. Scala erschwert das unnötig.

Korrektheit und Sicherheit

Ich habe es eingangs schon angesprochen, vor 20 Jahren fand ich die Sprache C ganz toll. Heute nicht mehr. Da habe ich meine Meinung ganz erheblich geändert, denn heute lege ich großen Wert auf Korrektheit und Sicherheit einer Sprache, daß sie Rechenfehler, Indexfehler usw. abfängt. Deshalb sollte eine neue Sprache heute die Sicherheitsmechanismen unterstützen, die Stand der Technik sind, wie das Verhindern von Pufferüberläufen, Taint-Mechanismen, die Java Sandbox, Exceptions, Abfangen von Arithmetikfehlern usw.

Einiges davon bringt Scala (oder genauer gesagt, meist die darunterliegende JVM) tatsächlich mit. Gut ist beispielsweise, daß die match-Anweisung eine Exception werfen kann, wenn nichts paßt. An anderen Stellen jedoch ist Scala auf dem technischen Stand von vor 20 Jahren (was ebenfalls eher an der JVM und nicht an Scala selbst liegt, aber nichts am Ergebnis ändert).

Integer-Arithmetik

Was soll ich sagen, es ist halt wie in C, eine schöne 32-Bit-Arithmetik ohne jede Überlaufprüfung. Exceptions gibt es nur bei der Division durch 0. Das führt zu einigen Rechenfehlern:

scala> 65000*65000
res0: Int = -69967296

scala> 65536*65536
res1: Int = 0

scala> 65536L * 65536L
res2: Long = 4294967296

Und die Autoren von Scala und dem Fachbuch fallen natürlich auch gleich drauf rein. So gibt es auf Seite 135/136 (1.Auflage) bzw. 145/146 (2.Auflage) ein Beispiel zur Implementierung von rationalen Zahlen als Bruch in einem Objekt. Die Funktion zur Abfrage, ob eine rationale Zahl kleiner ist als die andere wird im Buch mit

def lessThan(that: Rational) =
this.numer * that.denom < that.numer * this.denom

angegeben. Das beißt einen direkt in die Nase, daß das nicht funktioniert, weil man durch die Multiplikation schnell in den Zahlenüberlauf kommt. (So ein typischer Übungsaufgabenlösungs-Schrott.) Rechnet man das nach, dann stellt man fest, daß diese Funktion zwar die Frage, ob 1/50001 < 2/50002 wäre, richtig mit Ja beantwortet, aber die Frage ob 49000/50001 < 2/50002 ebenfalls mit Ja beantwortet, obwohl es nicht stimmt, weil 49000*50002 = -1844869296 ist. Exceptions oder sowas gibt es auch nicht. Weiter oben haben sie noch die Funktion zum Addieren zweier rationaler Zahlen, die ist genauso falsch.

Das ist ein typischer Fall dafür, wie diese eigentlich veraltete Java-Arithmetik zu ernomen Programmausführungs- und damit Sicherheitsproblemen führen kann. Jeder Assembler-Programmierer weiß, daß man zwei Integer-Zahlen nicht einfach so miteinander multiplizieren kann. Entweder muß man den Überlauf abfangen, oder die Arithmetik muß ein Ergebnis der doppelten Breite liefern. (Übung für den Leser: Schreibt die Funktion lessThan mal korrekt ohne auf Long Integer zurückzugreifen. Gar nicht so einfach.)

Ich habe wenig Verständnis dafür, daß man heute als moderne und mit Steuergeldern massiv geförderte Programmiersprache noch so einen Mist produziert. Solche Rechenfehler können auch zu Sicherheitsproblemen führen. Da muß man nur mal die Höhe mit der Breite eines Fotos multiplizieren, und schon geht es schief.

Kurzer Seitenblick zu Ruby: Dort ist 65536*65536 = 4294967296 , weil Ruby automatisch auf den Datentyp Bignum umschaltet. So soll es sein.

Fließpunktarithmetik

Ähnliche Probleme hat man mit der Fließpunktarithmetik. Die ist zwar IEEE-konform, aber trotzdem Bockmist. Unter Scala ist wie unter IEEE-Arithmetik üblich

scala> Math.asin(1.001)
res0: Double = NaN

NaN steht für Not a Number = Undefiniert. Rechnet man damit weiter ohne es geprüft zu haben, kommt es zu falschen Ergebnissen:

scala> Math.asin(1.001) < 0.3
res1: Boolean = false

Das heißt, daß man unter Scala fälschlich den Wert False erhält und wieder mit gültigen Werten weiterrechnet, obwohl das Zwischenergebnis undefiniert ist. Das ist fatal.

Kürzlich ist mir unter Ruby genau so ein Programmierfehler unterlaufen. Ich habe ein kleines Programm geschrieben, das aus geographischen GPS-Aufzeichnungen etwas berechnet und dafür Formeln zur sphärischen Trigonometrie eingegeben. Das Programm war im Prinzip eine korrekte Umsetzung trigonometrischer Formeln. Für die ersten Zweihunderttausend GPS-Koordinaten hat das auch wunderbar funktioniert und richtig gerechnet. Und dann ging's bei einer schief. Weil die Fließpunktarithmetik des Prozessors nur endlich genau ist und Rechen- und Rundungsfehler erzeugt. Dadurch war ein Zwischenergebnis, das rein mathematisch zwischen -1 und +1 liegen muß, eben doch geringfügig größer als +1 und es wurde etwas wie Math.asin(1.0000000000000000000342) berechnet. Ruby hat die Berechnung sofort mit einer Exception abgebrochen, ich habe sofort bemerkt, wo der Fehler liegt. Unter C, Java oder Scala wäre der Fehler nicht aufgefallen und hätte unbemerkt zu falschen Ergebnissen geführt.

Und nun stellt Euch vor, das Programm wäre Teil einer wichtigen Anwendung gewesen. Flugzeugnavigation. Ein Navigationsgerät für den Rettungswagen. Das Handnavigationsgerät in der Wüste. Das hätte falsch geleitet. Oder irgendwas anderes falsch berechnet. Stellt Euch vor, im Medizinwesen läuft eine Bestrahlung falsch. Oder irgendwo werden Kosten falsch berechnet. Oder ein teures Werkstück falsch hergestellt.

Ich bin der Meinung, daß so eine Drecksarithmetik in einer neuen modernen Programmiersprache nicht mehr vorkommen darf. Das ist veraltet, das ist der Stand von vor 20 Jahren.

Sicher, das liegt nicht eigentlich an Scala, sondern an der darunterliegenden JVM und der verwendeten Java Laufzeitbibliotheken. Das ändert aber nichts daran, daß das Ergebnis falsch ist und man Scala so nicht ohne weiteres einsetzen kann. Man muß mehr Arbeit darauf verwenden, die einzelnen Zwischenergebnisse zu prüfen, als man für die eigentliche Berechnung aufwendet. Ich komme unten im Abschnitt über funktionales Programmieren darauf zurück.

Taint-Mechanismen

halte ich gerade für die Programmierung von Anwendungen, die mit potentiellen Angreifern kommunizieren wie Web-Applikationen, für eine sehr wichtige Sicherheitseinrichtung gegen Programmierfehler. Perl und Ruby haben so etwas. Daten, die von außen eingegeben werden (etwa über Benutzereingaben, Sockets, Environment-Variablen usw.) werden als Tainted, schmutzig, markiert. Die Markierung überträgt sich auf weitere Werte, die daraus errechnet werden. Schreibe ich a=b+c, und c ist markiert, dann ist danach auch a markiert. Und gewisse, sicherheitsrelevante Funktionen akzeptieren keine markierten Parameter. Beispielsweise kann man einen markierten Wert nicht als Teil eines Dateinamens verwenden, mit dem man auf Dateien zugreift.

Bei einer Compiler-Sprache wie Scala könnte man sogar einiges dazu zur Kompilationszeit berechnen, ohne irgendetwas an den tatsächlichen Datenstrukturen oder der Java-Kompatibilität zu ändern.

Gibt's aber nicht. Scala wurde von Softwaretechnikern entwickelt. Und Softwaretechniker denken nicht an sicheres Programmieren.

Objektorientiertheit

Objektorientiertes Programmieren halte ich für die derzeit wichtigste Programmiertechnik.

Leider ist das in Scala nur beschränkt ausgebildet, obwohl Scala ja explizit als objektorientiert beschrieben wird. Während in manchen Sprachen wie Smalltalk oder Ruby alles ein Objekt und Teil der Hierarchie ist, hat Scala kei vollständiges und homogenes Klassenmodell.

Zahlen sind in Scala zwar prinzipiell in das Klassenmodell eingebunden, aber die Klasse ist geschlossen, man kann nichts hinzufügen oder ableiten. Sie sind als abstract und final definiert.

Während ich in Ruby ohne weiteres auch die Standardtypen wie Zahlen und Strings „aufmachen” und erweitern kann, um etwa Funktionsaufrufe wie 5.km , 8.Megabyte , 30.Tage , 9.Fakultaet zu erzeugen, oder auch einfach ein Interval mit 4..7 ist das in Scala nicht möglich. Was hier noch als Bequemlichkeit erscheinen mag, wird schon schwieriger, wenn man Algorithmen schreibt, die für Zahlen ebenso wie für andere Objekte funktionieren sollen, etwa wenn man auf algebraischen Gruppen rechnet. Eine Fouriertransformation kann auf Vektoren aus Fließpunktzahlen, aber ebenso auch anderen Elementen arbeiten, die sich wie in einem Körper verhalten. In Scala kann man das nicht elegant einheitlich für die Standardtypen und eigene Objekte schreiben.

Funktionales Programmieren

Derzeit gibt es an den Hochschulen einen unglaublichen Hype um das Funktionale Programmieren. Ich halte den Hype für groben Unfug.

Funktionales Programmieren sollte man durchaus als eine von vielen Programmiertechniken (oder ein Programmierparadigma, wenn man so will) beherrschen und anwenden, wenn es angemessen ist. Aber es ist nicht mehr und nicht weniger als das.

Wenn ich manchmal sehe, was an den Hochschulen als Funktionales Programmieren getrieben und gelehrt wird, dann habe ich jedoch den Eindruck, daß es nur eine euphemistische Umschreibung dafür ist, daß man nicht richtig programmieren kann oder zu faul ist, eine richtige Programmiervorlesung zu halten. Denn vieles, was da als „Funktionales Programmieren” verkauft wird, ist bei Licht betrachtet nur schlechtes, schlampiges Programmieren.

Viele glauben auch, daß Funktionales Programmieren etwas neues wäre, was sich durchsetzten müßte und wofür man neue Sprachen braucht. Meistens wissen gerade die, die am meisten für das Funktionale Programmieren und funktionale Sprachen trommeln, am wenigsten darüber, was es da alles gibt. Schon vor Jahrzehnten wurden in der Assemblerprogrammierung Sprungtabellen für Prozeduren verwendet - nichts anderes als Funktionales Programmieren, die Funktion wird als Parameter übergeben. In C gibt es Funktionspointer, mit denen man Funktionen als Parameter mitgeben kann, im Prinzip auch Funktionales Programmieren. Und die virtuellen Klassenfunktionen, die man in C++ überladen kann, sind eigentlich auch nichts anderes als eine Funktion, die als Parameter übergeben wird, nur daß der Pointer fest an Daten klebt (was eigentlich richtiger ist).

Gerade im Vergleich mit den virtuellen Klassenfunktionen sieht man, daß das Funktionale Programmieren in vielen seiner Erscheinungsarten kein eigenes Programmierparadigma ist, sondern nur eine abgestrippte Version des Objektorientierten Programmierens. Es bilden sich da nur viele ein, daß das was eigenes, tolles wäre.

Scala kommt explizit als Funktionale Programmiersprache daher und wird damit angepriesen. Das Scala-Handbuch von Odersky u.a. nervt massiv mit seinen häufigen Belehrungen und Besserwissereien, wie toll und wichtig es doch wäre, funktional zu programmieren, dabei stimmt vieles so nicht.

So predigen die Verfechter der Funktionalen Programmierung - auch Odersky - gerne, seiteneffektfreie Funktionen zu schreiben. Das ist naiv. Stellt Euch mal vor, wir treiben Bildverarbeitung mit einem Bild von sagen wird 50 Megapixel, also etwa 150 Megabyte. Und auf dem malen wir jetzt rum, indem wir einzelne Pixel setzen. Funktional und seiteneffektfrei programmiert würde eine Funktion zum Setzen eines Pixels das Bild nicht verändern, sondern eine veränderte Kopie als Ergebnis zurückgeben. Man sieht leicht ein, daß das absurd wäre.

Funktionales Programmieren funktioniert vor allem dann besonders gut, wenn man nicht so wirklich ernsthaft programmiert, sondern nur im Hörsaal Thesen an die Tafel schreibt, selbst festlegt, was gut und richtig ist, und die Programmieraufgaben auf ein paar Matheformeln oder realitätsferne Miniübungsaufgaben beschränkt ist. Deshalb ist das Funktionale Programmieren auch vor allem bei denen beliebt, die im Elfenbeinturm sitzen. Da macht das nichts und es fragt auch keiner so genau, ob's eigentlich funktioniert. Und es fördert halt auch so eine labormässige ad-hoc-Murkserei beim Programmieren.

Der geneigte Leser möge sich in Scala by Example mal ab Seite 99 das Beispiel zum Berechnen einer Summe von Primzahlen anschauen. Zunächst gibt Odersky ein Beispiel für die iterative Version. Schnell, effizient, einfach, gut lesbar. Braucht aber 9 Zeilen Code weil Scala im prozeduralen Stil nicht schön geraten ist. (Das allein gerät schon zum Zirkelschluß. Erst bauen sie Scala so, daß das prozedurale Programmieren vernachlässigt wird und nicht kompakt dasteht, und dann nehmen sie das als Beispiel, warum funktionales Programmieren kürzer sein soll, bestätigen sich damit also nur mit ihren eigenen Präferenzen. Darf einem Wissenschaftler nicht passieren.)

Dann wird das einfache interative Beispiel künstlich auf funktional umgestrickt und erst einmal aufgezeigt, daß es eigentlich Unsinn ist, weil eine Schleife von a nach b stattdessen durch eine Liste der Zahlen von a bis b ersetzt wird und enorm Speicherplatz benötigt (und damit natürlich auch langsamer ist). Dann folgen erstaunlich krampfige Klimmzüge um zu zeigen, daß es funktional mit allerlei Tricks dann doch so ähnlich wie iterativ hinzukriegen (aber schwer zu lesen und zu debuggen) ist. Warum macht man es dann überhaupt?

Das nimmt schon religiöse Züge an. Hätten die Jungs sich mal Ruby oder andere moderne Sprachen reingezogen, hätten sie das interativ deutlich besser gestalten können. Wie so oft habe ich den Eindruck, daß der Hauptgrund für Funktionales Programmieren in Defiziten bei der Befähigung zu „normalem” Programmieren liegt.

Java Virtual Machine für Funktionales Programmieren ungeeignet

Ich verstehe nicht, warum jemand wie Odersky so intensiven Wert auf das FP legt, und dann auf eine Maschine wie die JVM und deren Laufzeitbibliothek aufsetzt. Die ist nämlich für das FP ziemlich ungeeignet, das funktioniert so nicht.

Ich habe oben aufgezeigt, daß Scala (über die JVM) unter diversen Rechenfehlern bei Integer- und Fließpunktarithmethik leidet, die nicht durch Exceptions abgefangen werden. Wenn man korrekt arbeiten will, dann muß man nach jedem Rechenschritt und nach jedem Funktionsaufruf das Ergebnis prüfen, ob es innerhalb der Spezifikation liegt. Und damit ist man zwangsläufig im iterativen, prozeduralen Programmierstil. Dieses Abprüfen und Abbrechen, wenn die Werte nicht stimmen, ist mit dem Funktionalen Programmierstil eigentlich unvereinbar. Damit man funktional programmieren kann, muß jeder Fehlerzustand zu einer Exception führen. Nur so kann man etwas als geschlossenen und einfachen Formelausdruck hinschreiben.

Es ist seltsam. Odersky überschlägt sich fast vor Begeisterung und Trommeln für Scala als Funktionale Programmiersprache und nötigt dem Leser in seinen Belehrungen das FP geradezu auf. Er merkt aber nicht, daß die JVM und damit Scala für das funktionale Programmieren nicht geeignet sind.

Scala schlecht in Funktionaler Programmierung

Ich möchte die Kritik vertiefen. Das Problem liegt nicht nur in der JVM, sondern auch in der Sprache Scala selbst. Wollen wir das ganze Elend mal am Beispiel betrachten.

Als Beispiel für die vermeintliche Überlegenheit des FP bringen Odersky u.a. im Buch ab Seite 168 (1. Auflage) bzw. 179 (2.Auflage) in Listing 7.18 ein ganzseitiges (!) schlechtes iteratives Beispiel einer Prozedur mit dem Namen printMultiTable(), die einfach eine 10x10-Tabelle mit dem kleinen Einmaleins der Multiplikation ausdruckt (bemüht schlecht programmiert um es lang aussehen zu lassen).

Drei Seiten später stellen sie in Listung 7.19 zum Vergleich die angeblich bessere funktionale Variante vor und brauchen sage und schreibe drei (!) verschiedene Funktionen um das zu implementieren:

// Returns a row as a sequence
def makeRowSeq(row: Int) =
  for (col < - 1 to 10) yield {
    val prod = (row * col).toString
    val padding = " " * (4 - prod.length)
    padding + prod
  }

// Returns a row as a string
def makeRow(row: Int) = makeRowSeq(row).mkString

// Returns table as a string with one row per line
def multiTable() = {
  val tableSeq = // a sequence of row strings
    for (row <- 1 to 10)
    yield makeRow(row)
  tableSeq.mkString("\n")
}

Drei Funktionen! Versucht's mal zu lesen und durchzusteigen. (Und als Vorteil gegenüber der iterativen geben sie noch an, daß der Vorteil die Seiteneffektfreiheit wäre, weil es nicht druckt.)

Und mit so einem Käse und Unsinn wollen die einem das Funktionale Programmieren und die Überlegenheit von Scala schmackhaft machen.

Schreibt man etwas gleichwertiges und ebenfalls funktionales (!) in Ruby, dann sieht das so aus:

def multiTable
  (1..10).collect do |row|
    (1..10).collect {|col| "%4d" % (row*col) }.join(" ")
  end.join("\n")
end

Das ist doch ganz eindeutig kürzer, besser, lesbarer, übersichtlicher, flexibler. Und funktionaler, obwohl Ruby sich selbst nicht mal als explizit funktionale Sprache sieht!

Da machen die großes Geschrei um funktionales Programmieren (mit bewußt schlecht gemachten iterativen Beispielen, um vorzugaukeln, daß funktional besser wäre), und werden dann von Ruby locker funktional überholt.

Ganz ehrlich? Da sieht Scala aus wie gewollt und nicht gekonnt.

Schwafelbegriff Funktionales Programmieren

Was mich an dem Universitäts-Geschwätz über das angeblich so tolle Funktionale Programmieren am meisten stört ist, daß es so ein nicht näher spezifiziertes nebulöses Buzz-Word ist. Und auf Buzz-Words und Marketing-Begriffen reiten sie halt sehr gerne. Weil das ist da jetzt auch in Mode, und jeder will ja vorne mit dabei sein, auch wenn er nie ernsthaft programmiert und die eigenen Programme nur deshalb gut bewertet werden, weil man Wissenschaftlern das Recht einräumt, sich selbst für gut zu befinden. Ich habe noch nie einen getroffen, der – wie viele Wissenschaftler eben – so auf Funktionales Programmieren stand und genau sagen konnte, was es eigentlich ist. Da kommt dann meist wieder die Unfähigkeit zu erklären zum Vorschein, und sie kommen wieder mit irgendwelchen Beispielen.

Würde man es genau nehmen, würde man Funktionales Programmieren nur als allgemeinen Oberbegriff von (mindestens) fünf verschiedenen Eigenschaften einer Sprache ansehen, die sich teils nur auf die Syntax, teils aber auch auf die Mächtigkeit beziehen:

  • Behandelt die Sprache Funktionen wie normale Objekte? (vgl. First-Class Function)
  • Erlaubt die Sprache Aufrufe von Funktionen, die erst zur Laufzeit ausgewählt werden?
  • Erlaubt die Sprache syntaktisch anonyme und verschachtelte, also direkt als Parameter anzugebende Funktionen? (Auch als Lambda-Ausdrücke bekannt.)
  • Erlaubt eine Sprache die Kompilation oder Interpretation von erst zur Laufzeit im Quelltext erzeugten Funktionen?
  • Ist die Sprache (d.h. der Compiler oder Interpreter) in der Lage, nur funktional hingeworfene Funktionsdefinitionen darauf zu untersuchen, ob sie als Anfangs- oder Endrekursion ausgeführt oder zur Iteration umgewandelt werden können und dies gegebenenfalls auch so auszuführen?

Außerdem wird ja immer so großer Wert darauf gelegt, daß man zu Programmen die Korrektheit nachweist. Wie das bei erst zur Laufzeit erzeugten und ausgewählten Funktionen gehen soll, wäre eine interessante Frage.

Davon ganz abgesehen kann man durchaus auch der Meinung sein, daß es Funktionales Programmieren im engeren Sinne nicht geben kann, weil das dann kein Programmieren, sondern nur noch ein Parametrisieren ist, und man die eigentliche Arbeit dem Compiler und dem Laufzeitsystem überläßt.

Ich habe jedenfalls schon viele Leute gesehen, die Funktionalen Rotz abgeladen und sich eingebildet haben, sie könnten programmieren, aber nicht mehr sagen konnten, was dann da eigentlich passiert und ob und wann es terminiert und warum. Funktionales Programmieren ist halt immer auch ein Feigenblatt derer, die nicht programmieren können.

Unausgewogen – Abgefahrenes statt Grundhandwerkszeug

Ohne Zweifel, Scala enthält eine Menge neuer Ideen und Elemente, die ich so vorher in keiner gebräuchlichen Sprache gesehen habe. Was ich ja prinzipiell sehr begrüße, sonst hätte man ja nie einen Fortschritt, sondern immer nur Variationen der alten Suppe.

Nicht alle dieser Neuerungen gefallen mir oder machen auf mich den Eindruck, gelungen und ausgereift zu sein. Manches wirkt labormäßig-experimentell. Dagegen wäre auch noch nicht viel einzuwenden, wenn es Sprachoptionen sind, die man nicht verwenden muß sondern kann, wenn man will (und die vielleicht sogar als experimentelle Bestandteile der Sprache gekennzeichnet sind, bei denen man damit rechnen muß, daß sie sich in zukünftigen Versionen ändern).

Nach dem schnöden Grundhandwerkszeug, das meines Erachtens jede moderne universelle Programmiersprache haben sollte, und das die anderen Sprachen auch fast alle haben, sucht man bei Scala bisweilen vergeblich. Die haben da offenkundig nur das reingepackt, was sie in wissenschaftlichen Papers als Neuerung verkaufen können (und ich habe auch den Eindruck, daß sie deshalb so viele neue Begriffe einführen und Bekanntes umbenennen, um den Eindruck der Neuerung künstlich zu erhöhen). Ein paar Beispiele:

  • Ich verwende gerne und häufig case-Anweisungen statt if/else. Gerade unter Ruby sind die wirklich genial und leistungsfähig, weil sie eigentlich nur ein Eye-Candy sind und das in eine if/else-Kette umsetzen, die Muster und Wert über einen speziellen Operator === vergleichen, den man beliebig definieren und überladen kann. Dadurch (und durch das sehr universelle Klassenkonzept) sind ganz erstaunliche Dinge möglich, die auch ein sehr gut lesbares und fehlerarmes Programmieren ermöglichen. Ein Beispiel aus Ruby:
    case wert
      when nil            # Null-Wert,...
      when "abc"          # String-Vergleich
      when /gh?j(\d+)/    # regular Expression
      when 5..8           # Zahlenbereich
      when Integer        # Typ
      else	              # irgendwas anderes tun
    end
    

    Scala hat sowas nicht.

    Es hat zwar eine entfernt ähnliche Case-Anweisung mit Case Classes, Pattern matching und Extraktoren, die nicht nur einen einzelnen Wert, sondern ganze Datenstrukturen vergleicht, aber die ist großer Overkill. Das Kapitel im, was diese Kontrollstruktur beschreibt, ist ganze 35 Seiten lang und das über Extraktoren nochmal 16 Seiten. Und um ehrlich zu sein, ich habe es immer noch nicht so ganz und 100%ig verstanden, wie diese Case-Classes exakt funktionieren und wie man sie effizient anwendet. Man kann das in vielen Fällen auch nicht einfach so hinschreiben wie in anderen Sprachen, sondern muß case classes definieren, wenn man nicht gegen literale Konstanten vergleicht. Das Laufzeitsystem versucht dann, einen zur Laufzeit gegebenen Wert auf verschiedene Datenstrukturen und Klassen zu matchen, die als Typen in der Anweisung angegeben werden.

    Man sieht aber an dem, wie das funktioniert, und auch an den Beispielen, daß dieses Sprachelement gebaut wurde, um Compilergenerierte Sprachbäume, Formeln usw. zu vereinfachen und zu evaluieren. Irgendwer hat das für irgendwas geschrieben, wohl ein Algebra-System oder den Scala-Compiler selbst und dann in die Sprache geworfen. Sowas hat eigentlich in einer Programmiersprache selbst überhaupt nichts verloren, sondern gehört in eine Bibliothek (und damit ganz nach hinten in den Anhang des Buches). Keinesfalls aber darf es die normalen Sprachelemente verdrängen.

    Eine solche Case-Anweisung in Scala zu produzieren, wird leicht zum größeren Projekt und zur eigenen Programmieraufgabe. Daß man case wie in anderen Sprachen als einfache, schnelle, unkomplizierte Kontrollanweisung wie if/else hinschreibt, scheint da nicht vorgesehen zu sein.

    Die Scala-Entwickler scheinen schon manchmal nach dem Motto „Warum einfach und normal, wenn’s auch zwei Nummern komplizierter und umständlicher geht” verfahren zu sein. Die alte Faustregel „keep it smart and simple” gilt im Akademischen nicht, da gilt das Gegenteil.

  • Reguläre Ausdrücke – und damit meine ich die Regular Expressions für Strings, wie sie unter Unix oder perl und ruby üblich sind – sind eines meiner am häufigsten gewählten Sprachwerkzeuge. Sprachen wie perl und ruby unterstützen das enorm, indem sie durch eigene Syntax ( wie /abc/ ) erlauben, Reguläre Ausdrücke direkt als Literale bzw. Konstanten in den Programmlauf zu schreiben, und sie dann mit Operatoren wie =~ und === oder case-Anweisungen direkt zu verwenden. Schnelles, einfaches, fehlerarmes, gut lesbares Programmieren.

    Geht in Scala so nicht. Natürlich gibt es dort auch Regular Expressions, indem man sie aus der Java-Runtime benutzt. Aber das ist dann schon wieder umständlich und sperrig, weil man sie nicht als Literale schreiben, sondern nur über einen Funktionsaufruf generieren und in einer Variable speichern muß – der Expression also nicht da steht, wo man ihn verwendet. Umständlich und schlecht lesbar.

  • String-Interpolation haben sie auch nicht, das muß man alles mühsam über Operatoren und Ausdrücke selbst zusammenklopfen.
  • Ein amüsantes Detail ist, daß man in Scala XML-Daten direkt als Literal hinschreiben kann. Man kann also direkt in den Code

    var text = <p>Hello World</p>
    

    schreiben und text hat dann den Datentyp scala.xml.Elem .

    Ob das aber sinnvoll ist, eine einzelne Datenbeschreibungssprache direkt als Literal zuzulassen, darüber kann man sich trefflich streiten. Gibt ja auch andere Datenformate, und man kann durchaus die Auffassung vertreten, daß das in eine Bibliothek und nicht in die Scala-Syntax gehört.

    Auch das verstärkt bei mir wieder den Eindruck, daß Scala keine systematisch geplante Sprache ist, sondern ein experimentelles Sammelbecken, in dem jeder Mitarbeiter oder Diplomand reinwirft, was der in den letzte 3 Wochen so gebastelt hat, weil es ihm in irgendeiner Anwendung gerade gelegen kam (man sieht auch am Reference Manual, daß der Abschnitt über XML von einem anderen Autor stammt. Auch das deutet darauf hin. War vielleicht eine Studien- oder Diplomarbeit.

    Geschenkt. Kann ja ganz nett und manchmal nützlich sein, und man muß es ja nicht verwenden.

    Man merkt aber dann, wie unausgewogen (oder windschief) Scala ist, wenn man dagegen hält, daß es für andere, viel häufiger verwendete und wichtigere Datentypen keine Literale gibt. Beispielsweise habe ich in Scala bisher keine Möglichkeit gefunden (vielleicht habe ich es auch einfach nur in diesem verfilzten ungeordneten Lehrbuch nicht gefunden), einen mehrzeiligen Text (String) als Literal hinzuschreiben.

    Viele andere Sprachen erlauben das. Da kann man einfach ein \ vor das Zeilenende setzen, oder es gibt eigene Literale wie die Konstruktion <

  • Manchmal erstaunt das schon, wie schwerfällig und plump Scala an manchen Stellen daherkommt. Will eine Funktion mehrere Werte zurückgeben, muß sie das in ein Tupel packen, das man dann wieder zwischenspeichern und entpacken muß. In modernen Sprachen kann man stattdessen einfach a,b,c=funktion(...) schreiben und gut is.

    Wenn die unterliegende JVM die Rückgabe nur eines Wertes erlaubt, würde ich eigentlich erwarten, daß der Compiler selbst in der Lage ist, das automatische ein- und auspacken zu erledigen.

Lift und Entwicklungsumgebungen

Brrr.

Ich mag Ruby on Rails sehr gerne. Ist nicht perfekt, aber macht vieles gut und schnell.

Nachdem ich gelesen habe, daß man sowas in der Art unter dem Namen Lift auch für Scala baut, wollte ich mir das mal anschauen (halte es aber für ineffizient und ungünstig, daß man es als Filter für den Servlet Container implementiert hat). Dreimal habe ich es versucht, und dreimal entnervt abgebrochen. Weil immer irgendetwas gerade nicht verfügbar war.

Bei den ersten beiden Versuchen beruhte das Einführungsbeispiel (Sie erklären bei Lift auch nicht viel, sondern bringen irgendwelche Beispiele und fragen dann „Pretty cool huh?”. Nee, is nich cool.) auf Maven. Dazu muß man Maven mit einigen Optionen starten und dann lädt Maven erst mal einen großen Haufen Module und Funktionen aus dem Internet nach, die ihm erzählen, wie man denn ein Lift-Projekt bauen könnte. Von irgendwoher. Weiß man nicht so genau, von wem. Und ohne Breitband-Internet kann man es nicht mal starten. Und damit soll man dann ein verlässliches vertrauliches Projekt bauen.

Funktionierte auch nicht. Irgendeines der vielen heruntergeladenen Module hatte gerade irgendeine Macke. Von den Lift-Leuten wußte auch keiner, woran es liegen könnte. Ja, das stimme schon, momentan ginge es gerade nicht. Aber wo man suchen und reparieren oder auch nur fragen könnte, war nicht ersichtlich. Sowas ist professionell nicht einsetzbar.

Selbst wenn Maven mal funktioniert und das ganz Zeug von irgendwo herunterlädt, man weiß nicht, was das Ding da eigentlich treibt und warum.

Nicht viel besser sieht das mit der Standard-Entwicklungsumgebung für alles aus dem Java-Umfeld Eclipse aus. Da lädt man sich auch von irgendwo aus dem wilden Internet erst mal irgendwelche wilden Module herunter, damit Eclipse dann weiß, wie man das bauen könnte.

Dann gibt es noch ant, da ist einem aber auch nicht immer so richtig klar, was das macht, wenn irgendwelche Funktionen in Java Klassen versteckt sind.

Und weil ihnen das alles nicht so richtig gefallen hat, entwickeln irgendwelche Leute aus dem Scala-Umfeld noch sbt, das Simple Build Tool.

Manchmal habe ich den Eindruck, daß sich in dieser ganzen Java-Welt so ein Biotop aus Knallfröschen und Halbprofis gebildet hat, die auf solche halbgaren Hypes abfahren.

Fazit

Richtig viel Positives fällt mir an Scala nicht auf – oder dazu ein. Besser als Java ist es, das stimmt. Und es kann voll mit Java-Programmen zusammenarbeiten, man kann es also ohne weiteres in einer Java-Umgebung einsetzen. Ein paar nette Ideen sind auch drin, deren Nutzen aber sehr beschränkt ist. Die Idee, mal etwas frischen Wind in die muffige Programmsprachenszene mit ihrer soundsovielten Me-Too-Version überflüssiger, weil entweder gleichmächtiger oder nutzloser Sprachen zu bringen, wäre eine tolle Idee, wurde aber irgendwie vergeben.

Zum Einsatz erscheint mir Scala so nicht geeignet. Ich habe eingangs geschrieben, daß ich überlegt habe, für eine Sicherheitsschulung für Web-Applikations-Programmierer den Umstieg auf eine modernere, bessere aber kompatible Sprache vorzuschlagen. Die Idee habe ich mir sofort aus dem Kopf geschlagen, als ich mich mit Scala näher befasst habe. Sowas wie Scala hätte ich den Leuten dort wirklich nicht vorschlagen können. Die wären damit überfordert gewesen und hätten mich für verrückt erklärt. Zu Recht. Ich habe davon abgesehen, Scala dafür zu verwenden.

Scala zeigt, was an den Universitäten in Softwaretechnik alles schief läuft. Da rennen irgendwelche Evangelisten rum, die sich den ein oder anderen Spleen in den Kopf gesetzt haben und sich für besonders richtig halten, weil niemand außer ihnen selbst sie bewertet. So entstehen dann auf der einen Seite solche Hypes wie Funktionales Programmieren, die arge Theorie- und Formellastigkeit und die Vorliebe für irgendwelche exotischen Spielsprachen. Auf der anderen Seite fehlt es den Leuten echt an Programmierwissen und -erfahrung und an Bezug zur Realität. Dazu kommt der ständige Druck an der Universität, vorrangig oder nur irgendwas Neues, Publikationsfähiges zu bauen. Ordentliche Lehre, sondern eine Sprache mal sorgfältig auszuarbeiten paßt da nicht rein.

Scala macht mir keinen Spaß. Zu sehr muß man beim Programmieren das Handbuch danebenliegen haben, was einem nichts nützt, weil man das, was man sucht, entweder gar nicht oder nur nach Lesen ätzender Prosa findet.

Bei vielen Aufgabenstellungen, die ich in Ruby aus dem Stand schnell, elegant, lesbar, kurz, locker, flockig, flexibel und fehlerarm hinschreiben könnte, müßte ich in Scala erst mal eine Weile überlegen und lange abwägen, welchen der diversen Datentypen ich verwende – was man wegen der Inkompatibilität der Operatoren nachträglich ja nur mit größtem Aufwand ändern kann.

Bei manchen Aufgaben würde ich mir in Scala – ähnlich wie in Java – echt einen abbrechen, um das irgendwie hinzubekommen, Scala ist oft viel zu umständlich. Und da bin ich nicht der einzige. Ich war beim Lesen des Buches erschreckt, wie sehr sich sogar Odersky selbst einen abbricht, um Beispiele in Scala zu liefern. Wenn der nicht mal in seiner eigenen Programmiersprache gut, elegant und fehlerfrei programmieren kann, wie sollen es dann andere können?

Auf mich wirkt das meiste in Scala wie gewollt und nicht gekonnt. Oder wie von wissenschaftlichen Mitarbeitern entworfen, die noch keine Berufserfahrung haben, und nicht viel mehr kennen als Java und die Universitätsüblichen Exotensprachen. Und die noch nie unter Industriebedingungen programmiert haben, sondern deren Erlebnisuniversum sich auf die typischen Übungsaufgaben einer Informatikvorlesung beschränkt. Denn Scala erscheint mir auf genau diese zugeschnitten zu sein.

Scala will/soll möglichst viele der anderen Sprachen ersetzen. Man hat aber den fundamentalen Fehler begangen, daß man sich dabei nicht die Features anderer Sprachen angeguckt hat, sondern offenbar die persönlichen Ticks und Macken einiger Professoren erfüllen wollte, die als Meinungsführer gelten und willkürlich festlegen, welche Sprache sie in ihrer Vorlesung lehren lassen. Das merkt man vor allem an der Dokumentation sehr deutlich, wenn Odersky nicht Scala beschreibt sondern auflistet, welche der Ticks und Macken es erfüllt.

Scala erscheint mir wunderbar für folgende Zwecke geeignet:

  • Für den Dualismus aus Übungsaufgabe und Musterlösung, die man nie wieder braucht.
  • Als Compiler-Experimentalplattform.
  • Als Themengrundlage für Papers, Dissertationen, Diplomarbeiten, Studienarbeiten
  • Zum Beantragen von Forschungsgeldern und Drittmittel
  • Zum So-tun-als-habe-das-Institut-ein-tolles-Forschungsthema
  • Zur Masturbation in theoretischer und formaler Informatik

Nur eben nicht zum normalen Programmieren.

Oder wenn ich es anders, konstruktiv-kritisch formulieren und zu vier kurzen Punkten zusammenkochen soll, die die Probleme von Scala beschreiben:

  • Scala ist keine geplante Sprache, bei der man ein Design, einen durchgehenden Sprachstil als roten Faden festgelegt und dann die Elemente und Bibliotheken daran ausgerichtet hat, sondern es ist eine eingesammelte Sprache. Typisch für das Abmelken von Diplomanden und Doktoranden. (Ich weiß nicht, ob es wirklich so war. Aber so riecht es.)
  • Scala ist nicht von Leuten mit Profi- und Industrieerfahrung, sondern von Elfenbeinturmartisten geschrieben, deren Horizont sich vornehmlich auf Formeln, Papers schreiben und Übungsblätter in Programmiervorlesungen konzentriert. Bei vielen Scala-Elementen sieht man als Informatiker förmlich die Übungsaufgaben oder die Titel der Papers vor dem geistigen Auge. Das kann nicht Entwurfsziel einer professionellen Programmiersprache sein.
  • Scala basiert auf der Java Virtual Machine und der Java Laufzeitumgebung. Ich hielt diese schon 1997 für unzureichend und veraltet. Jetzt haben wir 2011.
  • Auch wenn man Scala zugestehen muß, noch in der Entwicklung zu sein, wurden meines Erachtens Entwurfsfehler begangen, die nur unter Aufgabe der Verträglichkeit und Kompatibilität zu den bestehenden Scala-Versionen zu korrigieren sind. Wenn Scala besser werden soll, muß man alles, was man jetzt in Scala schreibt, später überarbeiten (oder verschiedene Scala-Versionen mischen).

Ach ja, und das noch: Wer solche Bücher, Dokus und Beispiele schreibt wie Odersky, der muß noch einige Butterbrote essen, bevor er sich anderen als den ihm untergebenen Studenten gegenüber solche oberlehrerhaften Belehrungen zum Programmierstil leisten kann.


62 Kommentare (RSS-Feed)

dasuxullebt
15.5.2011 23:40
Kommentarlink

TL;DR

aber:

> Clojure? Ein Lisp-Dialekt. Schauderhaft. Bleibt derzeit also
> nur Scala.

Wenn du einen Lisp-Dialekt für Java suchst, über den du wegen seiner Lispigkeit was schlechtes sagen willst, nimm lieber ABCL. Ich persönlich finde Clojure wegen einem Haufen Dinge schlecht, insbesondere weil es zu un-lispig ist.

Naja, die Zukunft heißt sowieso: program extraction from proofs! *duck*


Jabe
16.5.2011 0:28
Kommentarlink

Dein FP-Beispiel zeigt, wie “over designed” (im akademischen Sinne) Scala ist. Der Ruby-Code ist pragmatisch und dazu noch funktional. Ich definiere FP übrigens anders: Wenn ich eine Funktion auf mehrere Elemente einer beliebigen Liste anwende und die Funktion danach nie wieder sehe. An dem Scala-Beispiel sieht man, wie man alles möglichst kompliziert machen kann und dann auch noch nutzlos kommentiert.

Auch genial ist Currying. Ich bin damals mit Ruby drübergestolptert. Nach drei mal lesen wurde mir klar: total trivial. Völlig nutzlos überhaupt einen Begriff dafür zu definieren. Das ist sicherlich für die Theoretiker totaaaal wichtig, aber für jede Programmiersprache sowas von nutzlos, keiner macht das ernsthaft und selbst wenn dann versehentlich.

Ich teile deine Meinung, dass Ruby eine der besten Sprachen im Moment ist. Ich persönlich bevorzuge allerdings C# (Ruby ist Platz 2). Die wochenlangen flame wars über M$ lassen wir einfach mal aus — Anders Hejlsberg ist einfach genial. Seine Interviews anhören oder lesen, das tut RICHTIG gut.


dasuxullebt
16.5.2011 2:07
Kommentarlink

> Auch genial ist Currying. (…) Das ist sicherlich für die Theoretiker
> totaaaal wichtig, aber für jede Programmiersprache sowas von nutzlos,
> keiner macht das ernsthaft und selbst wenn dann versehentlich.

Hast du dein Diplom/Master/whatever vom Flohmarkt oder was? “Currying” ist kein Programmierprinzip sondern eine Transformation die die Typisierung vereinfacht, und die modernen funktionalen Sprachen sind automatisch gecurried, as in, man definiert üblicherweise keine anderen Funktionen. Man führt diesen Begriff nur ein damit Schwachmaten in der FP-Vorlesung nicht wegen irgendwelcher (meist falschen) Vorstellungen von Stack-Besetzung das Protestieren anfangen, dass eine gecurriede Funktion ja nicht dasselbe sei wie die selbe in der nichtgecurrieten Version [ für jeden anständigen Compiler sind sie das ].

Mich kotzt das ewige Geseusel von Halbpragmaten an von wegen funktionale Sprachen seien ja sooooo praxisfremd und weiß der Geier was. Praktiker haben es bis jetzt nicht geschafft wenigstens mal Pufferüberläufe auszuschalten, ohne gleich eine riesen Maschinerie wie die Java-VM oder das .NET-Framework drüberzuhauen, leihen sich für Schwachfug wie C++0x und schlechte Shellsprachen wie Ruby mal eben das Lambda, reguläre Ausdrücke und ein paar Pfeiltypen aus, und wundern sich dann wenn das Ganze langsam und instabil wird, und irgendwie nicht zusammenpasst.

Das sind halt alles keine so einfachen Sachen, die man sich einfach mal eben ohne tieferes Verständnis ausleihen und in eine bestehende Sprache einpflanzen kann. Mir schaudert zum Beispiel wenn ich sehe dass man mit sowas wie Typed Scheme versucht, eine abhängig typisierte Sprache in die Öffentlichkeit zu rücken. Abhängige Typisierung wird sicher irgendwann soweit sein, dass man sie breit einsetzen kann. Bis es soweit ist muss aber noch viel Forschung an deren Skalierbarkeit betrieben werden, ein dicker Haufen an Fallstudien, und vor allem Vorlesungen die dafür sorgen dass die tollen Pragmaten sie auch verstehen.


TGL
16.5.2011 2:19
Kommentarlink

Zum Artikel: Danke für die interessante Analyse! Ruby scheint bei dir der Einäugige unter den Blinden zu sein, soweit die Projektgröße sich in Grenzen hält, was hälst du für große Projekte denn für erträglich?

Zu Jabe: C# habe ich mir auch mal ein wenig angeschaut, habe aber Probleme gehabt, weitere Infos für konkrete Probleme zu kriegen, kannst du bestimmte Seiten, Feeds oder auch Bücher empfehlen, wenn man da tiefer einsteigen will?


Hadmut
16.5.2011 13:20
Kommentarlink

@TGL: Sorry, mit C# kenne ich mich kaum aus. Ich habe zwar ein dickes Buch darüber und habe mir das mal angeschaut, weil ich in einem beruflichen Projekt eine Erweiterung für Microsoft Sharepoint gebraucht hätte. Sharepoint kann man mit .NET irgendwie erweitern. Als ich aber gemerkt habe, wieviel Aufwand die Erstellung wird, und daß das in keinem Verhältnis zum Nutzen (und damit zu dem, was der Auftraggeber zu bezahlen bereit ist) steht, hab ich es wieder weggelegt. C# ist nicht so das Problem, wieder mal eine neue Me-Too-Sprache mit ein paar Abwandlungen. Das Problem ist das ganze Gedöns, was da hintenraus in der Microsoft-Welt noch kommt. Und nur deswegen würde man sich ja für die Microsoft-spezifischen Sprachen interessieren.


Haskell
16.5.2011 9:51
Kommentarlink

Ich empfehle Haskell! Da gibt es keine Sicherheitsprobleme, denn ab einem gewissen Komplexitätsgrad wird das Programm nie fertig und die Programmierer landen für lange Zeit in der geschlossenen Anstalt…


Haskell
16.5.2011 9:59
Kommentarlink

Ach, noch als Ergänzung (sorry für den Doppelpost): Ich habe eine Antwort anzubieten auf Hadmuts Frage: “Ich habe nie verstanden, warum so viele Leute, Firmen, Universitäten auf Java gesprungen sind.”

Im ersten Semester (2000) gab es bei uns ca. 650 Erstsemesterstudenten. Vorbereitet war das Institut auf etwa die Hälfte. Da kommt Java sehr gelegen zum Aussortieren: Das noch wenige Jahre zuvor gelehrte (und für Lehrzwecke geeignetere) (Object-)Pascal wäre für viele Studenten auf Anhieb verständlich gewesen. Mit Java konnte man einfache Dinge komplizierter als kompliziert ausdrücken und so tun, als verstünde man nicht, wo die Probleme lägen. Ein probates Mittel, um bei zu vielen Studenten in den ersten Monaten auszusortieren…


J.
16.5.2011 10:05
Kommentarlink

“École Polytechnique Fédérale de Lausanne” – wie kommt man auf die Idee, sich dafür einen seltsamen englischen Namen auszudenken? Französisch ist doch keine sonderlich ungebräuchliche Sprache und wird zudem in lateinischer Schrift geschrieben.


J.
16.5.2011 10:21
Kommentarlink

“Was ist beispielsweise ein Trait?”

Aus der generischen Programmierung mit C++ ist mir der Begriff wohlbekannt: http://en.wikipedia.org/wiki/Traits_class

http://en.wikipedia.org/wiki/Trait_%28computer_science%29 scheint mir aber etwas anderes zu sein, und wird in der Wikipedia nicht so richtig prägnant erklärt …


J.
16.5.2011 10:23
Kommentarlink

“Man kann also direkt in den Code

var text =

Hello World

schreiben und text hat dann den Datentyp scala.xml.Elem .”

Da hat das Blog das HTML wohl als HTML ausgegeben, sprich, Du hast Escaping vergessen …


Hadmut
16.5.2011 12:39
Kommentarlink

@J: *Seufz* , ja, da hat das Escaping gefehlt. Danke! (Ich hatte das vorher im Entwurf mit was anderem geschrieben und beim Übertragen in WordPress hat nicht alles so geklappt, wie ich mir das gedacht hatte.)


georgi
16.5.2011 10:28
Kommentarlink

Hallo Hadmut!

Erstens: Das Wesen funktionaler Programmierung hast Du anscheinend noch nie begriffen. Du mußt mal von Deiner imperativen Sicht herunterkommen. Dann mußt Du auch nicht funktionale Konzepte zwanghaft in imperative (Sprungtabellen, callbacks etc.) übersetzen. Dann erst erscheint funktionale Programmierung ziemlich naheliegend, zumindest für Leute, die mathematische Notation gewöhnt sind.

Allerdings muß man dazusagen, daß mir keine funktionale Programmiersprache bekannt ist, die ich praktisch einsetzen würde. An jeder der Sprachen (auch Scala) ist irgendwas dran, was mich derart stört, daß ich die Sprache beiseite lege. Der funktionale Programmierstil ist das aber nicht.

Zweitens: Funktionale Programmierung und objektorientierte Programmierung passen nicht zusammen. Iteration, Variablenzuweisungen, Steueranweisungen (while, for etc.) gehören nicht in den Bereich funktionale Programmierung. Dazu gehören aber Currying, pattern-matching, abstrakte Datentypen.

Dein Beispiel mit der Bildverarbeitung ist wirklich schwierig mit funktionaler Programmierung umzusetzen. Dasselbe gilt für interaktives und reaktives Verhalten. Dafür gibt es Philipp Wadlers genialen Monad-Hack, den man erst verstanden haben muß, und der in Haskell umgesetzt wurde (auch keine Sprache, die ich einsetzen würde wegen der nervenden Monomorphismus-Bedingung im Typsystem)

Drittens: (Sicherheit) Funktionale Programmierung dürfte gerade in Hinsicht der Sicherheit Vorteile bringen. Die von C bekannte Stringarithmetik und überhaupt Zeiger gehören nicht in die funktionale Programmierung. Es kann daher auch keine Pufferüberläufe geben. Und überhaupt: Ist es nicht schön, endlich mal von Speicherproblemen verschont zu werden? Endlich mal komplexe Datenstrukturen benutzen zu können, ohne sich um einfach- oder doppelt-verlinkte Listen und Zeigerstrukturen, und deren ordnungsgemäße Beseitigung nach Gebrauch zu kümmern?

Cross-Site-Scripting ist ein Zeichen schlecht designter Systeme. Deshalb sind auch die genannten Sicherheitsfeatures entbehrlich (wie ich glaube; ich maße mir hier nichts an).

Viertens: Ruby habe ich früher auch schon mal weggelegt. Python bot bessere Dokumentationen. In den Standardbibliotheken war bisher alles vorhanden, was ich benötigte, und die waren auch gut dokumentiert. Einiges finde ich aber auch an Python nervend. Coroutinen statt der Generatoren hätte ich gern.

Fünftens: Funktionale Programmierung ist kein Hype. Ada, Java und überhaupt objektorientierte Programmierung waren Hypes. Letztere beiden haben sich aber als beständig erwiesen.


Hadmut
16.5.2011 13:09
Kommentarlink

@Georgi: Nee, da sehe ich vieles ganz anders. Ich glaube schon, daß ich das Wesen funktionaler Programmierung begriffen habe. Ich habe jedoch die Motivation und Begründung, funktional als durchgehenden, einheitlichen Königsweg und Einheitsprogrammierstil anzusehen, nicht akzeptiert und halte sie nicht für richtig. Ich halte funktionale Programmierung nur für manche Problemstellungen und nur im Bereich einzelner Algorithmen, nicht ganzer Programme für richtig.

Ich bitte dabei übrigens auch mal zu berücksichtigen, daß ich als Mensch in meiner Arbeitsweise imperativ und nicht funktional arbeite! Wenn ich die Küche saubermache, dann mache ich meine Küche sauber und baue nicht neben der dreckigen Küche eine saubere Kopie der Küche auf. Wenn ich mir Schuhe anziehe, dann ziehe ich mir die Schuhe an, die in der Garderobe stehen und fertige mir nicht baugleiche Kopien für den Tag an. Und wenn ich einen Blogartikel schreibe, dann tippe ich den in meinen Computer und stelle keine komplette Kopie meines Computers oder des Blogs her, die sich durch den Artikel vom alten unterscheidet.

Ich halte auch die Aussage für falsch, daß funktionale Programmierung und objektorientierte Programmierung nicht zusammenpassen, zumal die Formulierung windschief ist. Zu meiner Zeit hat man noch die abstrakten Datentypen gelehrt und daß man Spezifikation/API von der Implementierung trennt. Das heißt, daß nach außen hin nicht das verwendete Paradigma, sondern die Daten und die Funktion dasteht, und in der Implementierung dann der Algorithmus für die Daten aktiv wird. Insofern gehört der Algo immer irgendwo zum Datentyp und ist damit per se objektorientiert. Funktionen ohne Eingabevariablen müßte man damit sogar als Objektorientiert zu nil, void, unit (oder wie auch immer man das leere Datum nennen will) ansehen. Wenn man die Auffassung vertriett, daß funktional etwas anderes als objektorientiert, etwas inkompatibles und nicht passendes sein soll, dann verstehe ich das eher als Ausdruck der – von mir auch oben gerügten – Programmierschlampigkeit der Vertreter des funktionalen Programmierens, die per Euphemismus zum neuen Stil erhoben wird. Schließlich haben ja auch funktional programmierte Funktionen eine formale Parameterspezifikation, beziehen sich also auf einen gewissen Datentyp. Damit sind sie von ihrer Natur her objektorientiert.

Ich stimme Dir aber zu (und habe das ja oben geschrieben), daß Interation, if/else usw. nicht zur funktionalen Programmierung passen. Völlig richtig. Wäre so ja an sich auch ein interessanter Stil (den ich übrigens in Ruby häufig verwende). Mein Kritikpunkt ist ja aber, daß Scala – obwohl Odersky funktionales Programmieren predigt – bzw. die JVM dafür nicht geeignet ist, weshalb ich ja oben das Kapitel über die Integer- und Fließpunktarithmetik geschrieben habe. Denn die Unzulänglichkeiten der Arithmetik erzwingen es, daß ich – will ich korrekt und robust programmieren – nach jedem Schritt die Ergebnisse abprüfen und Fehler abfangen muß, und damit bin ich zwangsläufig in einem imperativen Programmierstil. Für sauberes funktionales Programmieren brauche ich da eine Arithmetik (bzw. eine ganze Laufzeit- und Standardbibliothek), die alle Fehlerzustände selbständig abfängt und durch Exceptions aus dem normalen Programmfluß entnimmt. Gerade deshalb halte ich Scala ja nicht für funktionales Programmieren geeignet (wenn man industrielle Qualitätsanforderungen stellt und nicht nur Beispiel- und Übungsblattprogramme schreibt), während erstaunlicherweise Ruby als nicht funktional beworbene Sprache das viel besser macht.

Mich stört ja der funktionale Aspekt von Scala auch gar nicht. Mich stört, daß sie es nicht brauchbar umgesetzt haben.

Und ja, funktionale Programmierung bringt große Vorteile in der Hinsicht Sicherheit, wenn man es richtig macht und alle Fehlerzustände mit Exceptions abfängt. Gerade das war ja der Grund, warum ich – wie oben beschrieben – für die Sicherheitsschulung ursprünglich vorhatte, Java-Programmieren Scala schmackhaft zu machen oder zumindest funktionale Denkweisen vorzuführen. Dann habe ich aber festgestellt, daß Scala nicht nur zu komplex, unlogisch und inkonsistent ist, sondern daß sie auch das Funktionale so grausig schlecht umgesetzt haben, daß man es nicht einmal so funktional einsetzen kann, daß es die Sicherheit wirklich hebt. Deshalb bin ich ja so enttäuscht von Scala. Ein guter Programmierstil in IT-Sicherheit ist durchaus sogar ein funktionaler Stil, aber Scala leistet das einfach nicht, was man dafür braucht. Die predigen da Funktionales Programmieren, aber kriegen’s dann nicht auf die Reihe.

Und Pufferüberläufe verhindet man übrigens nicht dadurch, daß man eine vergrößerte Kopie des Puffers erzeugt und verwendet, sondern daß man eine Exception wirft, wenn das Programm aufgrund Fehler auf was zugreifen will, was nicht da ist. Denn sonst macht man sich die Speicherprobleme erst.

Ich will übrigens auch Ruby nicht als wirklich gut hinstellen. Eingangs habe ich die Probleme von Ruby aufgezeigt, und Scala habe ich mir ja angesehen, weil ich was besseres als Ruby suchte. Scala war das aber nicht.

Ich stimme Dir auch zu, daß Funktionales Programmieren eigentlich kein Hype ist. Es wird aber im Hochschul-Lehrbereich wie ein Hype verwendet. Und deshalb geht’s auch schief. Würde man sich ernsthaft damit befassen, würde man es nicht als den Königsweg lehren und dann würde Scala nicht so aussehen, wie es aussieht.


K.
16.5.2011 12:09
Kommentarlink

Ich stimme dir im großen und ganzen zu, muss dir aber widersprechen, dass du zu Begin C mit PHP und Java als einfache Programmiersprache anführst. Ich habe jetzt mit mehreren Kommilitonen den Bachelor gemacht und von den 10 können, inklusive mir, genau 2 C. Nicht, dass es nicht im Studium drangekommen wäre: Sie raffen es nur einfach nicht. Dangling pointer, Memoryleaks oder Speicherverwaltung im Allgemeinen sind denen Fremdwörter. Die haben vorher Java gelernt und sehen überhaupt nicht ein, dass es Sprachen gibt, in denen niemand hinter denen aufräumt. Also bestehen die den Kurs mit 3.x und werden dann auf die Menschheit losgelassen.

Letztes Jahr hatte Fefe, für regelmäßige Leser seines Blogs in gewohnter Polemik, kritisiert, dass KDE jetzt auf einem Java Paket basiert und das auf die Praxis der Universitäten zurückgeführt, Java als einzige Sprache zu unterrichten. Habe dazu leider keine Zahlen, aber passt in mein Weltbild: http://blog.fefe.de/?ts=b2f6c021

Was deine Aussage zu Softwaretechnik im universitären Umfeld angeht kann ich dir voll und ganz zustimmen. Der Prof an unserer Uni sollte uns Java beibringen und hat erstmal
String string = new String();
string = “Hallo welt”;
auf seiner Folie gehabt. Man kann das ganze natürlich auch positiv sehen. Dem Lehrstuhl traue ich nicht zu, einen Compiler zu schreiben, insofern wird man wohl da von neuen Sprachen verschont bleiben.


Hadmut
16.5.2011 13:15
Kommentarlink

@K.: Da hast Du völlig Recht. Das liegt aber nicht daran, daß C schwer wäre, sondern daß sich die Universitäts-Lehrenden das unterste Niveau herausgesucht haben, und – wie ich immer wieder betone – einen äußerst schlampigen Stil lehren und das dann als wissenschaftliche Tugend hinstellen.

Und ich habe den Eindruck, daß die deshalb so auf funktionales Programmieren abfahren (deshalb oben das Beispiel mit der Bildverarbeitung), weil sie damit noch schlampiger arbeiten können. Bei Java kümmern sie sich nicht darum, wer hinter ihnen aufräumt. Bei funktionalem Programmieren kümmern sie sich auch nicht darum, wieviel Speicher überhaupt verbraucht wird, weil sie ja immer schön neue Kopien anlegen statt die bestehenden Daten zu ändern.

Deshalb lernen die Leute an den Universitäten ja immer weniger Programmieren, weil die Dozenten immer schlechter und fauler werden, man ihnen aber gestattet, diese Verschlechterung als neues Paradigma und Fortschritt der Wissenschaft zu bewerten.


dg
16.5.2011 14:48
Kommentarlink

Nun, wo du Taint-Mechanismen erwähnst… *die* wären mal ein perfekter Fall für die funktionale Programmierung, konkret für Monaden. ( http://blog.sigfpe.com/2007/04/homeland-security-threat-level-monad.html macht es mit einer Monade für geheime Daten vor; eine Monade für unsichere Daten geht wohl genauso).

Allerdings, ob Scala auch eine sinnvolle Syntax für Monaden bietet, ist eine andere Frage.

Daß du if/then/else imperativ und nicht funktional siehst, ist Gewöhnungssache. “variable:typ” und nicht “typ variable” zu schreiben, ist keine *neue* Notation, sondern eine aus der Mathematik. Currying ist einfach der Gedanke, eine Funktion von zwei Argumenten so hinzuschreiben, daß sie ein Argument nimmt, und eine Funktion zurückgibt, welche wiederum das zweite Argument nimmt und den Endwert liefert. Das gibt dem Programmierer die Möglichkeit, nicht nur mit der Funktion f und ihren Werten f(a,b) zu arbeiten, sondern auch mit der “Zwischenstufe” f(a,*) wo a fest ist und das zweite Argument noch zu liefern ist. Steht jedem frei, das nicht zu verwenden, aber stören sollte es einen nicht.

Floats scheinen generell in der Informatik eine Katastrophe zu sein.


schlingel
16.5.2011 14:58
Kommentarlink

Du hättest mir viel Lesarbeit erspart wäre gleich am Anfang gestanden was du von funktionalem Programmieren hältst.

Das ganze BlaBla davor ist doch sehr davon geprägt, dass der Blick noch nicht auf die – Achtung Bullshit-Bingo-Wort – Synergien zwischen Industriesprachen und FunkProg-Sprachen gerichtet worden ist.

Falls die Programmiersprachen tatsächlich interessieren empfehle ich das Buch Real World Functional Programming. Der Autor geht mit viel Geschick auf die Sprache F# ein und zeigt wie die vorhandenen FunkProg-Elemente in C# verwendet werden können um das gleiche zu schaffen.


Hadmut
16.5.2011 15:09
Kommentarlink

Ich schreib doch kein Blog um Leuten Lesarbeit zu ersparen. Du ersparst Dir viel Lesarbeit, wenn Du mein Blog einfach nicht liest. 😉

Ich habe außerdem momentan überhaupt keine Lust, meine Zeit damit zu vergeuden, mich in noch zwei Sprachen zu vertiefen, von denen ich jetzt schon weiß, daß sie mich nicht sonderlich interessieren und für meine Zwecke ungeeignet sind.


georgi
16.5.2011 16:00
Kommentarlink

@Hadmut

Wenn man die Auffassung vertriett, daß funktional etwas anderes als objektorientiert, etwas inkompatibles und nicht passendes sein soll, dann verstehe ich das eher als Ausdruck der – von mir auch oben gerügten – Programmierschlampigkeit der Vertreter des funktionalen Programmierens, die per Euphemismus zum neuen Stil erhoben wird.

Mein Eindruck ist genau umgekehrt. Funktionale Programmierung ist mathematisch motiviert. Gerade Leute, die sich mit Programmverifikation und Semantik von Programmiersprachen beschäftigen, lieben funktionale Programmierung wegen der Seiteneffektfreiheit. Bei funktionaler Programmierung ist alles so präzise definiert, daß die in dieser Hinsicht sehr anspruchsvollen Mathematiker zufrieden sind. Das ist nicht so ein Chaos wie bei C++.

Da funktionales Programmieren zustandsloses Programmieren ist, ergeben Klassen und Objekte keinen Sinn, denn diese Dinger enthalten immer einen inneren Zustand.

Es ist auch in Ruby eine gute Idee, alle Ausnahmen abzufangen. Daß Ruby eine bessere Arithmetik hat, kann man ja nicht dem funktionalen Paradigma anlasten.

Und Pufferüberläufe verhindet man übrigens nicht dadurch, daß man eine vergrößerte Kopie des Puffers erzeugt und verwendet, sondern daß man eine Exception wirft, wenn das Programm aufgrund Fehler auf was zugreifen will, was nicht da ist. Denn sonst macht man sich die Speicherprobleme erst.

Solche Situationen treten beim funktionalen Programmieren gar nicht auf. In funktionalen Programmen gibt es nur Konstanten und keine Variablen, denen in der Laufzeit Werte unterschiedlicher Größe zugewiesen werden könnten, keine Zeiger, die auf andererweitig belegten Speicher verweisen könnten. Der Speicher geht dem funktionalen Programmierer gar nichts an. Der benutzt das Hennessy-Milner-System bzw. die Conse (LISP) und baut damit seine Datenstrukturen. Alle Dinge, die Speicher betreffen, überläßt der schön dem Compiler/Interpreter. Der tut dann sein Bestes, die Wünsche des Programmierers auf die JVM zu prügeln.

Nicht nur mit Deinem Verständnis von funktionaler sondern auch von objektorientierter Programmierung bin ich nicht einverstanden. Dann müßten MODULA2 und ADA objektorientierte Sprachen sein. Sind sie aber nicht. In diesen Sprachen wie im Konzept des abstrakten Datentyps in der funktionalen Programmierung sind Spezifikation und Implementation/Repräsentation strikt getrennt.

Scala ist mit Sicherheit so besch***** wie OCaml und LISP und alles andere.


Hadmut
16.5.2011 16:35
Kommentarlink

Dazu habe ich gerade einen neuen Artikel gebloggt.

Außerdem ist es eine sehr akademische und universitäre Programmierweise, wenn man einfach so programmiert, daß man das Problem nicht löst, sondern jemand anderem überläßt (und dann so tut, als habe man es selbst gelöst).

MODULA2 kann man ganz entfernt durchaus als Ansatz einer Objektorienten Sichtweise ansehen. Man kann nämlich zusammengesetzte Datentypen (structs) definieren und Prozeduren, die auf diesen agieren.

Deine Argumentation bezügen Funktionalen Programmierens ist in der Hinsicht richtig, daß sie zutreffend ist. Insofern stimme ich Dir da durchaus zu. Aber genau in dem, was Du da beschreibst, sehe ich den wesentlichen Grund, warum funktionales Programmieren (allein) Bullshit ist. Siehe mein nächstes Posting mit näherer Begründung (hat auch nichts mehr mit Scala speziell zu tun).


Daniel
16.5.2011 17:48
Kommentarlink

“Ich bitte dabei übrigens auch mal zu berücksichtigen, daß ich als Mensch in meiner Arbeitsweise imperativ und nicht funktional arbeite! Wenn ich die Küche saubermache, dann mache ich meine Küche sauber und baue nicht neben der dreckigen Küche eine saubere Kopie der Küche auf. Wenn ich mir Schuhe anziehe, dann ziehe ich mir die Schuhe an, die in der Garderobe stehen und fertige mir nicht baugleiche Kopien für den Tag an. …”

@Hadmut
Und wenn ich ein Haus baue, fange ich sofort an den ersten Stein zu legen. Ganz ohne Bauplan – einfach direkt Stein auf Stein. Wer braucht schon Architekten und schert sich um Bauvorschriften oder Normen ;D

Klar sind einfache Sprachkonstrukte für “einfache” Aufgaben sinnvoller. Aber gerade anhand von regulären Ausdrücken kann man schnell ein komplexes Problem einfach aussehen lassen. Das heisst aber weder, dass es einfach ist noch das der angesprochene reguläre Ausdruck fehlerfrei wäre.


Hadmut
16.5.2011 17:59
Kommentarlink

Äh – und was willst Du mir damit sagen? Daß man nur mit funktionaler Programmierung planen kann, was man tut?

Ich verstehe nicht, was die (zutreffende) Aussage, daß man ein Haus planen muß und Bauvorschriften berücksichtigen muß, mit imperativ und funktional zu tun haben soll.


Stefan W.
16.5.2011 18:32
Kommentarlink

Leider gibt es keine Vorschau und kein Bearbeiten des Beitrags, wenn die Formatierung krankt – ich hoffe das Layout überlebt es. 🙂

a) Wie kommt man an die immutable Map, falls man einmal die mutable Maps importiert hat?

scala> val m1 : Map [String, Int] = Map ((“Eins”, 1))
m1: Map[String,Int] = Map((Eins,1))

scala> val m2 = collection.mutable.Map ((“Zwo”, 2))
m2: scala.collection.mutable.Map[java.lang.String,Int] = Map((Zwo,2))

scala> import collection.mutable.Map
import collection.mutable.Map

scala> val m3 = Map ((“Drei”, 3))
m3: scala.collection.mutable.Map[java.lang.String,Int] = Map((Drei,3))

scala> val m4 = collection.immutable.Map ((“Vier”, 4))
m4: scala.collection.immutable.Map[java.lang.String,Int] = Map((Vier,4))

b) eckige Klammern sind ähnlich Handbrechend wie geschweifte – letztere zu verdammen, und erstere zu vermissen, wirkt inkonsistent.

c) For-loop, mathematischer oder Ruby-artig:

for arg in args ; println(arg) ; end

for (arg val udo = new Rocker (“Udo Lindenberg”)
udo: Rocker = Rocker@16c171f

scala> udo.name = “Frank Zappa”

scala> println (udo.name)
Frank Zappa

e) Warum deklariert man Variablen mit name:typ und nicht typ name?
Wegen der Typinterferenz kann man den Typen oft weglassen – den Namen aber nicht. Ich meine gelesen zu haben, dass der Compiler schneller ist, wenn er nicht soundso oft erst die falsche Annahme testet.

f) Das Matching läßt sich fast 1:1 nach Scala transformieren:

scala> def wertmatch (wert: Any) = wert match {
| case Nil => println (“Nilkrokodil”)
| case “liko” => println (“literale Konstante”)
| case s: String if s.matches (“””gh?j(\d+)”””)
| => println (“Pattern matched”)
| case s: String => println (“String, sonstiger”)
| case n: Int if (n > 4 && n println (“special Int”)
| case i: Int => println (“arbitrary Int”)
| case _ => println (“sonstiges”)
| }
wertmatch: (wert: Any)Unit

scala> val samples = List (“liko”, “gj42”, “ghh23”, 5, -5, 3.1415, Nil)
samples: List[Any] = List(liko, gj42, ghh23, 5, -5, 3.1415, List())

scala> samples.foreach (wertmatch)
literale Konstante
Pattern matched
String, sonstiger
special Int
arbitrary Int
sonstiges
Nilkrokodil

Patternmatching ist nicht auf Case-Classes beschränkt, jene sind lediglich für das Patternmatching optimiert. Dank Typerasure ist Patternmatching aber nicht immer möglich.

g) Mehrzeiliger Text:
val purpose = “””Ziel
dieses Kommentares ist, zu rufen: “Me too!”.
Auch wir haben mehrzeilige Strings. “””


Hadmut
16.5.2011 18:35
Kommentarlink

Du hättest das Buch über Scala schreiben sollen, nicht Odersky.


Hadmut
16.5.2011 18:40
Kommentarlink

Zuzugeben, eckige Klammern sind fast so schwer einzugeben wie geschweifte (bei meiner Handgröße und Tastatur aber immer noch signikant leichter als geschweifte). Aber ich will ja die geschweiften nicht durch eckige ersetzen, sondern die Strukturen mit end und die Indizierung durch eckige. Ich finde das erheblich leichter lesbar und weniger fehlerträchtig.


Stefan W.
16.5.2011 18:38
Kommentarlink

Wie befürchtet – bei c) d) ging es schief. Wenn hier ein Link wäre, wo man rasch mal nachsehen kann, wie man für WordPress formatieren muss. Mit \ \? Oder ist es BB-ähnlich mit eckigen Klammern?

c) For-loop, mathematischer oder Ruby-artig:

for arg in args ; println(arg) ; end

for (arg <- args) println (arg)

println (args.mkString ("\n"))

d) Einfache Zuweisung:

scala> val udo = new Rocker ("Udo Lindenberg")
udo: Rocker = Rocker@16c171f

scala> udo.name = "Frank Zappa"

scala> println (udo.name)
Frank Zappa

Nachtrag: Punkt d) ist so wohl erst seit 2.8 möglich.


Hadmut
16.5.2011 18:44
Kommentarlink

Nein, eine Beschreibung zu WordPress-Eingaben kenne ich nicht.

Das ist sogar reichlich widersprüchlich und inskonsistent, wie WordPress Eingaben formatiert und welche Tags es akzeptiert und umwandelt.

Selbst wenn ich als Admin einen Kommentar schreibe, kommt es darauf an, über welche Seite ich es eingebe. Antworte ich auf einen Kommentar, dann kann ich keine Aufzählungen eingeben, die Tags werden gelöscht. Mache ich diesen Kommentar dann aber zum Ändern auf, und geben sie dann wieder ein, dann bleiben sie drin. WordPress ist zum Haare ausraufen. Deshalb fliegt es auch bald raus. Gibt noch mehr, was mir an WordPress nicht in den Kram paßt.


Jabe
16.5.2011 19:41
Kommentarlink

@TGL: Ja, bei C# kommt viel M$-Kram mit. Aber es gibt wirklich schlimmeres. Sharepoint wurde schon genannt. 🙂
Die BCL und das Fx sind in der Basis sehr angenehm und laufen auch in Mono sehr gut. Bis Oracle kam…? C# war früher ganz klar ein Java “me too”, hat sich aber weiterentwickelt. Einsteiger-Bücher kenne ich jetzt leider keine, aber als Referenz lohnt sich “C# 4.0 in a Nutshell” von Joseph & Ben Albahari. Jon Skeets Artikel sind auch immer empfehlenswert, er geht eben richtig ins Detail.
Aber willst du das wirklich? Das ganze ist doch urlahm, wurde von Unfähigen für Unfähige entwickelt und ich persönlich habe als Halbpragmat auch keine Ahnung. Was ist das überhaupt? Der Duden kennts nicht. Aber die haben sicher auch keine Ahnung.


Stefan W.
16.5.2011 19:59
Kommentarlink

Nachdem ich meine Kommentare losgeworden bin möchte ich aber noch meiner Verwunderung Ausdruck verleihen, dass ich in anderer Leute Augen jetzt also als jmd. da stehe, der an akademischen Sprachen interessiert scheint.

Nach einen Start in Basic ging es bei mir zum Erlernen eines C und C++ – Mischmaschs über. Dazu kam die Nichtsprache SqlWindows und dann Java. Nur mal eben angeschaut für ein 200 Zeilenprogramm habe ich Prolog und PHP.

An Java gefiel mir, daß man da aus dem Nichts, von Scratch, grafische Programme entwickeln kann, und die Vorstellung, dass der Kunde ein Programm für Windows braucht, aber ich als Entwickler das unter Linux entwickeln kann. Meine 600-Seiten-Schmöker zu C++ hatten jeweils 20-40 Seiten zu Windowsprogrammierung drin, die dann Dinge wie (far PASCAL …), DWORD und HWnd benutzt haben, ohne sie zu erklären, und die Demos ließen sich auch nicht kompilieren, was ziemlich frustrierend war.

Bei unkompilierten Sprachen habe ich immer ein schlechtes Gefühl. Mit denen wurde ich nicht warm. Ein Freund jubelte mir von Ruby vor, und ich einige Konstrukte, die ich jetzt bei Scala wiedergefunden habe, habe ich bei Ruby spontan abgelehnt, als seltsam, fremdartig, und wo sollte der Vorteil gegenüber Java sein? Kürzer? Man denkt ja eh mehr nach, als dass man tippt.

Smalltalk habe ich auch noch 2 Wochen versucht, und wurde auch nicht grün damit. Andere Syntax und wieder ein ganz neues API.

Bei jeder Sprache muß man auch wieder alle Bibliotheken neu lernen, auch wenn die vieles ähnlich machen. Scala kam mir da sehr entgegen, weil ich mein Javawissen 100% übernehmen kann. So brauche ich nur die Scalasyntax neu zu lernen, und ein paar Scalabibliotheken – letzteres geht aber einfach, in dem es bei Bedarf nach und nach gelernt werden kann.

Die arithmetischen Fehler finde ich auch ärgerlich, auch wenn sie nicht oft vorkommen. Gerade daher hat man dann wenig Erfahrung damit, wann sie zuschlagen.

Die Erfahrungen mit Scala würden es mir wohl jetzt erleichtern Ruby zu lernen, aber es zieht mich gar nichts in diese Richtung. Zu Java will ich aber auch nicht mehr zurück.

Das Collectionsframework wurde übrigen für Scala 2.8 stark überarbeitet – mit :: kann man aber nach wie vor nicht überall anhängen (bei Array kann man ja sowieso nicht anhängen).

Anhängen kann man bei einer List übrigens schon – es ist nur nicht performant. Da habe ich Dich aber vielleicht nur falsch verstanden – womöglich meinst Du genau das.

scala> val ii = List (3, 4, 5)
ii: List[Int] = List(3, 4, 5)

scala> ii :+ 6
res27: List[Int] = List(3, 4, 5, 6)


enno
16.5.2011 22:36
Kommentarlink

Ich bin immer wieder überrascht, wie gut die Java-VM optimiert. Ich bin von Java über Ruby zu Smalltalk gekommen und ich möchte auf keinen Fall zurück zu Java. Aber die Geschwindigkeit der VM ist schon beeindruckend. Selbst VisualWorks hat da keine Chance. Mein diesjähriger Fokus liegt allerdings auf Common Lisp. Da habe ich früher immer einen Bogen drum gemacht, aber der Buchrücken von “Let over Lambda” klang einfach zu interessant und jetzt habe ich mich festgebissen. Trotzdem, die schönste Sprache bleibt Smalltalk 🙂


enno
16.5.2011 22:48
Kommentarlink

Achso. Zum Thema Funktionales Programmieren. Es ist nur so ein Bauchgefühl, und ich kenne es auch nur vom Draufgucken auf Scala-Listings, aber ich habe den Eindruck, dass es dem “Getting things done” nur im Weg steht. Das Gefühl hatte ich bei Prolog damals auch. Eine vom Aussterben bedrohte Nischensprache.


ini
17.5.2011 14:27
Kommentarlink

Ist ja drollig eure Diskussion aber nix kommt an Visual Basic ran.


Hadmut
17.5.2011 14:29
Kommentarlink

Würg…


Bob
17.5.2011 15:25
Kommentarlink

Zum Thema “Also quasi Ruby mit fester Typbindung und API-Definitionen als Compilersprache. Eine ordentliche Sprache, die auch für größere Projekte taugt. Das wär’s.”

Hast Du Dir mal Google’s Go angeschaut? Das hat nämlich genau das.


Hadmut
17.5.2011 15:29
Kommentarlink

Nee, hab mir Go noch nicht näher angeschaut. Hab mir irgendwann mal angeguckt, was in der Wikipedia dazu steht, und es hat mir nicht so direkt gefallen.


ini
17.5.2011 15:34
Kommentarlink

Ok warn Scherz. Aber mal was aus der funktionalen Praxis:
Einer meiner damaligen Profs war LISP-Fan, KI-Experte. Der meinte mit seinem KI-Zeug (Mustererkennung) könnte er Geld verdienen und gründete eine Firma die entsprechende Lösungen entwickelte, nat. in vorwiegend in LISP, was anderes konnte er nicht ausser noch Prolog.

Ich dachte schon damals dass das nix wird und genau so kam es:
Die Probleme im Einzelnen:

* Fähiges Personal finden das freiwillig mit LISP arbeiten will. Selbst “seine” Studenten flüchteten gleich nach dem Diplom als sie einen hellen Moment hatten und merkten, dass sie sich damit keinen Gefallen tun. Die Entwicklung dort machte ein fester Mitarbeiter (einer seiner Diplomanden konnte er doch überreden), der Rest waren Praktikanten und stud. Hilfskräfte.

* Kommerzielle LISP-Syteme mit Support und Standardbibliotheken/Bindings waren am Aussterben.

* Ein Problem war der enorme Speicherverbrauch in der Bildverarbeitung wie du ihn geschildert hast, war ein regelrechtes deja vu als ich das gelesen habe. Man hat übelste Verrenkungen unternommen damit es performanter und resourcenschonender wurde.

* Das Zeug war wegen LISP schlecht an andere Software integrierbar. Theoretisch ging es, praktisch wegen vieler Bugs doch nicht. Der Hersteller stellte auf stur. Kunden wollten auch eine Lösung die auf Microcontrollern läuft, auch dafür gab/gibt es LISP-Lösungen aber wieder anderer Dialekt, zu lahm, unbrauchbar,… das war wie ein Rattenschwanz an Nachteilen den man damit hatte.

* Die Kunden wollten einfach keine LISP-basierten Lösungen. War ne regelrechte Phobie obwohl die damit nie zu tun gehabt hätten aber man wusste dass es ein totes Pferd ist und sich ein darauf basiertes Produkt nicht ins Haus holt.

* Funktional ist schön in der Theorie, in der Praxis musste man das schöne Theoriegebäude aufweichen und drumherum programmieren, letzendlich war es ein unwartbarer Mischmasch aus LISP, Prolog Java und C und weiteren Sprachen je nach Kundenwunsch.

* Ging er nach Jahren damit pleite. Der Laden hielt sich nur über Investoren über Wasser die er über seine Professorenfreunde z.T. von der GI auftreiben konnte. Z.T. ging da auch Forschungsgeld rein, indirekt über die Hochschule was aber nix anderes als getarnte Entwicklung für die Firma war. Der Rest kam von wenigen Kunden denen man das Zeug aufgeschwatzt hatte und dank unfangreicher Anpassungen weiter an ihnen verdiente.

* Funktionales Programmieren wie man es an der Hochschule lernt ist akademisches Spielzeug, man kann damit ein paar Dinge sehr elegant lösen in der Praxis hat man damit ganz andere Probleme die in der Lehre völlig ausgeblendet werden. Überall wo in der Praxis was funktional begonnen wurde kam es später zu einer kompletten Neuimplementierung die nicht-funktional war oder man hat das Zeug irgendwann beerdigt weil sich keiner damit auskannte (Personal gestorben,gewechselt,…) so meine Erfahrungen.


Bob
17.5.2011 21:07
Kommentarlink

Hmmm… Dann guck Dir vielleicht nochmal ein paar Folien z.B. on hier an:

http://golang.org/doc/docs.html

(unter Videos and talks, linke Seite)

Go ist meiner Ansicht nach erstmal C in “heutzutage gut gemacht”: mit multiple Rückgabewerte, keine automatische Casts, perfekte Konstanten (beliebig lang/präzise), “iota” statt enums (sehr geil für bitmasken, z.B.), Garbage Collection (aber: man hat relativ viel Kontrolle übers Memory Layout, wenn man auf sowas Wert legt), Closures (will ich z.B. nicht mehr missen). Und es ist natürlich alles compiliert. Ziel ist nur 10-20% langsamer zu sein als C.

Dann gibts ein sehr cooles Typ-System: Typen ohne Vererbung (keine Klassen, nur “structs”). “primitve typen” und structs werden absolut gleichbehandelt. Davon getrennt Interfaces, die automatisch implementiert werden, wenns halt passt. Damit kann super das Duck Typing der dynamischen Sprachen nachbauen – nur es skaliert* auf größere Projekte, da die Typen statisch gecheckt werden können**.

*=ok, hab ich natürlich (noch) nicht persönlich ausprobiert, wie gross das skaliert 😉
**= ja, leider leider gibts es noch typ-casts, aber die kann man zumindest vorher checken.

UND dann gibts noch Nebenläufigkeit in “einfach zu benutzen”. Vieles, was in anderen Sprachen schwer und ätzend ist, ist in Go einfach. Allerdings kriegt man noch genug Seil um sich zu hängen, Deadlocks und Race Conditions verhindert die Sprache nicht und solche Fehler macht man bspw. leichter als in Erlang – man muss sich für so Fehler aber weit mehr Mühe geben als in C/C++/Java etc.

Naja, gibts aber nicht für die JVM, also wohl offtopic…


HF
17.5.2011 21:47
Kommentarlink

Bildbearbeitung und Lisp. Da war doch was?
Ja!
http://docs.gimp.org/en/gimp-introduction-history.html#gimp-introduction-history-beginning

According to Peter Mattis and Spencer Kimball, the original creators of GIMP, in their announcement of GIMP 0.54:

The GIMP arose from the ashes of a hideously crafted CS164 (compilers) class project. The setting: early morning. We were both weary from lack of sleep and the terrible strain of programming a compiler in LISP. The limits of our patience had long been exceeded, and yet still the dam held.

And then it happened. Common LISP messily dumped core when it could not allocate the 17 MB it needed to generate a parser for a simple grammar using yacc. An unbelieving moment passed, there was one shared look of disgust, and then our project was vapor. We had to write something… ANYTHING … useful. Something in C. Something that did not rely on nested lists to represent a bitmap. Thus, the GIMP was born. 🙂


Ralf Muschall
20.5.2011 20:06
Kommentarlink

@Hadmut: “Wenn ich die Küche saubermache, dann mache ich meine Küche sauber und baue nicht neben der dreckigen Küche eine saubere Kopie der Küche auf. ”

Das ist aber nur, weil Du Dein eigener Compiler und Optimizer bist. Bei einem Compiler bestelle ich einfach eine saubere Küche und lasse ihn machen. Die am schnellsten hingetippte und verständlichste Lösung ist eine saubere Kopie, und der Compiler implementiert das dann so, dass er heimlich die dreckige Küche destruktiv manipuliert und beweist, dass das trotzdem threadsafe ist.

Übrigens, Fakultät *ist* rekursiv. Allerdings ist sie so leicht zu programmieren, dass sie jeder im Kopf optimiert und die iterative Variante hinmalt. Schon bei geringfügig komplizierteren Sachen sollte man so etwas tunlichst unterlassen, um Fehler zu vermeiden (ansonsten bastelt man Unit-Tests mit beiden Versionen, um herauszufinden ob die iterative Version überhaupt der Definition gehorcht).

PS: Geschweifte Klammern bekomme ich mit Shift-ü usw., Umlaute sind schwerer (Ctrl-Shift-U 0fc Leertaste, bzw. in Windows Alt-Shift, dann ü, dann wieder Alt-Shift) 😉


Hadmut
20.5.2011 20:17
Kommentarlink

Der Compiler baut aber keine neue Küche. Der Aufwand zur Compilationszeit interessiert mich auch nicht.

Der Compiler baut mir eine Putzfrau, die die Küche nicht putzt, sondern jedesmal eine neue bestellt. Wenn sich die Fähigkeit des Programmierens zu sehr auf das „beim Compiler bestellen” reduziert, ist es irgendwann kein Programmieren mehr.

Fakultät ist keine echte Rekursion, weil ich es auch Bottom Up bzw. als Produkt hinschreiben kann. Ich kann es von unten nach oben oder von oben nach unten aufmultiplizieren. Fakultät ist keine Rekursion, die man im Kopf zur Iteration optimiert, sondern eine Iteration, die manche im Kopf zur Rekursion umformulieren und sich dann drüber freuen, daß der Compiler es wieder zurückfummelt.


dasuxullebt
21.5.2011 1:46
Kommentarlink

> Fakultät ist keine Rekursion, die man im Kopf zur Iteration
> optimiert, sondern eine Iteration, die manche im Kopf zur Rekursion
> umformulieren und sich dann drüber freuen, daß der Compiler es wieder
> zurückfummelt.

Zumindest die Gamma-Funktion ist durch eine Funktionalgleichung gegeben, und gilt als Verallgemeinerung der Fakultät. Und was 0! ist ist irgendwie auch nicht so klar bei einer iterativen Definition. Gleiches gilt bei Potenzen. Die natürlichere Schreibweise ist da die Funktionalgleichung, und die führt in dem Fall zu einem rekursiven Algorithmus.

In dem Fall ist es aber wirklich egal, was man nun nimmt, Rekursion ist ein Werkzeug um Zeug klarer hinschreiben zu können, und zumindest ich finde es klarer, Fakultät rekursiv darzustellen, und dem Compiler ist es egal.

Ein viel lustigeres Beispiel ist da die Fibonacci-Folge. Die natürliche Definition ist da f_0=0, f_1=1, f_{n+2}=f_{n+1}+f_{n} – exptime, und nicht endrekursiv. Haskell macht das Ganze per lazy evaluation wieder linear. SML nicht: Man muss sich der wesentlich hässlicheren endrekursiven Gleichung F(1)=, F(n)= und f_n = \pi_1 F(n+1) herumärgern. Die stellt einen imperativen Algorithmus dar, und spiegelt ziemlich genau das wieder, was Imperaten machen würden. Sie sieht nur deshalb funktional aus, weil man den Scope jedes mal explizit übergibt.

Wenn man auf diesem Beispiel nun ein wenig weiter herumhaut erkennt man ein viel allgemeineres Muster dahinter, warum in diesem Fall die imperative (endrekursive) Lösung so viel schneller ist, und warum das oft so ist, aber nicht immer, und dessen Erforschung könnte (eine Garantie gibt es in der Forschung nicht) wichtige Erkenntnisse liefern. Ich könnte mehr dazu schreiben, hab aber grad keine Lust, zumal es hier wohl eh keinen interessiert (aber nette Idee für nen eigenen Blogpost eigentlich).


dasuxullebt
21.5.2011 1:48
Kommentarlink

Gah. Ich vergaß natürlich, dass im Web keine größer- und kleiner-Zeichen erlaubt sind – jetzt sind Teile des Textes verschwunden.


drac
6.7.2011 13:15
Kommentarlink

Ich habe das Buch “Programming in Scala” gelesen und sonst noch keine Erfahrung in Scala.
Da ich bereits C#- und Java- Erfahrung habe, waren die ersten 200 Seiten ziemlich langweilig. Da hatte ich gedacht, dass ich besser ein anderes Buch hätte kaufen sollen, dass speziell für Java-Erfahrene geschrieben ist.
Aber die nächsten 600 Seiten haben sich dann gelohnt. Ab und zu stand auch da, dass Java-Erfahrene sich die nächsten paar Seiten sparen können.


Hadmut
6.7.2011 13:21
Kommentarlink

Das ist aber doch genau das Problem, das er sich nicht zwischen einer Einführung in Scala und einer Einführung in das Programmieren entscheiden kann.


drac
6.7.2011 13:29
Kommentarlink

Ich finde Hadmuts Kritik an Scala, Odersky und dessen Buch sehr interesseant und vieles auch berechtigt.

Trotzdem habe ich die positive Würdigung der Sprachskalierung vermisst (oder überlesen). Ich könnte ein eigenes Sprachkonstrukt definieren. Nur als Beispiel ein eigenes while: myWhile, das so aufgerufen werden könnte:

myWhile(x code) {
while(condition) code()
}

Also sehr easy zu definieren und meiner Meinung nach ein geniales Feature.
Wenn ich mich recht erinnere, war das Currying unter anderem dafür notwendig.


Hadmut
6.7.2011 13:30
Kommentarlink

Geht unter Ruby schöner…


drac
6.7.2011 13:34
Kommentarlink

Komisch, in meinem vorigen Kommentar ist nicht die Definition von mywhile angekommen. Ich probiere es nochmal:

Solch ein Konstrukt würde in etwa so definiert
(mache ich jetzt alles aus dem Kopf, also bitte Fehler verzeihen oder korrigieren):

def myWhile(bool condition)(=> code) {
while(condition) code()
}


drac
6.7.2011 13:35
Kommentarlink

Wie ist das Beispiel unter Ruby ?


Hadmut
6.7.2011 13:38
Kommentarlink

Im direkten Vergleich sähe es ähnlich aus, der Code wird halt mit yield ausgeführt.

Der Vorteil von Ruby ist, daß ich das optional gestalten kann. Ich kann also beispielsweise eine Funktion foreach eines Objektes definieren, die mir dann, wenn ein Code-Block mit angegeben wird, den Block ausführt, und ansonsten als Rückgabewert eine Liste der Elemente mitgibt, die ausgeführt worden wäre.

Ich habe aber den Verdacht, daß Dein Beispiel falsch ist, weil condition als fester Wert übergeben wird. Ist condition = false wird der code nie ausgeführt, und ist er true, wird er ewig ausgeführt.


Hadmut
6.7.2011 13:40
Kommentarlink

Und um das Problem zu umgehen, kann man in Ruby sogar Prozeduren schreiben, die zum Zeitpunkt der Code-Erzeugung ausgeführt werden wie ein Macro. Ich kann also sogar Funktionen schreiben, die Ruby-Code ausgeben. Und damit bekommt man sowas dann auch in den Griff.


drac
6.7.2011 13:37
Kommentarlink

Und hier nochmal die Anwendung von myWhile (kam nicht richtig an):

myWhile(x<100) {
//do something
}


Hadmut
6.7.2011 13:39
Kommentarlink

Wie gesagt, ich habe den Verdacht, daß das Beispiel nicht funktioniert, weil x<100 nicht jedesmal neu ausgewertet wird, sondern nur einmalig. Oder?


drac
6.7.2011 13:46
Kommentarlink

Ah jetzt verstehe ich, warum mein erster myWhile-Kommentar nicht richtig ankam.
Da wurde alles zwischen spitzer geöffneter und geschlossener Klammer ignoriert.
Wenn man nur eine geöffnete Klammer hat, funktioniert es.
Wenn man nur eine geschlossene Klammer hat, funktioniert es.
Deshalb haben meine Korrekturen gezogen.


drac
6.7.2011 13:50
Kommentarlink

Oh danke Hadmut. Das myWhile müsste so definiert sein, dass condition als Funktion übergeben wird:

def myWhile(=>condition:bool)(=> code) {
while(condition) code()
}


drac
6.7.2011 13:51
Kommentarlink

Mit dieser Kritik hast mich richtig neugierig auf Ruby gemacht.
Wenn es nur typisiert wäre…


dasuxullebt
6.7.2011 15:28
Kommentarlink

Bin ich froh dass sowas mit defmacro in common lisp ganz einfach, und mit eindeutiger Unterscheidung wann welches Argument ausgewertet wird, und sogar ohne currying, geht…


datenwolf
22.9.2011 21:22
Kommentarlink

Ich habe ja Dein Blog bisher immer gerne gelesen, aber Deine Basherei gegen formale Programmdefinition, Funktionales Programmieren finde ich dann doch sehr daneben.

Gerade für jemanden im Sicherheitsbereich sollten funktionale Sprachen doch ein El-Dorado sein. Auf dem CCCamp2011 gab es einen Vortrag in dem ein formal/funktional entwickelter PDF-Parser vorgestellt wurde, etwa 300 Zeilen lang, der aus dem Stand 95% der ihm präsentierten Malware-PDFs alleine daran erkennt, dass sie formal nicht korrekt sind: http://events.ccc.de/camp/2011/Fahrplan/events/4426.en.html

Funktionspointer in C übergeben ist übrigens kein Funktionales Programmieren, da ich dem Pointer keinen Kontext mitgeben kann, da müsste man schon eine struct mit Funktionspointer, dem Kontext in dem er entstanden ist usw. mitgeben. Natürlich kann man immer irgendwie alles irgendwie in einer anderen Sprache nachbauen, Turig-Vollständigkeit FTW. Die Frage ist doch, wie sehr bricht man sich da einen ab, wenn man es tut.

Ich bin bei weitem kein Verfechter der funktionalen Programmierung. Ich verwende immer das Werkzeug, dass einer gestellten Aufgabe am besten zu Leibe rückt. Immer noch oft C, meistens Python, seltenst C++. Demnächst steht eine komplexe Motorsteuerung-/Meßwerterfassung an, da wird es wohl Go werden.

Immer öfter, je besser ich sie beherrsche, sind es funktionale Sprachen. Man darf auch nicht vergessen, dass alleine die Erfahrung mit rein funktionaler Programmierung einem einen neuen Blick auf so manches (alte) Problem gibt das man danach auch in einer imperativen Sprache eleganter und nicht selten effizienter löst, einfach weil man ein ganz anderes Verständis für die Zusammenhänge hat.


Hadmut
22.9.2011 21:48
Kommentarlink

@datenwolf: *Gähn* Die Argumentation „Ich hab dein Blog immer gerne gelesen, aber jetzt nicht mehr” ist so abgegriffen und kommt soooo häufig. Und ist dabei doch so substanzlos.

Und nein, gerade vom Sicherheitsaspekt her bin ich von Funktionalen Sprachen keineswegs begeistert. Hab ich hier im Blog auch schon mehrfach erläutert. Beispielsweise weil beim funktionalen Programmieren der Schwerpunkt auf dem Kopieren statt ändern liegt, was aus Sicherheitssicht eine Katastrophe ist. Ich habe immer noch nicht herausgefunden, wer eigentlich den Schwachsinn in Umlauf gesetzt hat, daß Funktionales Programmieren so sicher wäre. Das ist es nämlich nicht – bzw. nur von einem naiven Standpunkt allein aus Sprachsicht. Man weiß beispielsweise hinterher nicht mehr, wieviele Kopien eines Schlüssels im Speicher herumfahren. Und löschen kann man sie auch nicht.

Freilich kann man einen Pointer in C einen Kontext mitgeben. Man muß es halt hinschreiben. Oder C++ nehmen, denn eine objektorientierte Methode bekommt ja einen Kontext, nämlich das Objekt.

Und wenn Du meinen Artikel richtig gelesen hättest, dann hättest Du gemerkt, daß ich nichts gegen funktionale Sprachen im Allgemeinen habe, sondern nur was gegen Leute, die das als das einzig Seligmachende und das Beste hinstellen und lehren. Zumal ich die funktionale Programmierung in Scala für lausig umgesetzt halte. Umso lächerlich finde ich es, wenn Odersky so auf funktionales Programmieren abhebt. Ich finde es lächerlich, FP so hochzuloben und es dann so lausig zu implementieren.


datenwolf
22.9.2011 23:55
Kommentarlink

> objektorientierte Methode bekommt ja einen Kontext, nämlich das Objekt.

Und da fangen die Probleme an. C++ kennt Pointer-to-Member und dann noch Instanzen. Ich kann aber nicht einfach von einer Memberfunktion einer Instanz einen Pointer-to-Member-of-Instance nehmen (ein echtes Manko von C++, das nicht zu können) aber genau sowas in der Art bräuchte man, um zumindest im Ansatz funktional zu sein. Man kann sich das in C++ in beschränktem Umfang selber zusammenbauen, nur artet das in einem furchbaren Template-Rotz aus, der außerdem mit bestimmten Funktionssignaturen nicht klar kommt. So um 1998 herum habe ich mir mal sowas in mühevoller Arbeit geschrieben. Mittlerweile gibt es sowas auch bei Boost, aber so richtig schön ist das nach wie vor nicht.

D hat das ordentlich umgesetzt in Form der sog. Delegates. Damit muss man sich auch nicht mehr mit so einem unsäglichen signal-slot-connect herumschlagen, man übergibt einfach das Delegate als Callback z.B. an einen Button als OnClick-Handler oder was auch immer. Ähnliches gilt für Go.

> funktionalen Programmieren der Schwerpunkt auf dem Kopieren statt ändern liegt

Ich glaube Du hast da was ein wenig mißverstanden, nirgendwo in der rein funktionalen Programmierung wird formal mit _Kopien_ gearbeitet, es wird auf formaler Ebene _zugewiesen_ – dieser Eindruck entsteht natürlich leicht, wenn man da mit dem Blick des Imperators an die Sache geht, der denkt “funktional geht auch in $IMPERATIVE_SPRACHE”. Dem Compiler steht es frei, eine Speicherstelle wiederzuverwenden, wenn sich beim Kompilieren des Programms herausstellt, dass der Zustand einer Iteration in späteren Iterationen nicht mehr benötigt wird. Ob das dann in der Implementierung tatsächlich so gemacht wird steht natürlich auf einem anderen Blatt. Aber in Standardsituationen wie Tail-Rekursion wird das schon aus Effizienzgründen so gehandhabt, ständige De-/Allokation ist ineffizient und ständiges Kopieren erzeugt unnötig Cache- und Page-Misses.

Und dann darf man natürlich nicht vergessen, dass in einem (theoretischen) rein funktionalen System es so etwas wie frei adressierbaren Speicher nicht gibt; in so einem System wäre es ja noch nicht mal möglich Speicher im Sinne von Adressraum anzusprechen. Natürlich sind diese Überlegungen auf klassischen imperativen Architekturen hahnebüchen. Es gibt aber Leute (mit denen ich befreundet bin), die an einem Lambda-Kalkül-Prozessor (d.h. das Ding arbeitet schon auf Gatter-Ebene rein funktional) basteln und auch dessen Korrektheit formal beweisen wollen. Das behebt natürlich nicht das Problem der Schlüsselextraktion aus “vergessenen” Speicherstellen im physikalischen RAM; andererseits würde man auf einer solchen Lambda-CPU die Kryptoprimitive fest verdrahten und so gestalten, dass die typischen Seitenkanäle dicht gemacht werden, also Timing, (Differential) Power, Memory-Tapping usw. macht man ja bei heutigen “normalen” CPUs mittlerweile auch so. Und funktionalen Compilern könnte man auch beibringen entsprechend deklarierte Speicherstellen, die z.B. Schlüssel enthalten, bei der Freigabe zu überschreiben (man sollte da übrigens ein Zufallsmuster verwenden und nicht mit irgendwelchen Komplementärbits arbeiten, so als Hinweis an den Rest der Leserschaft, das Komplementärmuster ist dem Schlüssel äquivalent, liegt auch irgendwo im Speicher und wie überschreibt man das dann? Ausserdem haben die ColdBoot-Forscher vor 3 Jahren herausgefunden, dass man mit Komplementärbits überschriebene Speicherstellen wiederherstellen kann).

Geht man mal vom reinen Sicherheitsgedanken aus, dann ist Sicherheit aber nicht nur Kryptographie im Sinne von Datensicherheit (=Schlüsselsicherheit). Es geht auch um so “banale” Dinge, wie das Parsen von Datenströmen; eine Aufgabe deren Implementationen immer wieder mal schöne Schnitzer enthalten. Besonders beliebt bei Mediencontainern, wie z.B. PDF. Wenn ich einen Parser für PDFs schreiben will und ich mich auf die Untermenge der nicht verschlüsselten PDFs beschränke, dann habe ich gar nicht erst das Problem das mir Schlüssel entweichen könnten, tue mich aber mit der Aufgabe, PDFs zu parsen um einiges leichter wenn man das funktional macht. Macht man es formal, fallen einem auch gleich alle PDFs auf, die nicht korrekt sind, darunter auch diejenigen, die auf einen Exploit in einem PDF-Parser abzielen.

Ich bin übrigens kein Informatiker sondern Physiker und nutze z.B. Haskell für einige meiner Simulationsprogramme (in der Teilchenphysik, es gibt da ein C++ Standardpaket Namens ROOT, aber ich finde das, gelinde gesagt, scheußlich zu verwenden). Von daher ist an mir die Lehre wie sie an den Informatik-Fakultäten gehandhabt wird komplett vorbeigegangen.


Hadmut
23.9.2011 0:30
Kommentarlink

@datenwolf: Was soll denn das jetzt?

Ich äußere mich negativ über funktionales Programmieren, und du kommst nun mit – angeblichen – Schwächen von C++ daher? Das ist doch ein völlig anderes Thema.

Außerdem eine völlig bekloppte Diskussion – meine Kritik an Scala damit diskutieren zu wollen, daß Dir C++ nicht gefällt.

Und genauso dämlich ist es, damit diskutieren zu wollen, daß irgendwelche Freunde irgendwas festverdrahtetes entwickeln.

Funktionales Programmieren beruht fundamental darauf, daß Daten nie in sich selbst verändert werden, sondern immer nur Funktionswerte zurückgegeben werden. Unter rein funktionalem Programmieren kann man Daten niemals löschen, sondern sie nur „vergessen” und der garbage collection überlassen. Völlig inakzeptabel im Sicherheitsbereich. Und es macht es auch kein bisschen besser, daß es aus der funktionalen Sicht keinen frei adrressierbaren Speicher gibt. Denn der zugrundeliegende physikalische Computer hat sowas. Und den muß man aus Sicherheitssicht bearbeiten. Und da hilft es nicht, indem man ihn einfach wegdefiniert. Es ist ein unvertretbarer Schwachsinn, wenn da gelehrt wird, daß funktionales Programmieren das ein und alles wäre. Für manches ist es gut, für anderes aber völlig untauglich. Und meistens nur das Feigenblatt derer, die nicht richtig programmieren können, es aber trotzdem lehren.

Und es ist völlig bescheuert, jede Einzellösung (hier: Überschreiben) dem Compiler beibringen zu wollen. Denn damit programmiert man es ja doch wieder, nur eben im Compiler.

Und der ColdBoot-Krempel geht auch völlig am Thema vorbei, denn erstens stimmt er so nicht, zweitens setzt er physikalischen Zugriff voraus.

Das ganze Gelaber ändert alles nichts daran, daß man im Securitybereich einfach die Funktion braucht, Speicherzellen zu löschen.

Und wenn Du kein Informatiker bist und selbst sagst, daß Du eigentlich nicht weißt, worum es da geht und „Simulationsprogramme” in Haskell programmierst, was soll dann überhaupt die Diskussion? Was versprichst Du Dir davon, mit ziemlich unsinnigen und willkürlich aus ganz anderen Themen zusammengestoppelten Pseudoargumenten und wilden Behauptungen etwas diskutieren zu wollen, wenn Du es nicht verstanden hast?

Sorry, aber für sowas ist mir meine Zeit zu schade.


datenwolf
23.9.2011 9:30
Kommentarlink

> Und wenn Du kein Informatiker bist

Stimmt, ich bin Physiker. Habe das studiert, weil mir die Informatikstudiengänge an den hießigen Unis zu praxisfern sind. Ich wollte damit zum Ausdruck bringen, dass ich eben nicht im Informatik-Elfenbeinturm lebe, sondern konkret Software für praktische Anwendungen entwickle.

> und selbst sagst, daß Du eigentlich nicht weißt

Das habe ich nicht gesagt, die Bücher in meinem nicht-rein-mathematischen Lehrbuchregal sind ATM ca. 2/3 Informatik (Compilerbau, Betriebssysteme, Kryptographie, Bildverarbeitung), und 1/3 Physik – aus dem einfachen Grund, dass sich die Physik in ihren Grundlagen doch recht kompakt hinschreiben lässt, man aber in der Informatik ständig etwas neues findet.

> Und der ColdBoot-Krempel geht auch völlig am Thema vorbei, denn erstens stimmt er so nicht, zweitens setzt er physikalischen Zugriff voraus.

a) Wenn eine CPU-Architektur (siehe erwähnte Lambda-CPU) es gar nicht mehr ermöglicht Speicher beliebig zu adressieren, weil ihr dazu schlicht die Instruktionen fehlen, dann bleibt aber nur der physikalische Zugriff.

b) Die ColdBoot-Leute haben das damals auf dem 25c3 in einem Workshop in der Praxis vorgeführt.

C++ habe ich in’s Spiel gebracht, weil Funktion+Objektinstanz-Kontext als funktionales Programmieren bezeichnet wurde. Was es einfach nicht ist. Ich hätte auch Java als Beispiel nehmen können. Natürlich kann ich funktionale Strukturen auch in imperativen Sprachen abbilden, jeder Compiler für eine funktionale Sprache tut das ja. Nur sieht das dann halt überhaupt nicht mehr wie ein “normales”, in entsprechender Zielsprache geschriebenes Programm aus.

> Funktionales Programmieren beruht fundamental darauf, daß Daten nie in sich selbst verändert werden, sondern immer nur Funktionswerte zurückgegeben werden.

> Unter rein funktionalem Programmieren kann man Daten niemals löschen, sondern sie nur „vergessen” und der garbage collection überlassen. Völlig inakzeptabel im Sicherheitsbereich.

Wieso? Ein Garbage Collector bräuchte bei der Freigabe die Speicherstellen doch nur mit hoher Entropie überschreiben.

Tut mir leid, ich kann es nicht anders sagen, aber Du kommst mir da jetzt gerade ein wenig vor wie der Professor in Adele der nur Fouriertransformation kennt und alle anderen Aspekte komplett aus den Augen verliert. Du stützt Dich mit der Aussage “funktionale Programmierung ist im Sicherheitsbereich inakzeptabel” alleine auf die eine Eigenschaft der Immutabilität, weil das ein Problem für Kryptoimplementierungen /sein könnte/, ohne nur in Betracht zu ziehen, dass es im Hintergrund dann doch nicht so ist. Weiterhin gibt es Sicherheitsanwendungen die absolut nichts mit Vertraulichkeit zu tun haben und in diesem Bereich ist es dann auch schnurz, ob man Speicher wieder überschreibt, oder nicht (eben die schon zwei mal erwähnte Validierung von Daten). Wobei ja die ganze Idee von “ich überschreibe vor der Freigabe meine Variablen” eh komplett nutzlos ist, wenn Virtuelle Maschinen und Instanzmigration in’s Spiel kommen.

Wenn man vertraulichen Speicher am Ende der Nutzung wieder überschreibt, dann um zu verhindern, dass er nach Freigabe durch Speicherallokationen in anderen Prozessen auftaucht und dort uninitialisiert ausgelesen wird. Dieses Überschreiben vor Freigabe ist aber ein fürchterlicher Kludge, der grundsätzliche Mängel aktueller Systeme zu kaschieren. Würde man das ordentlich angehen, dann würde die CPU anbieten nicht nur zu Pagen, sondern jede Page mit einem Schlüssel zu versehen und in-situ zu ent-/verschlüsseln. Beim Betriebssystem holte man sich entsprechenden Speicher speziell als “vertraulichen” Speicher. Da irgendwie zu versuchen diese Lecks aus dem Programm selbst heraus abzudichten wird man nie richtig hinbekommen. Das mit der online-Krypto beim Speicherzugriff versucht Intel ja gerade an den Markt zu bringen.


Hadmut
23.9.2011 12:16
Kommentarlink

@datenwolf: Rote Karte.

Dieses Geschwafel hat überhaupt nichts mehr mit dem Thema zu tun.

Und was diese abstruse Lambda-CPU macht, ist völlig irrelevant, weil wir hier eben nicht Lambda-CPUs sondern Milliarden normale PC herumstehen haben, und mit denen müssen wir klarkommen. Es geht ja nicht darum, daß es eine (derzeit nicht existente) Architektur geben könnte, auf der funktionale Programmierung sicher sein könnte, sondern darum, was wir heute und jetzt haben. Und dieser Lambda-CPU-Käse wird sich in den nächsten 10 Jahren ganz sicher nicht durchsetzen.

Du kannst darüber gerne diskutieren. Ich will das Thema nicht abwerten oder verdammen (weshalb der Vorwurf mit den Fouriertransformationen völliger Quatsch ist).

Aber es geht hier nunmal nicht darum, einfach irgendwas zu diskutieren, sondern um das Thema des jeweiligen Blog-Artikels. Und das verfehlst Du erstens meilenweit, und zweitens argumentierst Du völlig unsachlich mit einer fiktiven CPU-Architektur, die es noch nicht einmal gibt. Hier geht es um Praxis und damit um die Architekturen, die man im Laden kaufen kann.

Es reicht nicht, irgendwas tolles zu sagen. Man muß auch das Thema treffen können. Und das kannst Du gar nicht, nach dem, was Du bisher schreibst.

Außerdem gehen mir solche Rechthabereien, daß Leute sich einfach irgendwelche beliebigen weithergeholten Themenwechsel aus der Luft greifen, um irgend eine abstruse Meinung zu begründen, ziemlich auf die Nerven.

Bisher hast Du ja nicht mal nachvollziehbar beschrieben, was dieses Maschinenmodell genau sein soll. Auf der Ebene kann man nicht diskutieren, wenn einer eine Phantasie hat und sich ein Modell mit irgendwelchen Wundereigenschaften ausdenkt, und die anderen nicht mal eine genaue Beschreibung bekommen. Solche Universalrechthabereien mag ich gar nicht.