Warum Kotlin?

Programme sollen so geschrieben werden, dass Menschen sie lesen können, und erst in zweiter Linie für Maschinen, die sie ausführen.Harold Abelson, Mitautor, Structure and Interpretation of Computer Programs.

Dieses Kapitel bietet einen Überblick über die historische Entwicklung von Programmiersprachen, damit Sie verstehen, wo Kotlin einzuordnen ist und warum Sie es lernen möchten. Wir führen einige Themen ein, die, wenn Sie ein Anfänger sind, momentan zu kompliziert erscheinen mögen. Fühlen Sie sich frei, dieses Kapitel zu überspringen und später darauf zurückzukommen, nachdem Sie mehr vom Buch gelesen haben.

Die Gestaltung von Programmiersprachen ist ein evolutionärer Weg, der von der Erfüllung der Bedürfnisse der Maschine zur Erfüllung der Bedürfnisse des Programmierers führt.

Eine Programmiersprache wird von einem Sprachdesigner erfunden und als eines oder mehrere Programme implementiert, die als Werkzeuge zur Nutzung der Sprache dienen. Der Implementierer ist in der Regel der Sprachdesigner, zumindest anfangs.

Frühe Sprachen konzentrierten sich auf Hardwarebeschränkungen. Mit zunehmender Rechenleistung der Computer verlagerten sich neuere Sprachen hin zu anspruchsvollerer Programmierung mit einem Schwerpunkt auf Zuverlässigkeit. Diese Sprachen können Merkmale basierend auf der Psychologie des Programmierens wählen.

Jede Programmiersprache ist eine Sammlung von Experimenten. Historisch gesehen war das Design von Programmiersprachen eine Abfolge von Vermutungen und Annahmen darüber, was Programmierer produktiver machen könnte. Einige dieser Experimente scheitern, einige sind mäßig erfolgreich und einige sind sehr erfolgreich.

Wir lernen aus den Experimenten jeder neuen Sprache. Einige Sprachen befassen sich mit Problemen, die sich als nebensächlich statt wesentlich erweisen, oder die Umgebung ändert sich (schnellere Prozessoren, günstigere Speicher, neues Verständnis von Programmierung und Sprachen) und dieses Problem wird weniger wichtig oder sogar unbedeutend. Wenn diese Ideen veraltet sind und sich die Sprache nicht weiterentwickelt, verschwindet sie aus der Verwendung.

Die ursprünglichen Programmierer arbeiteten direkt mit Zahlen, die Prozessor-Maschinenbefehle darstellten. Dieser Ansatz führte zu zahlreichen Fehlern, und Assemblersprache wurde geschaffen, um die Zahlen durch mnemonische Opcodes—Wörter, die sich Programmierer leichter merken und lesen konnten, zusammen mit anderen hilfreichen Werkzeugen zu ersetzen. Es gab jedoch immer noch eine Eins-zu-eins-Entsprechung zwischen Assemblerbefehlen und Maschinenbefehlen, und Programmierer mussten jede Zeile Assemblercode schreiben. Darüber hinaus verwendete jeder Computerprozessor seine eigene spezifische Assemblersprache.

Das Entwickeln von Programmen in Assemblersprache ist äußerst kostspielig. Höhere Programmiersprachen helfen, dieses Problem zu lösen, indem sie eine Abstraktionsebene von den niedrigeren Assemblersprachen schaffen.

Compiler und Interpreter

Die Anweisungen einer interpretierten Sprache werden direkt von einem Programm namens Interpreter ausgeführt. Kotlin wird kompiliert statt interpretiert. Der Quellcode einer kompilierten Sprache wird in eine andere Darstellung umgewandelt, die als eigenes Programm läuft, entweder direkt auf einem Hardwareprozessor oder auf einer virtuellen Maschine, die einen Prozessor emuliert:

Sprachen wie C, C++, Go und Rust werden in Maschinencode kompiliert, der direkt auf der zugrunde liegenden Hardware-Zentralverarbeitungseinheit (CPU) läuft. Sprachen wie Java und Kotlin werden in Bytecode kompiliert, der ein Zwischenformat ist, das nicht direkt auf der Hardware-CPU läuft, sondern auf einer virtuellen Maschine, einem Programm, das Bytecode-Anweisungen ausführt. Programme, die von der JVM-Version von Kotlin erzeugt werden, laufen auf der Java Virtual Machine (JVM).

Die Portabilität ist ein wichtiger Vorteil einer virtuellen Maschine. Der gleiche Bytecode kann auf jedem Computer laufen, der eine virtuelle Maschine hat. Virtuelle Maschinen können für spezielle Hardware optimiert werden und Geschwindigkeitsprobleme lösen. Die JVM enthält viele Jahre solcher Optimierungen und wurde auf vielen Plattformen implementiert.

Zur Kompilierungszeit wird der Code vom Compiler überprüft, um Kompilierungsfehler zu entdecken. (IntelliJ IDEA und andere Entwicklungsumgebungen heben diese Fehler hervor, wenn Sie den Code eingeben, sodass Sie schnell Probleme entdecken und beheben können). Wenn es keine Kompilierungsfehler gibt, wird der Quellcode in Bytecode kompiliert.

Ein Laufzeitfehler kann zur Kompilierungszeit nicht entdeckt werden, daher tritt er erst auf, wenn Sie das Programm ausführen. Typischerweise sind Laufzeitfehler schwieriger zu entdecken und teurer zu beheben. Statisch typisierte Sprachen wie Kotlin entdecken so viele Fehler wie möglich zur Kompilierungszeit, während dynamische Sprachen ihre Sicherheitsprüfungen zur Laufzeit durchführen (einige dynamische Sprachen führen nicht so viele Sicherheitsprüfungen durch, wie sie könnten).

Sprachen, die Kotlin beeinflusst haben

Kotlin zieht seine Ideen und Merkmale aus vielen Sprachen, und diese Sprachen wurden von früheren Sprachen beeinflusst. Es ist hilfreich, etwas über die Geschichte der Programmiersprachen zu wissen, um Perspektiven zu gewinnen, wie wir zu Kotlin gekommen sind. Die hier beschriebenen Sprachen wurden wegen ihres Einflusses auf die nachfolgenden Sprachen ausgewählt. All diese Sprachen inspirierten letztendlich das Design von Kotlin, manchmal indem sie ein Beispiel dafür waren, was man nicht tun sollte.

FORTRAN: FORmula TRANslation (1957)

Entwickelt für den Einsatz durch Wissenschaftler und Ingenieure, war das Ziel von Fortran, das Codieren von Gleichungen zu erleichtern. Fein abgestimmte und getestete Fortran-Bibliotheken sind noch heute im Einsatz, werden jedoch typischerweise “umwickelt”, um sie von anderen Sprachen aus aufrufbar zu machen.

LISP: LISt Processor (1958)

Anstatt anwendungsspezifisch zu sein, verkörperte LISP wesentliche Programmierkonzepte; es war die Sprache der Informatiker und die erste funktionale Programmiersprache (Sie werden in diesem Buch über funktionale Programmierung lernen). Der Kompromiss für seine Macht und Flexibilität war die Effizienz: LISP war typischerweise zu teuer, um auf frühen Maschinen ausgeführt zu werden, und erst in den letzten Jahrzehnten wurden Maschinen schnell genug, um eine Wiederbelebung der Nutzung von LISP zu ermöglichen. Zum Beispiel ist der GNU Emacs-Editor vollständig in LISP geschrieben und kann mit LISP erweitert werden.

ALGOL: ALGOrithmic Language (1958)

Wahrscheinlich die einflussreichste der Sprachen der 1950er Jahre, da sie eine Syntax einführte, die in vielen nachfolgenden Sprachen Bestand hatte. Zum Beispiel sind C und seine Derivate “ALGOL-ähnliche” Sprachen.

COBOL: COmmon Business-Oriented Language (1959)

Entwickelt für Geschäft, Finanzen und administrative Datenverarbeitung. Es hat eine englischartige Syntax und sollte selbstdokumentierend und sehr lesbar sein. Obwohl diese Absicht im Allgemeinen scheiterte—COBOL ist berüchtigt für Fehler, die durch ein fehlplatziertes Punktzeichen eingeführt wurden—zwang das US-Verteidigungsministerium die weitverbreitete Einführung auf Großrechnern, und Systeme laufen (und erfordern Wartung) noch heute.

BASIC: Beginners’ All-purpose Symbolic Instruction Code (1964)

BASIC war einer der frühen Versuche, Programmieren zugänglich zu machen. Obwohl sehr erfolgreich, waren seine Funktionen und Syntax begrenzt, sodass es nur teilweise hilfreich für Menschen war, die anspruchsvollere Sprachen lernen mussten. Es ist überwiegend eine interpretierte Sprache, was bedeutet, dass man den ursprünglichen Code für das Programm benötigt, um es auszuführen. Trotzdem wurden viele nützliche Programme in BASIC geschrieben, insbesondere als Skriptsprache für Microsofts “Office”-Produkte. BASIC könnte sogar als die erste “offene” Programmiersprache betrachtet werden, da zahlreiche Variationen davon erstellt wurden.

Simula 67, die ursprüngliche objektorientierte Sprache (1967)

Eine Simulation beinhaltet typischerweise viele “Objekte”, die miteinander interagieren. Verschiedene Objekte haben unterschiedliche Eigenschaften und Verhaltensweisen. Die zu der Zeit existierenden Sprachen waren unhandlich für Simulationen zu verwenden, daher wurde Simula (eine weitere “ALGOL-ähnliche” Sprache) entwickelt, um direkte Unterstützung für die Erstellung von Simulationsobjekten zu bieten. Es stellt sich heraus, dass diese Ideen auch für allgemeine Programmierung nützlich sind, und dies war der Ursprung der objektorientierten (OO) Sprachen.

Pascal (1970)

Pascal erhöhte die Kompilierungsgeschwindigkeit, indem es die Sprache so einschränkte, dass sie als Einzelpass-Compiler implementiert werden konnte. Die Sprache zwang den Programmierer, ihren Code auf eine bestimmte Weise zu strukturieren und legte etwas umständliche und weniger lesbare Einschränkungen für die Programmorganisation auf. Da Prozessoren schneller wurden, Speicher billiger und die Compiler-Technologie besser, wurden die Auswirkungen dieser Einschränkungen zu kostspielig.

Eine Implementierung von Pascal, Turbo Pascal von Borland, arbeitete zunächst auf CP/M-Maschinen und machte dann den Sprung zu frühen MS-DOS (Vorläufer von Windows), später entwickelte es sich zur Delphi-Sprache für Windows. Indem alles im Speicher untergebracht wurde, kompilierte Turbo Pascal in atemberaubender Geschwindigkeit auf sehr leistungsschwachen Maschinen, was das Programmerlebnis dramatisch verbesserte. Sein Schöpfer, Anders Hejlsberg, entwarf später sowohl C# als auch TypeScript.

Niklaus Wirth, der Erfinder von Pascal, schuf nachfolgende Sprachen: Modula, Modula-2 und Oberon. Wie der Name schon sagt, konzentrierte sich Modula auf die Aufteilung von Programmen in Module, für bessere Organisation und schnellere Kompilierung. Die meisten modernen Sprachen unterstützen separate Kompilierung und eine Form von Modulsystem.

C (1972)

Trotz der zunehmenden Zahl von Hochsprachen schrieben Programmierer immer noch in Assemblersprache. Dies wird oft als Systemprogrammierung bezeichnet, da es auf Ebene des Betriebssystems erfolgt, umfasst aber auch eingebettete Programmierung für spezielle physische Geräte. Dies ist nicht nur mühsam und teuer (Bruce begann seine Karriere mit dem Schreiben von Assemblersprache für eingebettete Systeme), sondern es ist auch nicht portabel—Assemblersprache kann nur auf dem Prozessor laufen, für den sie geschrieben wurde. C wurde als “hochlevelige Assemblersprache” entworfen, die dennoch nah genug an der Hardware ist, dass man selten Assemblersprache schreiben muss. Noch wichtiger ist, dass ein C-Programm auf jedem Prozessor mit einem C-Compiler läuft. C entkoppelte das Programm vom Prozessor, was ein großes und teures Problem löste. Als Ergebnis konnten ehemalige Assemblersprachen-Programmierer in C weitaus produktiver sein. C war so effektiv, dass neuere Sprachen (insbesondere Go und Rust) immer noch versuchen, es für die Systemprogrammierung abzulösen.

Smalltalk (1972)

Von Anfang an als rein objektorientiert konzipiert, hat Smalltalk die OO- und Sprachtheorie erheblich vorangebracht, indem es eine Plattform für Experimente war und die schnelle Anwendungsentwicklung demonstrierte. Es wurde jedoch in einer Zeit entwickelt, als Sprachen noch proprietär waren, und der Einstiegspreis für ein Smalltalk-System konnte in die Tausende gehen. Es war interpretiert, sodass man eine Smalltalk-Umgebung benötigte, um Programme auszuführen. Open-Source-Smalltalk-Implementierungen erschienen erst, nachdem die Programmierwelt sich weiterentwickelt hatte. Smalltalk-Programmierer haben großartige Einblicke geliefert, die späteren OO-Sprachen wie C++ und Java zugutekamen.

C++: Ein besseres C mit Objekten (1983)

Bjarne Stroustrup schuf C++, weil er ein besseres C wollte und Unterstützung für die objektorientierten Konstrukte, die er bei der Verwendung von Simula-67 erlebt hatte. Bruce war acht Jahre lang Mitglied des C++-Normungsausschusses und schrieb drei Bücher über C++, darunter Thinking in C++.

Rückwärtskompatibilität mit C war ein grundlegendes Prinzip des C++-Designs, sodass C-Code in C++ mit praktisch keinen Änderungen kompiliert werden kann. Dies bot einen einfachen Migrationspfad - Programmierer konnten weiterhin in C programmieren, die Vorteile von C++ nutzen und langsam mit C++-Funktionen experimentieren, während sie produktiv blieben. Die meisten Kritiken an C++ lassen sich auf die Einschränkung der Rückwärtskompatibilität mit C zurückführen.

Eines der Probleme bei C war das Thema Speicherverwaltung. Der Programmierer muss zuerst Speicher erwerben, dann eine Operation mit diesem Speicher ausführen und dann den Speicher freigeben. Das Vergessen, Speicher freizugeben, wird als Speicherleck bezeichnet und kann dazu führen, dass der verfügbare Speicher aufgebraucht wird und der Prozess abstürzt. Die anfängliche Version von C++ machte einige Innovationen in diesem Bereich, zusammen mit Konstruktoren, um eine ordnungsgemäße Initialisierung sicherzustellen. Spätere Versionen der Sprache haben bedeutende Verbesserungen in der Speicherverwaltung vorgenommen.

Python: Freundlich und flexibel (1990)

Der Designer von Python, Guido Van Rossum, schuf die Sprache basierend auf seiner Inspiration des „Programmieren für alle“. Seine Pflege der Python-Community hat ihr den Ruf verliehen, die freundlichste und unterstützendste Community in der Programmierwelt zu sein. Python war eine der ersten Open-Source-Sprachen, was zu Implementierungen auf praktisch jeder Plattform führte, einschließlich eingebetteter Systeme und maschinellem Lernen. Seine Dynamik und Benutzerfreundlichkeit machen es ideal für die Automatisierung kleiner, sich wiederholender Aufgaben, aber seine Funktionen unterstützen auch die Erstellung großer, komplexer Programme.

Python ist eine echte “Grassroots”-Sprache; es hatte nie ein Unternehmen, das es förderte, und die Einstellung seiner Fans war, die Sprache niemals zu pushen, sondern einfach jedem zu helfen, der sie lernen möchte. Die Sprache verbessert sich stetig, und in den letzten Jahren ist ihre Popularität explodiert.

Python könnte die erste Mainstream-Sprache gewesen sein, die funktionale und OO-Programmierung kombinierte. Es war Java voraus mit automatischer Speicherverwaltung durch Müllabfuhr (normalerweise müssen Sie selbst nie Speicher zuweisen oder freigeben) und der Fähigkeit, Programme auf mehreren Plattformen auszuführen.

Haskell: Reine funktionale Programmierung (1990)

Inspiriert von Miranda (1985), einer proprietären Sprache, wurde Haskell als offener Standard für die Forschung zur reinen funktionalen Programmierung geschaffen, obwohl es auch für Produkte verwendet wurde. Syntax und Ideen von Haskell haben eine Reihe nachfolgender Sprachen beeinflusst, darunter Kotlin.

Java: Virtuelle Maschinen und Müllabfuhr (1995)

James Gosling und sein Team erhielten die Aufgabe, Code für eine TV-Set-Top-Box zu schreiben. Sie entschieden, dass sie C++ nicht mochten und anstatt die Box zu erstellen, entwickelten sie die Java-Sprache. Das Unternehmen, Sun Microsystems, setzte einen enormen Marketingdruck hinter die kostenlose Sprache (damals eine neue Idee), um die aufkommende Internetlandschaft zu dominieren.

Dieses wahrgenommene Zeitfenster für die Internet-Dominanz setzte das Java-Sprachdesign unter erheblichen Druck, was zu einer beträchtlichen Anzahl von Mängeln führte (Das Buch Thinking in Java beleuchtet diese Mängel, damit die Leser darauf vorbereitet sind, mit ihnen umzugehen). Brian Goetz bei Oracle, der derzeitige leitende Entwickler von Java, hat bemerkenswerte und überraschende Verbesserungen an Java vorgenommen, trotz der Einschränkungen, die er geerbt hat. Obwohl Java bemerkenswert erfolgreich war, ist ein wichtiges Kotlin-Designziel, die Mängel von Java zu beheben, damit Programmierer produktiver sein können.

Der Erfolg von Java beruht auf zwei innovativen Funktionen: einer virtuellen Maschine und Müllabfuhr. Diese waren in anderen Sprachen verfügbar - zum Beispiel haben LISP, Smalltalk und Python Müllabfuhr, und UCSD Pascal lief auf einer virtuellen Maschine -, aber sie wurden nie als praktikabel für Mainstream-Sprachen angesehen. Java änderte das und machte Programmierer dadurch erheblich produktiver.

Eine virtuelle Maschine ist eine Zwischenebene zwischen der Sprache und der Hardware. Die Sprache muss keinen Maschinencode für einen bestimmten Prozessor erzeugen; sie muss nur eine Zwischen-Sprache (Bytecode) erzeugen, die auf der virtuellen Maschine läuft. Virtuelle Maschinen erfordern Rechenleistung und wurden vor Java als unpraktisch angesehen. Die Java Virtual Machine (JVM) führte zu Javas Slogan “write once, run everywhere.” Darüber hinaus können andere Sprachen leichter entwickelt werden, indem sie die JVM anvisieren; Beispiele umfassen Groovy, eine Java-ähnliche Skriptsprache, und Clojure, eine Version von LISP.

Die Müllabfuhr löst das Problem, das Freigeben von Speicher zu vergessen, oder wenn es schwierig ist, zu wissen, wann ein Speicherplatz nicht mehr genutzt wird. Projekte wurden erheblich verzögert oder sogar abgebrochen wegen Speicherlecks. Obwohl die Müllabfuhr in einigen früheren Sprachen vorkommt, galt sie als inakzeptabel aufwändig, bis Java ihre Praktikabilität demonstrierte.

JavaScript: Nur dem Namen nach Java (1995)

Der ursprüngliche Webbrowser kopierte und zeigte einfach Seiten von einem Webserver an. Webbrowser vervielfältigten sich und wurden zu einer neuen Programmierplattform, die Sprachunterstützung benötigte. Java wollte diese Sprache sein, war aber zu umständlich für den Job. JavaScript begann als LiveScript und wurde in NetScape Navigator integriert, einen der ersten Webbrowser. Die Umbenennung in JavaScript war ein Marketingtrick von NetScape, da die Sprache nur eine vage Ähnlichkeit mit Java hat.

Als das Web aufblühte, wurde JavaScript enorm wichtig. Das Verhalten von JavaScript war jedoch so unvorhersehbar, dass Douglas Crockford ein Buch mit dem ironischen Titel JavaScript, the Good Parts schrieb, in dem er alle Probleme mit der Sprache aufzeigte, damit Programmierer sie vermeiden können. Nachfolgende Verbesserungen durch das ECMAScript-Komitee haben JavaScript für einen ursprünglichen JavaScript-Programmierer unkenntlich gemacht. Es wird jetzt als stabile und ausgereifte Sprache betrachtet.

Web-Assembly (WASM) wurde von JavaScript abgeleitet, um eine Art Bytecode für Webbrowser zu sein. Es läuft oft viel schneller als JavaScript und kann von anderen Sprachen generiert werden. Zum Zeitpunkt des Schreibens arbeitet das Kotlin-Team daran, WASM als Ziel hinzuzufügen.

C#: Java für .NET (2000)

C# wurde entwickelt, um einige der wichtigen Fähigkeiten von Java auf der .NET (Windows) Plattform bereitzustellen, während es den Designern freistellte, sich nicht an die Java-Sprache zu halten. Das Ergebnis beinhaltete zahlreiche Verbesserungen gegenüber Java. Zum Beispiel entwickelte C# das Konzept der Erweiterungsfunktionen, die in Kotlin stark genutzt werden. C# wurde auch deutlich funktionaler als Java. Viele C#-Funktionen haben offensichtlich das Design von Kotlin beeinflusst.

Scala: SCALAble (2003)

Martin Odersky schuf Scala, um auf der Java Virtual Machine zu laufen: Um auf der Arbeit auf der JVM aufzubauen, um mit Java-Programmen zu interagieren und möglicherweise mit der Idee, dass es Java verdrängen könnte. Als Forscher nutzten Odersky und sein Team Scala als Plattform, um mit Sprachmerkmalen zu experimentieren, insbesondere solchen, die nicht in Java enthalten sind.

Diese Experimente waren erhellend, und eine Reihe davon fand in modifizierter Form ihren Weg nach Kotlin. Zum Beispiel wird die Fähigkeit, Operatoren wie + für spezielle Fälle neu zu definieren, als Operatorüberladung bezeichnet. Dies war in C++ enthalten, aber nicht in Java. Scala fügte die Operatorüberladung hinzu, erlaubt aber auch die Erfindung neuer Operatoren durch Kombination beliebiger Zeichenfolgen. Dies führt oft zu verwirrenderen Code. Eine begrenzte Form der Operatorüberladung ist in Kotlin enthalten, aber man kann nur Operatoren überladen, die bereits existieren.

Scala ist auch ein objekt-funktionales Hybrid, ähnlich wie Python, aber mit einem Fokus auf reine Funktionen und strenge Objekte. Dies inspirierte die Entscheidung von Kotlin, ebenfalls ein objekt-funktionales Hybrid zu sein.

Wie Scala läuft Kotlin auf der JVM, interagiert jedoch viel einfacher mit Java als Scala (siehe Anhang B). Darüber hinaus zielt Kotlin auf JavaScript, das Android-Betriebssystem und erzeugt nativen Code für andere Plattformen.

Atomic Kotlin entwickelte sich aus den Ideen und Materialien von Atomic Scala.

Groovy: Eine dynamische JVM-Sprache (2007)

Dynamische Sprachen sind ansprechend, weil sie interaktiver und prägnanter sind als statische Sprachen. Es gab zahlreiche Versuche, ein dynamischeres Programmiererlebnis auf der JVM zu erreichen, darunter Jython (Python) und Clojure (ein Dialekt von Lisp). Groovy war die erste, die breite Akzeptanz erreichte.

Auf den ersten Blick erscheint Groovy als bereinigte Version von Java, die ein angenehmeres Programmiererlebnis bietet. Der meiste Java-Code läuft unverändert in Groovy, sodass Java-Programmierer schnell produktiv sein können und später die anspruchsvolleren Funktionen erlernen können, die bemerkenswerte Programmierverbesserungen gegenüber Java bieten.

Die Kotlin-Operatoren ?. und ?:, die sich mit dem Problem der Leere beschäftigen, erschienen zuerst in Groovy.

Es gibt zahlreiche Groovy-Funktionen, die in Kotlin erkennbar sind. Einige dieser Funktionen erscheinen auch in anderen Sprachen, was wahrscheinlich stärker dafür drängte, dass sie in Kotlin aufgenommen wurden.

Warum Kotlin? (Eingeführt 2011, Version 1.0: 2016)

Genauso wie C++ ursprünglich als “ein besseres C” gedacht war, war Kotlin zunächst darauf ausgerichtet, “ein besseres Java” zu sein. Es hat sich seitdem erheblich über dieses Ziel hinaus entwickelt.

Kotlin wählt pragmatisch nur die erfolgreichsten und hilfreichsten Funktionen aus anderen Programmiersprachen aus—nachdem diese Funktionen in der Praxis getestet und als besonders wertvoll erwiesen wurden.

Wenn Sie also von einer anderen Sprache kommen, könnten Sie einige Funktionen dieser Sprache in Kotlin wiedererkennen. Dies ist beabsichtigt: Kotlin maximiert die Produktivität, indem es bewährte Konzepte nutzt.

Lesbarkeit

Lesbarkeit ist ein Hauptziel bei der Gestaltung der Sprache. Die Kotlin-Syntax ist prägnant—sie erfordert in den meisten Szenarien keine Förmlichkeit, kann aber dennoch komplexe Ideen ausdrücken.

Werkzeuge

Kotlin stammt von JetBrains, einem Unternehmen, das sich auf Entwicklerwerkzeuge spezialisiert hat. Es bietet erstklassige Unterstützung für Werkzeuge, und viele Sprachmerkmale wurden mit Blick auf Werkzeuge entwickelt.

Multi-Paradigma

Kotlin unterstützt mehrere Programmierparadigmen, die in diesem Buch sanft eingeführt werden:

  • Imperatives Programmieren
  • Funktionales Programmieren
  • Objektorientiertes Programmieren

Multi-Plattform

Kotlin-Quellcode kann in verschiedene Zielplattformen kompiliert werden:

  • JVM. Der Quellcode wird in JVM-Bytecode (.class Dateien) kompiliert, der dann auf jeder Java Virtual Machine (JVM) ausgeführt werden kann.
  • Android. Android hat seine eigene Laufzeitumgebung namens ART (der Vorgänger hieß Dalvik). Der Kotlin-Quellcode wird in das Dalvik Executable Format (.dex Dateien) kompiliert.
  • JavaScript, um innerhalb eines Webbrowsers ausgeführt zu werden.
  • Native Binaries durch die Generierung von Maschinencode für spezifische Plattformen und CPUs.

Dieses Buch konzentriert sich auf die Sprache selbst, wobei die JVM als einzige Zielplattform verwendet wird. Sobald Sie die Sprache beherrschen, können Sie Kotlin auf verschiedene Anwendungen und Zielplattformen anwenden.

Zwei Kotlin-Funktionen

Dieses Atom setzt nicht voraus, dass Sie ein Programmierer sind, was es schwierig macht, die meisten Vorteile von Kotlin gegenüber Alternativen zu erklären. Es gibt jedoch zwei Themen, die sehr wirkungsvoll sind und zu diesem frühen Zeitpunkt erklärt werden können: Java-Interoperabilität und das Problem, “keinen Wert” anzuzeigen.

Mühelose Java-Interoperabilität

Um “ein besseres C” zu sein, muss C++ rückwärtskompatibel mit der Syntax von C sein, aber Kotlin muss nicht rückwärtskompatibel mit der Syntax von Java sein—es muss nur mit der JVM arbeiten. Dies befreit die Kotlin-Designer, eine viel sauberere und leistungsfähigere Syntax zu schaffen, ohne das visuelle Rauschen und die Komplikationen, die Java überladen.

Damit Kotlin “ein besseres Java” ist, muss das Erlebnis, es auszuprobieren, angenehm und reibungslos sein, sodass Kotlin eine mühelose Integration mit bestehenden Java-Projekten ermöglicht. Sie können ein kleines Stück Kotlin-Funktionalität schreiben und es mitten in Ihren bestehenden Java-Code einfügen. Der Java-Code merkt nicht einmal, dass der Kotlin-Code da ist—er sieht einfach wie weiterer Java-Code aus.

Unternehmen untersuchen oft eine neue Sprache, indem sie ein eigenständiges Programm mit dieser Sprache erstellen. Idealerweise ist dieses Programm nützlich, aber nicht essentiell, sodass es bei einem Scheitern des Projekts mit minimalem Schaden beendet werden kann. Nicht jedes Unternehmen möchte die Ressourcen aufwenden, die für diese Art von Experimenten erforderlich sind. Da Kotlin sich nahtlos in ein bestehendes Java-System integriert (und von dessen Tests profitiert), wird es sehr billig oder sogar kostenlos, Kotlin auszuprobieren, um zu sehen, ob es passt.

Darüber hinaus bietet JetBrains, das Unternehmen, das Kotlin erstellt, IntelliJ IDEA in einer “Community” (kostenlosen) Version an, die Unterstützung sowohl für Java als auch für Kotlin beinhaltet und die Möglichkeit bietet, die beiden einfach zu integrieren. Es gibt sogar ein Tool, das Java-Code nimmt und ihn (größtenteils) in Kotlin umschreibt.

Anhang B behandelt Java-Interoperabilität.

Darstellung von Leere

Ein besonders vorteilhaftes Kotlin-Feature ist seine Lösung für ein herausforderndes Programmierproblem.

Was tun Sie, wenn Ihnen jemand ein Wörterbuch in die Hand drückt und Sie bittet, ein Wort nachzuschlagen, das nicht existiert? Sie könnten Ergebnisse garantieren, indem Sie Definitionen für unbekannte Wörter erfinden. Ein nützlicherer Ansatz ist einfach zu sagen: “Es gibt keine Definition für dieses Wort.” Dies zeigt ein erhebliches Problem in der Programmierung: Wie zeigt man “keinen Wert” für einen Speicherplatz an, der nicht initialisiert ist, oder für das Ergebnis einer Operation?

Die Null-Referenz wurde 1965 für ALGOL von Tony Hoare erfunden, der sie später als “meinen Milliarden-Dollar-Fehler” bezeichnete. Ein Problem war, dass sie zu einfach war—manchmal reicht es nicht aus, zu wissen, dass ein Raum leer ist. Man muss vielleicht wissen, warum er leer ist. Dies führt zum zweiten Problem: der Implementierung. Aus Effizienzgründen war es typischerweise nur ein spezieller Wert, der in eine kleine Menge Speicher passte, und was war besser als der Speicher, der bereits für diese Information bereitgestellt war?

Die ursprüngliche C-Sprache initialisierte den Speicher nicht automatisch, was zahlreiche Probleme verursachte. C++ verbesserte die Situation, indem neu zugewiesener Speicher auf null gesetzt wurde. Wenn also ein numerischer Wert nicht initialisiert ist, ist er einfach eine numerische Null. Das schien nicht so schlimm zu sein, aber es ermöglichte es, dass nicht initialisierte Werte unbemerkt durchrutschten (neuere C- und C++-Compiler warnen oft davor). Schlimmer noch, wenn ein Speicherstück ein Zeiger war—verwendet, um auf ein anderes Speicherstück zu verweisen—würde ein Nullzeiger auf die Speicheradresse null zeigen, was fast sicher nicht das ist, was man will.

Java verhindert Zugriffe auf nicht initialisierte Werte, indem es solche Fehler zur Laufzeit meldet. Obwohl dies nicht initialisierte Werte entdeckt, löst es das Problem nicht, denn die einzige Möglichkeit, zu überprüfen, ob Ihr Programm nicht abstürzt, besteht darin, es auszuführen. Es gibt Schwärme dieser Art von Fehlern im Java-Code, und Programmierer verschwenden enorme Mengen an Zeit, um sie zu finden.

Kotlin löst dieses Problem, indem es Operationen verhindert, die Nullfehler verursachen könnten, zur Kompilierzeit, bevor das Programm ausgeführt werden kann. Dies ist das am meisten gefeierte Merkmal von Java-Programmierern, die Kotlin übernehmen. Diese eine Funktion kann Java’s Nullfehler minimieren oder eliminieren, was Ihrem Projekt erhebliche Mengen an Zeit und Geld spart.

Eine Fülle von Vorteilen

Die beiden Funktionen, die wir hier erklären konnten (ohne mehr Programmierkenntnisse zu erfordern), machen einen großen Unterschied, unabhängig davon, ob Sie ein Java-Programmierer sind oder nicht. Wenn Kotlin Ihre erste Sprache ist und Sie an einem Projekt arbeiten, das mehr Programmierer benötigt, ist es viel einfacher, einen der vielen existierenden Java-Programmierer für Kotlin zu gewinnen.

Kotlin hat viele weitere Vorteile, die wir erst erklären können, wenn Sie mehr über das Programmieren wissen. Dafür ist der Rest des Buches da.

  • -

Sprachen werden oft aus Leidenschaft gewählt, nicht aus Vernunft… Ich versuche, Kotlin zu einer Sprache zu machen, die aus einem Grund geliebt wird.—Andrey Breslav, Kotlin Lead Language Designer.