Welche Programmiersprachen lernen?

the next big thing Golo Roden  –  231 Kommentare

Persönliche Weiterentwicklung ist für viele Entwicklerinnen und Entwickler gerade zu Beginn eines neuen Jahres häufig ein großes Thema. Besonders gut eignet sich dazu das Lernen einer neuen Programmiersprache. Welche Sprachen bieten sich an?

Die vergangene Woche war für viele Entwicklerinnen und Entwickler die erste Arbeitswoche des neuen Jahres. Ein neues Jahr ist für viele Menschen häufig mit guten Vorsätzen verbunden, insbesondere im Bereich der persönlichen Weiterentwicklung. Um dieses Thema ging es auch bereits im Dezember des vergangenen Jahres ausführlich im Adventsspecial von the native web. Daher bietet es sich an, die dort ausgesprochenen Empfehlungen als Grundlage für gute Vorsätze zu verwenden.

Eine der Empfehlungen war, regelmäßig neue Programmiersprachen zu lernen, da das das Beschäftigen mit Theorie und Praxis auf elegantem Weg verbindet. Aus naheliegenden Gründen ist es kaum möglich, in zahlreichen Sprachen gleichermaßen bewandert zu sein – trotzdem lässt sich aus der Beschäftigung mit anderen Sprachen gerade konzeptionelles Wissen sehr gut extrahieren, das man anschließend auf den eigenen Alltag transferieren kann.

In diesem Artikel werden fünf Sprachen vorgeschlagen, alte und junge, und naturgemäß ist eine solche Auswahl stets subjektiv. Für jede Sprache wird daher begründet, was für sie spricht und warum sie ausgewählt wurde, aber die Liste stellt keine objektive Wahrheit dar. Dennoch lässt sich aus der Beschäftigung mit diesen fünf Sprachen sicherlich genug Wissenswertes lernen, dass sich der Aufwand rentiert.

Assembler

Den Anfang macht Assembler, was letztlich nichts anderes ist als Maschinensprache, die in eine menschenlesbare Form gebracht wurde. Assembler entspricht also nicht dem Binärcode, der nur aus Nullen und Einsen besteht, sondern den sogenannten Opcodes. Das sind die Befehle, die eine CPU kennt und verarbeiten kann. Beispiele dafür aus x86-Assembler wären MOV, mit dem ein Wert in einem Register abgelegt werden kann, und ADD, mit dem zwei Werte addiert werden können.

Obwohl Assembler heutzutage kaum noch praktische Relevanz hat, liefert die Beschäftigung mit dieser Sprache ein hervorragendes Grundverständnis für den Aufbau und die Funktionsweise von Computern, insbesondere der CPU und deren Zusammenarbeit mit dem Speicher. Dieses Wissen ist deshalb wichtig, weil die modernen Hochsprachen letztlich nur Abstraktionsebenen über diese Schicht darstellen.

Jede Abstraktion ist jedoch zu einem gewissen Maß brüchig: Compiler sind zwar sehr gut darin, Code aus Hochsprachen in optimierten Maschinencode zu übersetzen, dennoch gibt es Situationen, in denen der erzeugte Code unerwartet langsam oder träge läuft, weil ein Spezialfall im Code von der CPU nur sehr umständlich verarbeitet werden kann. Deshalb ist es hilfreich zu verstehen, was unter der Haube passiert, um beispielsweise Performance und Effizienz von Code besser beurteilen und optimieren zu können.

Neue Sprachen lernen: Assembler

Go

Anders als bei Assembler handelt es sich bei Go um eine verhältnismäßig junge Sprache. Die erste stabile Version wurde 2012 von Google vorgestellt. Die Idee hinter Go war, eine Sprache wie C und C++ zu entwickeln, aber ohne deren historische Altlasten, quasi eine Art "modernes C". Dieses Ziel merkt man Go durchaus an, denn es eignet sich weniger für die Anwendungsentwicklung als vielmehr für systemnahe Entwicklung. Gerade im Cloud-Bereich wird Go daher vielfach genutzt.

Bemerkenswert an Go ist, dass großer Wert auf Einfachheit und Klarheit gelegt wurde. Beispielsweise gibt es nur einen einzigen Schleifentyp. Auf Exceptions wird gänzlich verzichtet, stattdessen geben Funktionen Fehler als Bestandteil des Rückgabewerts zurück, was im Vergleich zu try-catch-Konstrukten zu linearerem und häufig besser lesbarem und damit verständlicherem Code führt.

Das Typsystem von Go ist statisch, außerdem unterstützt Go die objektorientierte Programmierung. Allerdings ist das Typsystem nicht nominal wie das von C# und Java, sondern strukturell wie das von TypeScript. Interfaces müssen also nicht explizit implementiert werden, es genügt, wenn ein Typ die passende äußere Form aufweist. Go arbeitet darüber hinaus mit einer Garbage Collection und kennt zwar Pointer, aber keine Pointerarithmetik.

Der Compiler von Go erzeugt statisch gelinkte Binaries, die ohne zusätzliche Laufzeitumgebung oder Bibliotheken auskommen. Bemerkenswert ist, dass der Compiler auch Binaries für andere Plattformen erzeugen kann als nur für jene, auf der er betrieben wird.

Eine große Besonderheit von Go ist das Konzept zur asynchronen Programmierung. Nebenläufigkeit wird mit sogenannten Go-Routinen umgesetzt, die über sogenannte Channels miteinander kommunizieren. Ein Channel stellt dabei eine Art In-Memory-Message-Queue dar, die außer zur Kommunikation auch zur Synchronisation von Go-Routinen dienen kann.

Dieses Thema ist in Verbindung mit der Option, kompakte und effiziente Binaries für verschiedene Plattformen erzeugen zu können, ein gutes Argument, sich mit Go zu befassen.

Neue Sprachen lernen: Go

Haskell

Haskell ist im Gegensatz zu Go eine funktionale Sprache, genau genommen sogar eine rein funktionale Sprache. Ursprünglich 1990 vorgestellt, gibt es inzwischen zahlreiche verschiedene Implementierungen, von denen die wichtigste aber der Glasgow Haskell Compiler (GHC) sein dürfte. Dass es sich bei Haskell um eine rein funktionale Sprache handelt, bedeutet, dass Funktionen generell keine Seiteneffekte aufweisen und "pure" sind, imperative Sprachkonstrukte gibt es nicht.

Aspekte wie I/O, die auf Seiteneffekte angewiesen sind, werden in Haskell über das Typsystem umgesetzt. In Verbindung mit Monaden und der sogenannten "do-Notation" wird quasi-imperativer Code ermöglicht, der unter der Haube aber dennoch auf funktionalen Konstrukten fußt. Das Typsystem ist statisch, unterstützt aber in hohem Maße Typinferenz, weshalb man Entwicklerin oder Entwickler Typen nur selten von Hand angeben müssen.

Da Haskell darüber hinaus Typvariablen kennt, lassen sich Funktionen oftmals flexibel und generisch schreiben, aber typspezifisch verwenden. Aufgrund des funktionalen Paradigmas kommt man auch mit zahlreichen anderen funktionalen Konstrukten in Berührung, von Funktionen höherer Ordnung über Currying und algebraische Datentypen bis hin zu Lazy Evaluation, Infinite Generators und Pattern Matching. Daher ist Haskell eine ausgezeichnete Sprache, um funktionale Konstrukte kennenzulernen.

Viele dieser Konstrukte lassen sich in anderen Sprachen nicht originär abbilden, aber dennoch geben sie neue Impulse und erweitern den persönlichen Horizont.

Neue Sprachen lernen: Haskell

Lisp

Lisp ist die nach heutigen Maßstäben zweitälteste Programmiersprache nach Fortran. Eingeführt im Jahr 1958 von John McCarthy, hat Lisp bis heute nichts von seiner Eleganz verloren. Lisp basiert auf dem Lambda-Kalkül und bietet eine ausgesprochen einfache, aber zugleich extrem flexible und mächtige Syntax. Dementsprechend ist Lisp außerdem multiparadigmatisch, die Sprache unterstützt prozedurale ebenso wie funktionale und objektorientierte Programmierung.

Viele der Sprachkonstrukte, die heute selbstverständlich scheinen, haben ihren Ursprung in Lisp. Dazu zählen Bedingungen, Rekursion, Funktionen als Datentypen, dynamische Typisierung, Garbage Collection, ein Symbol-Datentyp und Metaprogrammierung. Eine Besonderheit ist die sogenannte Homoikonizität. Das bedeutet, dass Daten und Code in Lisp die gleiche Form aufweisen – weshalb es verhältnismäßig leicht ist, Programme zu schreiben, die sich selbst modifizieren oder die gänzlich neue Programme schreiben.

All diese Aspekte zeigen, warum man sich mit Lisp beschäftigen sollte: Der US-amerikanische Informatiker Eric S. Raymond hat einmal gesagt, dass Lisp selbst dann eine lernenswerte Sprache sei, wenn man sie niemals praktisch verwenden würde, der Erkenntnisgewinn allein trage dazu bei, eine bessere Entwicklerin beziehungsweise ein besserer Entwickler zu werden. Dem ist kaum etwas hinzuzufügen.

Wer sich mit Lisp beschäftigen will, stößt (wie bei Haskell) auf zahlreiche verschiedene Implementierungen, unter anderem Common Lisp, Schema und Clojure. Der bekannteste Urenkel von Lisp ist jedoch JavaScript: Die Sprache enthält ungemein viele Anleihen an Lisp, tatsächlich war das ursprüngliche Ziel für JavaScript, ein Lisp mit C-artiger Syntax für den Webbrowser zu entwickeln. Wer Lisp lernt, erfährt sehr viel auch über JavaScript und verbessert auf dem Weg das Verständnis dieser Sprache.

Neue Sprachen lernen: Lisp

Python

Python ist von allen genannten Sprachen vermutlich die mit der höchsten Verbreitung. In den vergangenen Jahren hat Python sehr viel Zulauf erfahren, vor allem in den Bereichen der künstlichen Intelligenz und des maschinellen Lernens. Dabei ist Python jedoch keine neue Sprache. Die Ursprünge gehen zurück auf das Jahr 1991, in dem Guido van Rossum die erste Version vorstellte. Ziele von Python waren Einfachheit und Übersichtlichkeit, zwei Faktoren, die sich Python bis heute erhalten hat.

Auch Python ist multiparadigmatisch. Das Typsystem ist dynamisch, wobei es zumindest optional statische Typannotationen gibt. Auffällig ist die außergewöhnlich große Standardbibliothek und die Verfügbarkeit zahlreicher Bibliotheken für den wissenschaftlichen Gebrauch, beispielsweise NumPy und SciPy. Aus diesem Grund wurden viele Bibliotheken für künstliche Intelligenz und maschinelles Lernen für Python entwickelt, allen voran TensorFlow und Keras. Daher ist Python inzwischen die De-facto-Sprache für dieses Umfeld.

Erwähnenswert ist aber auch der "Zen of Python", eine Sammlung von 19 Aphorismen, die grundlegende Prinzipien der Entwicklung beschreiben. Gerade sie sind auch hervorragend auf andere Sprachen übertragbar und vielleicht aus der Sicht des Lernens der wichtigste Faktor, den Python zum Erkenntnisgewinn beizutragen hat.

Neue Sprachen lernen: Python

Fazit

Assembler, Go, Haskell, Lisp und Python – wer den Entschluss fast, sich im Lauf des Jahres 2021 mit diesen Sprachen zu beschäftigen, hat eine gute Ausgangsbasis, Neues zu lernen, was auch außerhalb der genannten Sprachen nützlich ist. Besonders praktisch ist, dass die genannten Sprachen auch eine gewisse Bandbreite abdecken, von alt bis jung, von systemnah bis zu künstlicher Intelligenz, von prozedural über objektorientiert bis hin zu funktional.

Und wie gesagt ist das Ziel bei alledem nicht, am Jahresende in jeder dieser Sprachen professionell arbeiten zu können. Oftmals sind es die kleinen Erkenntnisse zwischen den Zeilen, die insgesamt viel mehr bewirken, als der Versuch, gleichzeitig auf allen Hochzeiten zu tanzen, was letztlich ohnehin nicht funktioniert. In diesem Sinne: Viel Spaß und Erfolg!