Eigenschaften und Unterscheidung von Programmiersprachen – IT-Berufe-Podcast #182

Um Eigenschaften und Unterscheidungsmerkmale von Programmiersprachen geht es in der einhundertzweiundachzigsten Episode des IT-Berufe-Podcasts.

TL;DR

Ich gebe dir Kriterien an die Hand, mit denen du die Programmiersprachen deines Abschlussprojekts im Fachgespräch beschreiben und für eine Aufgabe auswählen kannst. Dazu gehören das Programmierparadigma, die Art, wie Code ausgeführt wird, und weitere Merkmale wie Syntax oder Speicherverwaltung. Bei der Typisierung unterscheidest du zwei unabhängige Dimensionen: statisch oder dynamisch sowie stark oder schwach. Auch die Plattform und das Ökosystem gehören zum Wissen, das du beim Entwickeln brauchst.

Kapitelmarken

  • [00:00:00] Einstieg und Bedeutung für das Fachgespräch
  • [00:02:56] Was ist eine Programmiersprache?
  • [00:04:38] Grundbausteine von Algorithmen
  • [00:06:37] Turing-Vollständigkeit und andere Spracharten
  • [00:09:38] Sprache, Plattform und Ökosystem
  • [00:12:44] Klassenbibliotheken und Laufzeitplattformen
  • [00:15:12] Buildtools, Abhängigkeiten und Frameworks
  • [00:17:47] Einsatzzweck von Programmiersprachen
  • [00:19:24] Frontend und Backend
  • [00:20:06] Skriptsprachen und Websprachen
  • [00:23:29] Programmierparadigmen und First Class Citizens
  • [00:25:15] Idiomatischer Code und Multiparadigmen-Sprachen
  • [00:28:29] Imperative und deklarative Programmierweise
  • [00:34:52] Unstrukturierte Programmierung mit goto
  • [00:37:11] Strukturierte Programmierung
  • [00:37:44] Prozeduren und Funktionen
  • [00:39:00] Objektorientierung und Kapselung
  • [00:41:20] Funktionale Programmierung
  • [00:43:47] Logische Programmierung mit Prolog
  • [00:47:00] Compiler und Interpreter
  • [00:48:50] Bytecode und Just-in-Time-Compiler
  • [00:50:35] Typisierung als Prüfungsthema
  • [00:51:46] Die unabhängigen Dimensionen der Typisierung
  • [00:52:58] Statische und dynamische Typisierung
  • [00:55:03] Typinferenz
  • [00:57:47] Starke und schwache Typisierung
  • [01:00:00] Implizite Typumwandlungen und Fehlerquellen
  • [01:05:07] Beispiele für die vier Typisierungskombinationen
  • [01:06:49] Typfehler und Tests
  • [01:08:09] C-ähnliche Syntax und andere Schreibweisen
  • [01:09:41] Grafische Programmiersprachen
  • [01:10:30] Sprachhöhe und Generationen von Programmiersprachen
  • [01:13:29] 4GL-Sprachen mit SQL, Natural und ABAP
  • [01:16:51] General Purpose und Domain-Specific Languages
  • [01:18:49] Interne und externe DSLs
  • [01:19:46] Portabilität und virtuelle Maschinen
  • [01:21:07] Managed und unmanaged Speicher
  • [01:22:24] Garbage Collection und Echtzeitsysteme
  • [01:25:52] Performance und Speicherverbrauch
  • [01:28:15] Beispiele für Websprachen und TypeScript
  • [01:30:15] Sprachen für Anwendungen in Unternehmen
  • [01:32:19] Appentwicklung und Hardware-nahe Sprachen
  • [01:33:30] Funktionale Sprachen und Elixir
  • [01:35:02] Prolog und andere Denkweisen beim Programmieren
  • [01:35:59] Buchempfehlung Seven Languages in Seven Weeks
  • [01:37:06] Kriterien für eine Antwort im Fachgespräch
  • [01:39:20] Java anhand der Kriterien beschreiben
  • [01:40:47] Fragen, Shownotes und Newsletter

Probeabo bei Audible (Affiliate)

Inhalt

Was ist eine Programmiersprache?

  • Programmiersprache: „Eine Programmiersprache ist eine formale Sprache zur Formulierung von Datenstrukturen und Algorithmen, d.h. von Rechenvorschriften, die von einem Computer ausgeführt werden können.“ [Herv. d. Verf.]
  • Bausteine von Algorithmen: Sequenz, Verzweigung (z.B. if, switch, aber auch Pattern Matching), Wiederholung (GOTO, Schleifen, Rekursion)
  • Turing-complete: „[…] die Eigenschaft einer Programmiersprache oder eines anderen logischen Systems, sämtliche Funktionen berechnen zu können, die eine universelle Turingmaschine berechnen kann.“

Demnach sind keine Programmiersprachen: HTML/XML (Auszeichnungssprache), CSS (Stylesheet-Sprache), SQL (Datenbankabfragesprache).

Sprache vs. Plattform vs. Ökosystem

Programmiersprachen bringen meistens „eingebaute“ („native“) Funktionen mit, die direkt in der Syntax der Sprache formuliert werden können:

  • Ein-/Ausgabe-Befehle, um Daten verarbeiten zu können
  • Deklaration von Variablen zum Speichern von Informationen
  • mathematische Funktionen wie Addition, Multiplikation usw.
  • Steueranweisungen für Verzweigung und Wiederholung
  • Möglichkeiten zur Programmunterteilung (z.B. Funktionen, Subprogramme)
  • Einbinden von (externen) Bibliotheken zur Wiederverwendung

Viele Programmiersprachen bringen außerdem noch eine umfangreiche Bibliothek an vorgefertigten Implementierungen (z.B. in Form von Klassen in objektorientierten Sprachen) mit. Diese Bibliothek ist bei der Einarbeitung in eine neue Sprache meist schwieriger/langwieriger zu lernen als die Syntax. Oftmals teilen sich mehrere Programmiersprachen die Bibliotheken einer gemeinsamen Plattform, z.B. der JVM bei Java und Kotlin bzw. .NET bei C# und Visual Basic.

Darüber hinaus existiert meist auch noch ein ganzes Ökosystem rund um die Sprache/Plattform:

Klassifizierung/Einsatzzweck(e)

Im Alltag sind die Identifikation und Auswahl einer für das jeweilige „Realweltproblem“ passenden Sprache wichtig. Viele Programmiersprachen haben Schwerpunkte bei ihrem Einsatz, weil sie für bestimmte Einsatzzwecke optimiert wurden oder dafür viele vorgefertigte Lösungen mitbringen.

  • Einsatzzweck: Webanwendung (z.B. PHP), App (z.B. Swift), Desktop-Anwendung (z.B. C#), Server-Anwendung (z.B. Java)
  • Frontend (browserseitig) vs. Backend
  • Scriptsprachen: geringer Programmieraufwand für schnell sichtbare Ergebnisse, oft Interpretersprachen mit dynamischer Typisierung und laxer Syntaxprüfung (z.B. Semikolons optional), Beispiele: PowerShell, PHP
  • Web-Programmiersprachen: bringen meist umfangreiche Bibliotheken und Frameworks für Webanwendungen mit, oftmals auch Scriptsprachen, Beispiele: PHP, Ruby, Python

Programmierparadigma

Ein Programmierparadigma gibt die grundsätzliche Art und Weise vor, wie mit einer Programmiersprache entwickelt wird. Es definiert grundlegende Herangehensweisen und Prinzipien bei der Softwareentwicklung, aber auch ganz konkrete syntaktische Vorgaben. So legt es z.B. fest, mit welchen Konstrukten das Programm hauptsächlich arbeitet (z.B. Objekte in der Objektorientierung bzw. Funktionen in der funktionalen Programmierung als sogenannte „First Class Citizens“), wie Programme modularisiert werden sollten und auf welche Art und Weise Algorithmen vorzugsweise formuliert werden sollten („idiomatische Programmierung“).

Viele Programmiersprachen sind heutzutage sogenannte Multiparadigmensprachen, bieten also Konzepte aus mehreren Paradigmen an, z.B. Objektorientierung und funktionale Programmierung. Meist haben sie aber ein definierendes Paradigma, z.B. Objektorientierung bei Java.

Imperativ vs. Deklarativ

Grundsätzlich kann man die imperative und deklarative Programmierung unterscheiden. Während bei der imperativen Programmierung (von lat. „imperare“ – befehlen) exakt vorgegeben wird, in welcher Reihenfolge der Computer welche Befehle wie ausführen muss, gibt man bei der deklarativen Programmierung (von lat. „declarare“ – erklären) lediglich vor, welches Ergebnis am Ende erreicht sein soll, und lässt den Computer den Weg dorthin selbst finden.

Beispiel:

// imperativ
for (int i = 0; i < list.getSize(); i++)
{
    System.out.println(list.get(i));
}

// deklarativ
list.forEach(System.out::println);

Konkrete Programmierparadigmen

  • unstrukturiert: Einsatz von GOTO führte dazu, dass konkrete Programmabläufe nicht mehr nachvollzogen werden konnten
  • strukturiert: Verzicht auf GOTO und Einsatz von Kontrollstrukturen wie if und while
  • prozedural: Programme werden in kleine, wiederverwendbare Einheiten („Prozeduren“) aufgespalten
  • funktional: (mathematische) Funktionen bilden den Kern dieser Vorgehensweise, Higher Order Functions, Immutability und Rekursion als wichtige Merkmale
  • objektorientiert: Objekte kapseln Eigenschaften und Funktionen zu einer Einheit, Vererbung und Polymorphie als wichtige Merkmale
  • logisch: Programmierung auf Basis der mathematischen Aussagenlogik

Compiler vs. Interpreter

  • Compiler: Übersetzt Quellcode in Maschinen- oder Bytecode, bevor das Programm ausgeführt wird.
    • JIT-Compiler: Just-In-Time-Compiler übersetzen z.B. Teile des Bytecodes zur Laufzeit in Maschinencode, um die Performance zu erhöhen.
  • Interpreter: Interpretiert den Quellcode Zeile für Zeile und übersetzt ihn während der Ausführung in Maschinencode.

Typisierung

  • statisch vs. dynamisch
    • statisch: Datentypen stehen schon zur Compile-Zeit fest.
    • dynamisch: Datentypen werden erst zur Laufzeit geprüft.
  • stark vs. schwach: eher ein Spektrum („stärker/schwächer typisiert“) als eine harte Einteilung
    • stark: keine Typumwandlung möglich oder nur explizit („Cast“, (int)3.5)
    • schwach: implizite Typumwandlungen durch die Sprache, z.B. if (1) { ... }

Beispiele für alle Kombinationen

  • statisch/stark: Java
> cat .\Main.java
class Main {
    public static void main(String[] args) {
        double d = 1.5;
        int i = d;
    }
}

> javac .\Main.java
.\Main.java:6: error: incompatible types: possible lossy conversion from double to int
    int i = d;
        ^
1 error
  • statisch/schwach: C
> cat test.c
#include <stdio.h>
int main() {
    int i = 1;
    if (i) {
        printf("Hallo\n");
    }
    return 0;
}
> gcc test.c -o test
> ./test
Hallo
  • dynamisch/stark: Ruby
> cat .\test.rb
i = 1
s = "a"
puts i + s

> ruby .\test.rb
./test.rb:3:in `+': String can't be coerced into Integer (TypeError)
    from ./test.rb:3:in `<main>'</main>
  • dynamisch/schwach: PHP
> cat test.php
$i = "asdf";
if ($i) {
    echo "Hallo\n";
}
> php test.php
Hallo

Syntax

Syntaktisch gibt es eigentlich nur die Unterscheidung zwischen Sprachen, die ähnlich zu C sind (insb. Klammern, Schlüsselwörter, Datentypen) oder eben nicht.

Beispiel Java (C-ähnlich):

void pruefePerson(int alter) {
    if (alter >= 18) {
        System.out.println("volljährig");
    }
}

Beispiel Ruby:

def pruefePerson(alter)
    puts "volljährig" if alter >= 18
end

Grafisch vs. textuell

Die weitaus meisten Programmiersprachen sind textuelle Sprachen, aber es gibt auch grafische Programmiersprachen, bei denen die Algorithmen „zusammengeklickt“ werden können. Ein Beispiel ist Scratch.

Abstraktionsniveau/Sprachhöhe

  • 1GL: Maschinensprache, Nullen und Einsen
  • 2GL: Assembler, etwas abstrakter, aber immer noch kryptisch, an bestimmte Prozessoren gebunden
  • 3GL: moderne Hochsprachen wie C, Java usw.
  • 4GL: Sprachen mit Fokus auf einen bestimmten Anwendungsbereich, Ziel: wenig Code für häufig benötigte Funktionen, Beispiele: Natural, ABAP

General Purpose vs. Domain Specific

  • General Purpose Language (GPL): Kann eingesetzt werden, um beliebige Probleme zu lösen, verwendet aber eine allgemeine Syntax. Beispiele: Java, C#, PHP etc.
  • Domain Specific Language (DSL): Kann nur Probleme eines genau abgegrenzten Bereichs lösen, verwendet dafür aber eine perfekt passende Syntax. Es gibt interne (fachliche APIs der eigenen Komponenten) und externe (komplett separate Programmiersprachen mit Compiler usw.).

Weitere Unterscheidungsmöglichkeiten

  • Portabilität/Laufzeitumgebung: hardwarenah (C, C++) vs. virtuelle Maschine (Java, C#)
  • Managed vs. unmanaged: Manuelle Speicherverwaltung (C) vs. Garbage Collector (Java, C#)
  • Performance/Speicherverbrauch: Durch die Kombination mehrerer der obigen Eigenschaften können sich deutliche Unterschiede bei der Performance einzelner Sprachen ergeben. So ist ein Programm in C, das speziell für die konkrete Laufzeitumgebung kompiliert wurde, sicherlich schneller als ein Java-Programm, das auf einer virtuellen Maschine interpretiert und ausgeführt wird. Aber das ist immer noch schneller als ein JavaScript-Programm, das zunächst noch interpretiert werden muss.

Beispiele für Programmiersprachen

Diese Liste ist nicht vollständig!

  • Web
    • PHP: sehr verbreitete Web-Programmiersprache mit viel Unterstützung für übliche Anforderungen (z.B. Zugriff auf Query-String usw.)
    • Ruby: Basis von Ruby on Rails und geschaffen, um Entwickler:innen glücklich zu machen
    • Python: gerade im KI-Umfeld stark verbreitet
    • JavaScript: bislang die einzige (!) Programmiersprache für das Frontend im Browser
    • Typescript: statisch typisierte Alternative zu JavaScript
  • Enterprise
    • Java: großes Ökosystem, Langlebigkeit, Abwärtskompatibilität, sehr performant
    • C#: stark verbreitet für Windows-Anwendungen
    • COBOL: alte, aber immer noch in vielen großen Unternehmen eingesetzte 4GL-Sprache für klassische Business-Anwendungen
    • ABAP: Programmiersprache von SAP
    • VBA: Makrosprache für Microsoft Office
  • App
    • Kotlin: Standardsprache für Android-Anwendungen, läuft wie Java auf der JVM
    • Swift: Standardsprache für iOS-Anwendungen, „Nachfolger“ von Objective-C
  • Hardware
    • Assembler: immer noch bei hochperformanten Anwendungen im Einsatz (z.B. Spiele)
    • C: Basis vieler eingebetteter Systeme und Betriebssysteme
    • C++: objektorientierter Aufsatz auf C
  • Funktional
    • Haskell: die funktionale Programmiersprache, in der realen Welt nicht allzu verbreitet
    • F#: funktionale Sprache für .NET
    • Lisp: Urvater der modernen funktionalen Programmiersprachen
    • Elixir: basiert auf Erlang und ist stark bei nebenläufiger Programmierung
  • Logisch
    • Prolog: Programmierung mit Prädikatenlogik, Backtracking usw.

Literatur

Seven Languages in Seven Weeks: A Pragmatic Guide to Learning Programming Languages (Pragmatic Programmers) (Affiliate)*

Seven Languages in Seven Weeks: A Pragmatic Guide to Learning Programming Languages (Pragmatic Programmers) (Affiliate)*

Links

Zusammenfassung

Programmiersprachen im Abschlussprojekt und Fachgespräch

In meinen Fachgesprächen frage ich häufig nach den Eigenschaften der eingesetzten Programmiersprachen. Wenn du als IT-Azubi zum/zur Fachinformatiker:in Anwendungsentwicklung mehrere Sprachen in deinem Abschlussprojekt verwendest, solltest du jede davon einordnen können. Die Merkmale helfen dir auch dabei, eine Sprache für die Anforderungen deines Projekts auszuwählen.

Was eine Programmiersprache ausmacht

Mit einer Programmiersprache formulierst du Datenstrukturen und Algorithmen, die ein Computer ausführen kann. Ein Algorithmus beschreibt, welche Schritte ein Problem lösen. Dafür stehen grundlegende Bausteine zur Verfügung:

  • Sequenzen: Befehle werden in einer festgelegten Reihenfolge ausgeführt.
  • Verzweigungen: Eine Bedingung bestimmt, welcher Programmteil ausgeführt wird, etwa mit if oder switch.
  • Wiederholungen: Schritte werden mehrfach ausgeführt. Das geht mit Schleifen oder rekursiven Aufrufen.

Turing-Vollständigkeit bezeichnet die Fähigkeit eines Systems, sämtliche Funktionen zu berechnen, die eine universelle Turing-Maschine berechnen kann.

HTML und XML zeichnen Texte aus und geben ihnen Bedeutung. CSS beschreibt, wie Dokumente aussehen. SQL dient dazu, Datenbanken abzufragen, und wird später als Beispiel für eine deklarative, domänenspezifische Sprache eingeordnet.

Sprache, Plattform und Ökosystem

Am Beispiel Java lassen sich die Begriffe genauer beschreiben:

  • Zur Sprache gehören die Syntax und die Möglichkeiten, Programme zu formulieren. Du kannst Variablen anlegen, mit Operatoren rechnen und den Ablauf durch Kontrollstrukturen steuern. Methoden teilen den Code in kleinere Bausteine auf. Bibliotheken ergänzen vorhandene Funktionen. Eingebaute Fähigkeiten werden als nativ bezeichnet.
  • Die Plattform führt die Programme aus. Java und Kotlin können zu Bytecode kompiliert werden, den die Java Virtual Machine, kurz JVM, ausführt. Auf .NET arbeiten beispielsweise C# und Visual Basic. Eine Plattform kann damit mehrere Sprachen unterstützen.
  • Zum Ökosystem gehören Werkzeuge und Frameworks, die das Entwickeln begleiten. Maven und Gradle bauen Java-Projekte und kümmern sich um Abhängigkeiten. Weitere Beispiele sind npm für JavaScript, RubyGems für Ruby und JUnit für Tests. Für Webanwendungen gibt es unter anderem Spring, Jakarta EE, Rails und Blazor.

Wenn du in einem Unternehmen als Entwickler:in anfängst, brauchst du auch Kenntnisse über die dort eingesetzten Werkzeuge und Bibliotheken. Im Fachgespräch stehen die allgemeinen Eigenschaften der Sprachen im Vordergrund.

Einsatzzweck

Viele Sprachen haben einen Schwerpunkt, der bei ihrer Auswahl hilft:

| Aufgabenbereich | Beispiele |
| — | — |
| Hardware-nahe Programme | C, C++, Assembler |
| Webanwendungen | PHP, Ruby, Python |
| Anwendungen in Unternehmen und auf Servern | Java, C# |
| Windows-Desktopanwendungen | C# |
| Android-Apps | Kotlin |
| iOS-Apps | Swift |

Im Browser spielt JavaScript eine zentrale Rolle. WebAssembly kommt als weitere Möglichkeit hinzu. Mit Node.js lässt sich JavaScript auch auf dem Server ausführen. Die Aussagen zur Verbreitung im Browser beziehen sich auf den Aufnahmezeitpunkt 2023.

Der Begriff Skriptsprache ist unscharf. Häufig bezeichnet er Sprachen, mit denen du mit wenig Code schnell sichtbare Ergebnisse erhältst. Sie werden oft interpretiert und sind häufig dynamisch typisiert. Beispiele sind Bash und PowerShell sowie PHP oder Ruby. Bei Webprojekten erleichtern vorhandene Bibliotheken und Frameworks viele typische Aufgaben.

Programmierparadigmen und idiomatischer Code

Ein Programmierparadigma prägt, wie du Probleme angehst und welche Möglichkeiten eine Sprache dafür bereitstellt. First Class Citizens sind Elemente, mit denen du direkt arbeiten kannst, etwa indem du sie in Variablen speicherst oder als Parameter übergibst. In funktionalen Sprachen gehören Funktionen dazu.

Wenn du idiomatisch programmierst, folgst du den üblichen Vorgehensweisen der jeweiligen Sprache. Dazu gehört beispielsweise, in funktionalem Code auf unveränderbare Werte zu achten und Wiederholungen rekursiv zu formulieren.

Viele moderne Sprachen unterstützen mehrere Paradigmen. Java und C# enthalten funktionale Möglichkeiten und sind im Kern objektorientiert. Bei einer Multiparadigmen-Sprache solltest du deshalb auch das vorherrschende Paradigma benennen können.

Imperativ und deklarativ

Bei der imperativen Programmierweise legst du die einzelnen Arbeitsschritte und ihre Reihenfolge fest. Eine Schleife mit einer selbst verwalteten Indexvariable ist ein typisches Beispiel.

Deklarativer Code beschreibt das gewünschte Ergebnis. Bei SQL formulierst du beispielsweise, welche Datensätze du erhalten möchtest. Das Datenbanksystem bestimmt, wie es die Anfrage abarbeitet. Auch moderne Java-Funktionen zur Listenverarbeitung übernehmen Details des Durchlaufens. Wenn die Sprache diese Arbeit organisiert, kann sie Möglichkeiten zum parallelen Ausführen bereitstellen.

Wie viel Kontrolle du über einzelne Schritte brauchst, ergibt sich aus deinem Projekt. Bei einem kleinen Mikroprozessor können genaue Vorgaben zum Speicher und zu den CPU-Zyklen eine Rolle spielen.

Die einzelnen Paradigmen

  • Unstrukturiert: Sprünge mit goto bilden Verzweigungen und Wiederholungen ab. Viele Sprünge erschweren es, den Programmablauf beim Lesen nachzuvollziehen. Dijkstras Artikel "Go To Statement Considered Harmful" thematisiert dieses Problem.
  • Strukturiert: Kontrollstrukturen wie if und while machen den Ablauf nachvollziehbarer.
  • Prozedural: Benannte Unterprogramme ermöglichen, Code mehrfach aufzurufen. C ist ein Beispiel. Ein Unterprogramm mit Rückgabewert wird als Funktion bezeichnet; eines ohne Rückgabewert heißt Prozedur.
  • Objektorientiert: Objekte fassen Daten und die dazugehörigen Methoden zusammen. Kapselung gehört zu den Grundlagen. Vererbung und Polymorphie sind weitere prüfungsrelevante Begriffe.
  • Funktional: Funktionen stehen im Mittelpunkt. Higher Order Functions können andere Funktionen als Parameter erhalten. Unveränderbare Werte und rekursive Aufrufe prägen diese Arbeitsweise. Dadurch lassen sich Probleme vermeiden, die entstehen, wenn mehrere parallel laufende Programmteile dieselben Daten verändern.
  • Logisch: Du definierst Fakten und Regeln, aus denen das Programm Antworten ableitet. Aus Vaterbeziehungen und einer Regel für Großvaterbeziehungen kann es beispielsweise eine entsprechende Anfrage beantworten. Prolog ist eine Sprache dieses Paradigmas.

Compiler, Interpreter und JIT

Ein Compiler übersetzt Quellcode vor dem Ausführen in Maschinen- oder Bytecode. Dabei kann er Fehler erkennen und das Übersetzen abbrechen. Zwischen dem Schreiben und dem Starten des Programms liegt ein zusätzlicher Schritt.

Ein Interpreter verarbeitet Code während des Ausführens. Fehler können auftreten, sobald die betreffende Stelle erreicht wird. Ein Bash-Skript dient dafür als Beispiel.

Bei Java werden mehrere Verfahren kombiniert: Der Compiler erzeugt Bytecode, den die JVM ausführt. Ein Just-in-Time-Compiler, kurz JIT-Compiler, übersetzt häufig ausgeführte Codeteile zur Laufzeit in Maschinencode. Spätere Durchläufe können diesen bereits übersetzten Code ausführen.

Typisierung

Für das Fachgespräch solltest du beide Dimensionen der Typisierung beschreiben können. Statisch oder dynamisch betrifft den Zeitpunkt, zu dem Typen feststehen beziehungsweise geprüft werden. Stark oder schwach beschreibt den Umgang mit Typen und Typumwandlungen. Daraus ergeben sich vier Kombinationen.

Statisch und dynamisch

Bei statischer Typisierung stehen die Datentypen bereits zur Compilezeit fest. Java und C# gehören dazu. Der Compiler kann unzulässige Operationen mit bekannten Typen früh erkennen.

In dynamisch typisierten Sprachen werden Typen zur Laufzeit relevant. Beispiele sind PHP und Ruby. Eine Variable kann im Verlauf des Programms Werte unterschiedlicher Typen aufnehmen. Typfehler können dadurch beim Ausführen auftreten, weshalb Tests entsprechende Fälle abdecken müssen.

Mit Typinferenz leitet der Compiler den Typ aus dem Code ab. Bei var s = "Hallo" ergibt sich der Typ aus dem zugewiesenen String. Die Variable behält diesen festgelegten Typ. Du sparst dir, ihn selbst auszuschreiben.

Stark und schwach

Starke und schwache Typisierung bilden ein Spektrum. Für die Einordnung spielen besonders implizite Typumwandlungen eine Rolle: Die Sprache wandelt Werte automatisch in einen anderen Typ um. So können manche Sprachen eine Zahl in einer Bedingung als Wahrheitswert auswerten.

Ein expliziter Cast steht sichtbar im Code. Das Umwandeln einer Gleitkommazahl in eine Ganzzahl kann beispielsweise den Nachkommateil abschneiden.

Automatische Umwandlungen können Fehler schwerer erkennbar machen. Wenn du in einer PHP-Bedingung versehentlich eine Zuweisung mit = schreibst, kann deren Ergebnis zu einem Wahrheitswert umgewandelt werden. Die Bedingung verhält sich dann anders als der beabsichtigte Vergleich.

| Kombination | Beispiele |
| — | — |
| Statisch und stark | Java, C# |
| Statisch und schwach | C |
| Dynamisch und stark | Ruby |
| Dynamisch und schwach | PHP, JavaScript |

Syntax und grafische Sprachen

Java und C# haben eine C-ähnliche Syntax, etwa mit geschweiften Klammern für Blöcke. Ruby beschreibt Strukturen unter anderem durch Schlüsselwörter wie def und end. In Python legt die Einrückung die Blockstruktur fest.

Bei grafischen Programmiersprachen setzt du Bausteine in einer Oberfläche zusammen. Scratch ist ein Beispiel. Ich arbeite außerdem mit Flow in einem Enterprise-Service-Bus, wo unter anderem Pfeile den Datenfluss darstellen.

Sprachhöhe und Abstraktion

| Generation | Merkmale und Beispiele |
| — | — |
| 1GL | Maschinensprache mit binären Befehlen |
| 2GL | Assembler mit kurzen, prozessornahen Befehlen |
| 3GL | Hochsprachen wie C, Java, C#, Ruby, Python und PHP |
| 4GL | Sprachen mit stärkerem Bezug zu bestimmten Aufgabenbereichen, etwa SQL, Natural und ABAP |

Bei einer höher abstrahierten Sprache brauchst du für bestimmte Aufgaben weniger Code. Natural kann beispielsweise eine Datenbanktabelle mit einem kurzen Befehl durchlaufen. Details der technischen Ausführung übernimmt die Umgebung.

Allgemeine und domänenspezifische Sprachen

Eine General Purpose Language, kurz GPL, eignet sich für unterschiedliche Aufgabenbereiche. Java und C# gehören dazu.

Eine Domain-Specific Language, kurz DSL, ist auf eine abgegrenzte Domäne zugeschnitten. SQL beschreibt beispielsweise Anfragen an relationale Datenbanken.

  • Eine interne DSL entsteht innerhalb einer vorhandenen Sprache, etwa durch eine fachlich passende API.
  • Eine externe DSL besitzt eine eigene Syntax. SQL dient dafür als Beispiel.

Portabilität, Speicher und Laufzeit

Für die Portabilität spielt die Umgebung eine Rolle, in der dein Programm läuft. Virtuelle Maschinen wie die JVM erlauben, Programme auf verschiedenen Plattformen auszuführen. Hardware-nahe Programme hängen stärker von ihrer konkreten Umgebung ab.

Bei unmanaged Code kümmerst du dich selbst um dynamisch reservierten Speicher. In C gibst du ihn beispielsweise mit free wieder frei. Vergessene Freigaben können Speicherlecks verursachen.

In managed Umgebungen wie Java und C# übernimmt ein Garbage Collector das Freigeben nicht mehr erreichbarer Speicherbereiche. Er benötigt dafür Rechenzeit und kann das Programm zeitweise anhalten. Solche Pausen müssen bei Echtzeitsystemen berücksichtigt werden. Bei üblichen Webanwendungen fallen sie häufig gegenüber anderen Wartezeiten kaum ins Gewicht.

Performance und Speicherbedarf ergeben sich aus mehreren Eigenschaften und der konkreten Laufzeitumgebung. Typprüfungen zur Laufzeit benötigen Arbeit; auch ein Interpreter oder Garbage Collector beansprucht Ressourcen. Optimierte virtuelle Maschinen können in bestimmten Fällen sehr schnell arbeiten. Eine belastbare Einschätzung braucht das konkrete Szenario.

Weitere Sprachbeispiele und Material

TypeScript ergänzt JavaScript um statische Typen und wird zu JavaScript transpiliert. Dabei entsteht Code in einer anderen Programmiersprache.

In Unternehmen begegnen dir außerdem COBOL, insbesondere bei Banken und Versicherungen, sowie ABAP im SAP-Umfeld. VBA ist die Makrosprache von Microsoft Office. Als funktionale Beispiele kommen Haskell, F# und Lisp hinzu. Elixir baut auf Erlang auf und ist auf nebenläufige Programme ausgerichtet.

Ich empfehle dir "Seven Languages in Seven Weeks", um unterschiedliche Paradigmen anhand konkreter Sprachen kennenzulernen. Quellen und Codebeispiele stehen in den Shownotes zur Episode 182. Mein kostenloser Newsletter begleitet dich mit wöchentlichen Inhalten, die zu deinem Ausbildungsstand passen, einschließlich Themen für das Fachgespräch.

Transkription der gesamten Episode

Automatisch erzeugte Transkription der Episode

[0:00] Herzlich Willkommen zum IT-Berufe-Podcast, dem Podcast rund um die Ausbildung in den

[0:10] IT-Berufen. In dieser Episode geht es um Eigenschaften von Programmiersprache. Viel Spaß!

[0:20] Hallo und herzlich Willkommen zur 182. Episode des IT-Berufe-Podcasts. Mein Name ist Stefan

[0:27] Macke und heute gibt es mal wieder etwas Technischeres und zwar insbesondere für die

[0:31] Anwendungsentwickler und Entwicklerinnen da draußen. Und zwar wollen wir heute mal ein

[0:34] paar Programmiersprachen unterscheiden anhand ihrer Kriterien, anhand ihrer Merkmale. Das ist

[0:40] auch etwas, was wir oft im Fachgespräch mal abfragen, insbesondere der Punkt Typisierung.

[0:44] Ui, da fangen ganz, ganz viele Prüfungen immer an zu schwimmen. Deswegen gehen wir das heute mal

[0:47] durch, was eigentlich so die Unterschiede sind, was es überhaupt für Typisierungen gibt. Aber

[0:51] das ist nur eines der Kriterien und wir gucken uns mal an, wie man Programmiersprachen so

[0:55] unterscheiden kann. Denn insbesondere bei den Abschlussprojekten gibt es heute immer mehr

[0:58] Projekte, wo auch mehrere Programmiersprachen im Einsatz sind. Der Klassiker ist natürlich,

[1:02] ich habe ein Webprojekt, im Frontend habe ich JavaScript, im Backend habe ich irgendwas

[1:06] anderes. Java oder C-Sharp oder meinetwegen auch wieder JavaScript. Egal, das geht ja heute alles.

[1:10] Aber wenn man mal fragt, was ist denn eigentlich der Unterschied zwischen den Sprachen, die du da

[1:14] eingesetzt hast in deinem Projekt, dann wird es immer haarig. Und deswegen habe ich heute mal ein

[1:18] paar Kriterien mitgebracht, wie man Programmiersprachen unterscheiden kann, welche Eigenschaften die haben

[1:23] und dann sollte man eigentlich für die, zumindest für die, die man selber einsetzt, erklären können,

[1:28] ja, wo man die eingruppiert quasi. Und ich habe schon mal eine Episode gemacht zu Testverfahren

[1:34] und da habe ich es ähnlich gemacht. Man kann Testverfahren auch nach ganz ganz vielen Kriterien

[1:38] eingruppieren. Macht es ein Mensch oder macht es eine Maschine? Ist es zu Beginn des Projekts oder

[1:44] zu Ende des Projekts? Ist es eine Unit, die getestet wird oder das ganze System? Und so

[1:48] weiter und so fort. Also man kann dann verschiedene Testverfahren dort einsortieren. Und genauso ist

[1:51] bei Programmiersprachen auch. Da gibt es mehrere Kriterien und die wollen wir uns heute auch der

[1:55] Reihe nach mal angucken. Und dann unterscheiden wir die Programmiersprachen anhand dieser Kriterien.

[2:00] Ich gehe schon mal vorweg einmal die Sachen durch. Und zwar wollen wir uns heute anhören, einmal den

[2:05] grundsätzlichen Einsatzzweck einer Programmiersprache, welchen Schwerpunkt sie hat. Dann natürlich das

[2:10] Programmierparadigma, was dahinter steckt, Objektorientierung etc. Dann Imperativ und

[2:15] Deklarativ, kann man auch unterschreiben. Ob es eine Compiler- oder Interpretersprache ist, das ist

[2:21] auch interessant. Dann natürlich die Typisierung. Mein Lieblingsbeispiel, wie gesagt, auch fürs

[2:24] Fachgespräch. Dann die Syntax der Sprache. Ist es eine grafische oder textuelle Sprache? Welches

[2:30] Abstraktionsniveau hat die Sprache? Und ja, noch ein paar weitere Unterscheidungsmöglichkeiten,

[2:36] aber eher kleinerer Natur. Das wird alles heute auf dich zukommen. Die Folge könnte auch deswegen

[2:41] ein bisschen länger werden. Ich versuche mich gut zu fassen, aber ich schweife bei diesem Lieblingsthema

[2:45] von mir gerne ab. Also ja, mal gucken, wie gut ich das schaffe, heute meine angepeilte Stunde

[2:51] vielleicht einzuhalten. Wir werden sehen. Gut, fangen wir doch einfach mal an. Zu Beginn sollten

[2:56] wir uns vielleicht einmal darüber unterhalten, was überhaupt eine Programmiersprache ist.

[2:59] Wahrscheinlich hast du ein bisschen was im Kopf, wenn ich dir sage, was für eine Programmiersprache

[3:03] nutzt du denn. Klar. Aber was ist denn eigentlich genau eine Programmiersprache? Und da können wir

[3:08] uns mal so ein paar Definitionen anschauen. Eine ist, eine Programmiersprache ist eine formale

[3:13] Sprache zur Formulierung von Datenstrukturen und Algorithmen, das heißt von Rechenvorschriften,

[3:20] die von einem Computer ausgeführt werden können. Die ganzen Informationen, Definitionen, Links und

[3:26] so weiter findest du natürlich wie immer in den Shownotes übrigens. Das will ich jetzt nicht jedes

[3:28] Mal dazusagen. Unter itberufepodcast.de slash 182 für die 182. Episode kannst du einfach die Links

[3:35] im Detail angucken, die Originalquellen und so weiter. Ich gehe mal kurz auf diese Definition

[3:40] ein. Es geht darum, Datenstrukturen zu formulieren. Okay, aber ich würde den Fokus eher auf die

[3:44] Algorithmen legen. Wiederholen wir nochmal, was überhaupt ein Algorithmus ist. Vielleicht weißt

[3:49] du das nicht mehr. Ein Algorithmus ist einfach eine Handlungsanweisung, um ein Problem zu lösen,

[3:53] ganz einfach gesagt. Und ja, wenn wir das jetzt auf Programmiersprachen übertragen, muss dieser

[3:58] Algorithmus von einem Computer durchgeführt werden können, damit der Computer eben das Problem lösen

[4:02] kann. Dafür sind Programmiersprachen da. Jetzt müssen wir uns nur angucken, wie formuliert man

[4:08] solche Algorithmen. Wenn ich jetzt sage, ich habe eine Sprache, in der ich einen Algorithmus formuliere,

[4:11] dann wäre ja auch Deutsch eine Sprache. Weil ich kann zum Beispiel sagen, nimm acht Äpfel,

[4:16] schäle die Äpfel, lege die Äpfel auf einen Kuchenteig und so weiter. Und schon habe ich am

[4:21] Ende ein Rezept für einen Apfelkuchen abgearbeitet, was nichts anderes ist als ein Algorithmus. Nämlich,

[4:26] um das Problem zu lösen, einen leckeren Apfelkuchen essen zu können. Das heißt,

[4:29] da müssen wir noch ein bisschen mehr machen, glaube ich, um das als Programmiersprache durchgehen zu

[4:33] lassen. Und wenn wir uns jetzt anschauen, woraus solche Algorithmen bestehen, dann können wir ein

[4:38] bisschen genauer sagen, was eine Programmiersprache ist und was nicht. Und zwar kann man jeden

[4:46] Algorithmus zusammensetzen aus Sequenzen, Verzweigungen und Wiederholungen. Eine Sequenz

[4:51] bedeutet immer, mach, mach, mach in dieser Reihenfolge. So was wie, arbeite von oben nach

[4:56] unten exakt in dieser Reihenfolge Befehle ab. Das ist einfach, als wenn du in einer Programmiersprache

[5:01] drei Statements hintereinander schreibst und der Computer arbeitet die ab. Und nicht in zufälliger

[5:05] Reihenfolge, sondern genau dieser Reihenfolge. Das ist dann eine Sequenz. Wenn es dann etwas

[5:09] komplizierter wird, dann müssen wir manchmal vom Weg abzweigen und eine Fallunterscheidung einbauen.

[5:15] Zum Beispiel, wenn die Person volljährig ist, dann nimm Aufschlag auf Preis. Wenn nicht,

[5:20] dann eben nicht. Zum Beispiel. Das ist eine Verzweigung. In Programmiersprachen erkennst

[5:24] du das oft wieder in Form eines If-Statements oder ein Switch-Statement zum Beispiel. Eine

[5:29] Verzweigung. Und dann haben wir natürlich noch die Wiederholungen. Ganz oft werden Wiederholungen

[5:34] mit Schleifen gleichgesetzt. Die gute alte Vorschleife oder Wildschleife. Aber es gibt

[5:39] auch andere Möglichkeiten, Wiederholungen zu machen. Zum Beispiel eine Rekursion. Das

[5:42] wiederholt auch Schritte, ohne die Form einer Schleife anzunehmen. Und das brauchen wir auch

[5:47] in Algorithmen, wie zum Beispiel in meinem Apfelkuchen. Acht Äpfel. Da möchte ich acht

[5:51] mal hintereinander ein Apfel schälen zum Beispiel. Das will ich ja nicht jedes Mal wieder neu

[5:55] programmieren. So einfach mach acht mal Apfel schälen zum Beispiel. Diese drei Bausteine

[6:00] brauchen wir. Sequenzen, Verzweigungen, Wiederholungen. Und wenn wir die nicht haben,

[6:03] ja, dann können wir halt keine Algorithmen formulieren, weil das brauchen wir halt für

[6:07] so gut wie jeden Algorithmus. Wenn wir diese drei Bausteine haben, dann können wir jeden

[6:11] Algorithmus formulieren, den wir uns vorstellen können, um ein Problem zu lösen. Es gibt noch

[6:16] bessere Möglichkeiten, Algorithmen zu formulieren, mehrere Features, die Sprachen anbieten, damit es

[6:21] ein bisschen schneller geht. Aber wenn man das runter bricht, brauchen wir immer nur diese drei

[6:25] Sachen. Sequenz, Verzweigung, Wiederholung. Das heißt, wenn ich mir jetzt Sprachen angucke,

[6:29] und die haben diese drei, dann kann ich sehr sicher sagen, dass das eine Programmiersprache

[6:32] ist, denn dann kann ich damit Algorithmen formulieren. Eine andere Bezeichnung für eine

[6:37] Programmiersprache, die sich so eine nennen darf, die ist Turing Complete. Das hast du vielleicht

[6:44] auch schon mal gehört. Alan Turing, das war ein britischer Mathematiker. Gibt es auch ein paar

[6:49] Filme drüber über den Herren. Der hat ein paar coole Sachen gemacht, zum Beispiel die Enigma

[6:53] entschlüsselt im Zweiten Weltkrieg und verschiedene andere Dinge. Und der hat mal gesagt,

[6:58] also mein Mann sagt, wenn eine Programmiersprache Turing Complete ist, dann hat sie oder ist das die

[7:04] Eigenschaft einer Programmiersprache oder eines anderen logischen Systems, sämtliche Funktionen

[7:10] berechnen zu können, die eine universelle Turing-Maschine berechnen kann. Ja, super. Jetzt

[7:15] sind wir da ähnlich wie bei Algorithmen. Was ist denn jetzt ein Algorithmus? Müssen wir erst mal

[7:18] fragen, was ist denn jetzt eine Turing-Maschine? Und eine Turing-Maschine, die hat der Herr Turing

[7:22] sich mal ausgedacht, das ist eine Maschine, mit der man beliebige Kalkulationen machen kann. Das

[7:27] kann ich jetzt hier nicht im Detail erklären, da kannst du am besten mal ein paar Videos oder einen

[7:31] Text zu durchlesen. Ich glaube, im IT-Handbuch von Sascha Kersken ist das Ding auch einmal erklärt,

[7:35] was es damit auf sich hat. Und grundsätzlich, wenn wir uns jetzt diese beiden Definitionen

[7:40] angucken, dann geht es bei Programmiersprachen eben darum, dass wir Probleme damit lösen können,

[7:44] in Form von Algorithmen. Und wenn wir jetzt einfach mal angucken, was demnach dann zum Beispiel keine

[7:49] Programmiersprachen sind, dann fällt uns direkt ein HTML. HTML hat nämlich insbesondere keine

[7:55] Verzweigungen und keine Schleifen. Ja, wenn du in HTML irgendwas wiederholen willst, dann musst

[7:59] du copy, paste machen und die Datei speichern. Und das war deine Wiederholung. Ja, das heißt,

[8:02] das kann ich nicht mit HTML. Genauso wenig wie XML. Damit kann ich auch nicht programmieren. Beides

[8:08] sind einfach Auszeichnungssprachen, die Text eine Semantik verpassen. Wie zum Beispiel in HTML kann

[8:16] ich einem Text den Strong Tag vergeben und darum also den Text damit umschließen und dann sagt

[8:22] halt der Browser, okay, dieses Wort ist wichtig. Damit habe ich dem Text eine Semantik, eine

[8:26] Bedeutung verpasst. Aber ja, das war's. Ich kann damit nicht programmieren. Deswegen ist es auch

[8:30] keine Programmiersprache. Genauso wenig, wenn wir schon im Web bleiben, ist CSS eine Programmiersprache.

[8:34] Das ist eben ein Style-Sheet, um ja in diesem Fall HTML, beispielsweise auch XML-Dokumenten,

[8:39] ein Layout zu verpassen. Also wie das aussehen soll. Farben, Textgröße, Seitenumbrüche,

[8:44] was auch immer ich damit halt machen will. Das hat auch nichts mit Programmierung zu tun. Und

[8:48] genauso wenig ist SQL eine Programmiersprache. Das ist einfach dafür da, um Datenbanken abzufragen.

[8:53] Auch wenn man meinen könnte, Moment, da programmiere ich doch was und dann kommen Ergebnisse raus. Ja,

[8:58] aber was du in SQL zum Beispiel nicht machen kannst, ist eine Wiederholung. Es geht sogar

[9:02] ein Switch, ein If, eine Verzweigung. Das heißt dann zwar nicht If oder Switch, sondern Case zum

[9:07] Beispiel. Du kannst Select Case und so weiter machen und dann anhand von Fallunterscheidungen

[9:12] bestimmte Dinge selektieren. Aber eine Wiederholung geht leider nicht in SQL. Und

[9:16] deswegen kannst du damit auch keine allgemeingültigen Algorithmen formulieren,

[9:19] weil dir dieses wichtige Merkmal dort fehlt. Okay, ja, dann würde ich sagen, haben wir jetzt

[9:25] erstmal klar oder festgestellt, was eine Programmiersprache ist. Ja, damit möchte ich

[9:29] oder muss ich Algorithmen formulieren können. Dann ist es eine Programmiersprache. Und wenn

[9:33] man jetzt heute anfängt, eine Programmiersprache zu lernen, dann reicht das meistens leider nicht

[9:38] aus, denn die Sprache ist eingebettet in eine Plattform oder vielleicht sogar in ein ganzes

[9:42] Ökosystem. Und das muss man vielleicht auch ein wenig unterscheiden. Das heißt, bevor wir jetzt

[9:46] nochmal mit den konkreten Unterschieden von Programmiersprachen anfangen, möchte ich das

[9:50] nochmal einmal abgrenzen. Also wir haben zum Beispiel eine Programmiersprache, ich nehme jetzt

[9:54] mal Java als Beispiel. Nicht nur, weil ich die oft benutze oder weil die in vielen Berufsstunden

[9:58] gemacht wird, sondern weil man es daran sehr gut erklären kann, diese drei Begriffe Sprache,

[10:03] Plattform, Ökosystem. So die Programmiersprache Java selbst, wenn ich mir nur die Sprache angucke,

[10:08] hat die eine Syntax, das heißt Vorschriften, wie ich Befehle in dieser Sprache formulieren muss. Da

[10:14] gibt es dann zum Beispiel eingebaute Ein- und Ausgabebefehle, um zum Beispiel Sachen einlesen,

[10:20] Daten einlesen zu können oder ausgeben zu können. Das gute alte System.out.println. Das

[10:24] kennst du vielleicht, um irgendetwas auf der Konsole an Text auszugeben. Das ist ein eingebauter

[10:29] Befehl, der ist einfach da in der Sprache, den kann ich aufrufen. Genauso kann ich in diesen

[10:33] Sprachen üblicherweise Variablen deklarieren, also Speicher des Computers, dem gebe ich einen

[10:38] Namen und kann dann darauf zugreifen, dort Werte drin ablegen und wieder abrufen. Außerdem hat

[10:43] Java zum Beispiel eingebaut mathematische Funktionen, die guten alten Operatoren wie

[10:47] plus minus mal geteilt und so weiter. Andere Programmiersprachen haben zum Beispiel einen

[10:50] extra Operator für die Potenz. Das hat Java jetzt nicht, aber das grundsätzliche mathematische Zeug,

[10:56] was man so berechnen möchte, das bieten die Programmiersprachen meistens an. Außerdem

[11:00] haben wir natürlich Steueranweisungen für Verzweigung und Wiederholung, nämlich zum

[11:04] Beispiel das if-Statement oder die while-Schleife. Das ist einmal Verzweigung if, Schleife für

[11:09] Wiederholung und dann kann ich meistens auch meine Programme in irgendeiner Form unterteilen. Ich kann

[11:14] zum Beispiel eine Art Subprogramm, eine Funktion, eine Methode in Java genannt anlegen oder ein

[11:20] Subprogramm oder wie auch immer. Denn üblicherweise schreibe ich nicht einfach alles in einem riesen

[11:25] Programm runter, sondern ich möchte das modularisieren. Ich möchte es in Teile zerteilen

[11:29] nach dem üblichen Divide-and-Conquer-Prinzip. Ich programmiere nicht einfach alles runter,

[11:33] sondern ich fange erst mal klein an, baue mir kleine Bausteine und baue aus den Bausteinen

[11:37] dann nichts Größere, bis ich irgendwann das Problem gelöst habe. Das bieten mir die

[11:40] Programmiersprachen auch von sich aus an. Und meistens bieten die Programmiersprachen auch

[11:46] an, irgendwelche Bibliotheken einzubinden. Wenn Java dann irgendwas nicht mehr kann,

[11:50] wie zum Beispiel, was fällt mir ein, keine Ahnung, irgendeine grafische Darstellung auf

[11:54] dem Bildschirm oder sowas, dann könnte ich mir dafür vielleicht eine Bibliothek herunterladen,

[11:58] in mein Programm einbinden und einfach nutzen, damit ich das selber nicht programmieren muss.

[12:03] Und dafür bieten mir Programmiersprachen meistens auch Funktionen. Wie gesagt,

[12:07] das ist alles nice to have. Sequenz, Verzweigung, Wiederholung reicht für eine Programmiersprache,

[12:11] aber heute übliche Programmiersprachen bieten alles das an, was ich gerade gesagt habe. Und

[12:17] wenn diese Dinge in die Programmiersprache eingebaut sind, also quasi die Statistik

[12:21] der Programmiersprachen, das ist einfach da, dann nennt man das auch nativ, also quasi eingebaut,

[12:25] wie Native American, die Ureinwohner Amerikas, nativ in die Programmiersprache eingebaut. Du

[12:30] musst dafür nichts zusätzlich installieren oder herunterladen, das kann die Sprache einfach von

[12:35] sich. Und diese nativen Funktionen, wie gerade genannt wurden, die sind halt bei den meisten

[12:40] Sprachen dabei. Jetzt gibt es aber viele Programmiersprachen, die eben auch noch eine

[12:44] ganze Bibliothek mitbringen an vorgefertigten Implementierungen. Zum Beispiel in Java,

[12:50] da gibt es einen Haufen Klassen, die einfach schon vorprogrammiert sind. Das geht los bei

[12:54] solchen einfachen Sachen wie Integer und String. Ja, diese Datentypen, die sind auch nicht einfach

[12:59] da in der Sprache, sondern die muss auch ja jemand mal entwickelt haben. Und diese ganze

[13:02] Klassenbibliothek, die bringen heutzutage die Programmiersprachen eigentlich mit. Und bei Java

[13:06] ist es zum Beispiel auch so. Da gibt es einfach, ich kann dir nicht sagen wie viele, aber Tausende

[13:10] an eingebauter Klassen, die einfach mit dabei sind. Die haben mit der Programmiersprache an

[13:16] sich erstmal nichts weiter zu tun, weil die erweitern zum Beispiel nicht die Syntax der

[13:19] Sprache. Aber die bieten dir halt viele eingebaute Funktionen, die du dann einfach

[13:23] aufrufen kannst. Und je nachdem, wie umfangreich diese Klassenbibliothek ist, kannst du halt ganz

[13:28] viele Sachen mit der Sprache selbst schon machen, weil sie einfach schon drin sind. Oder du musst

[13:33] sie halt zusätzlich einbinden in Form von externen Bibliotheken. Und dieses ganze Zeug

[13:39] mit diesen Bibliotheken und der Programmiersprache und so weiter, das läuft auf einer Plattform. Ich

[13:45] hatte gerade gesagt Sprache, Plattform, Ökosystem. Und Plattform ist dann das, wo eben die

[13:49] Programmiersprache drauf läuft und alles, was sie dann halt mitbringt. Zum Beispiel bei Java die

[13:53] JVM, die Java Virtual Machine. Das ist das Ding, auf der dann die Programme, die man programmiert

[14:01] hat, ausgeführt werden. Und da ist dann halt das ganze Zeug drin, was man halt eben braucht,

[14:04] um das auszuführen. Das ist dann die Plattform. Und jetzt kann ich zum Beispiel auf der JVM bei

[14:09] Java auch mit anderen Programmiersprachen programmieren als Java. Ich kann zum Beispiel

[14:13] Kotlin nehmen. Das ist eine sehr beliebte Programmiersprache heutzutage, mit der werden

[14:17] moderne Android-Apps zum Beispiel entwickelt. Kotlin ist die Standardprogrammiersprache für

[14:22] Android. Inzwischen hat Java abgelöst. Beide laufen aber auf der gleichen Plattform, nämlich

[14:27] auf der JVM. Wie funktioniert das? Java, die Programmiersprache, und Kotlin, die Programmiersprache,

[14:32] werden beide kompiliert zu Bytecode. Und dieser Bytecode wird dann von der JVM ausgeführt. Das

[14:38] heißt, ich habe eine einzige Plattform. Ich habe aber durchaus mehrere Programmiersprachen,

[14:42] die auf dieser Plattform laufen können. Und da ist die JVM nicht die einzige. Es gibt zum Beispiel

[14:46] bei Microsoft auch .NET. Da gibt es auch viele Programmiersprachen, zum Beispiel C-Sharp oder

[14:51] Visual Basic, die auch alle auf der gemeinsamen Plattform .NET dann arbeiten. Und üblicherweise

[14:58] reicht es heutzutage eben nicht, nur die Sprache zu kennen. Ich muss mich auch in der Plattform ein

[15:01] bisschen auskennen, weil die Programmiersprache, ja, das Zeug läuft ja auf dieser Plattform. Also

[15:07] es gehört zusammen. Und ich muss mich damit auch ein wenig beschäftigen natürlich. Über die reine

[15:12] Programmiersprache und die Plattform hinaus gibt es aber auch noch etwas, was dazukommen könnte,

[15:17] und das ist dann das Ökosystem rund um die Sprache. Was meine ich damit? Wenn man jetzt

[15:22] heutzutage in der Programmiersprache Software entwickelt, dann reicht es nicht aus, auf seinem

[15:26] eigenen PC irgendwie kurz den Compiler anzuschmeißen und ist man fertig. Ganz oft braucht man zum

[15:30] Beispiel Buildtools, weil ich so viele Dependencies, also Abhängigkeiten habe, die ich selber gar nicht

[15:34] programmieren will, die ich mir irgendwie in mein Projekt reinholen möchte. Und dann möchte ich

[15:37] nicht jedes Mal auf eine Website gehen und mir irgendeine Datei runterladen, damit ich die dann

[15:40] in mein Projekt einbinde. Ich möchte einem Tool sagen, hey, lad du das mal runter, und zwar in der

[15:44] passenden Version, damit es auch läuft. Beispiel wieder für Java, Maven oder Gradle, die Buildsysteme.

[15:49] Dann haben wir Dependency Management, zum Beispiel unter JavaScript das NPM, der Node-Package-Manager,

[15:55] oder Ruby Gems für Ruby. Das heißt, wenn ich Abhängigkeiten mir reinholen will, dann möchte

[16:01] ich das zum Beispiel in einer einfachen Syntax machen, in irgendein File einfach eintragen, hey, ich hätte

[16:04] gerne folgendes Gem in Version so und so, und dann soll das einfach von alleine funktionieren, ohne

[16:09] dass ich da selber Hand anlegen muss. Außerdem brauchen wir, wenn wir vernünftig Software entwickeln

[16:13] wollen, natürlich auch Test-Frameworks zum Beispiel. Da haben wir in Java das berühmte JUnit. Das ist

[16:17] auch nicht einfach magischerweise da. Das muss auch noch berücksichtigt werden, wenn ich so ein Projekt

[16:21] starte. Oder es gibt noch weitere Frameworks, wenn ich zum Beispiel im Web was entwickle. Da gibt es

[16:26] unter Java Spring oder Jakarta.ie oder unter Ruby das Rails-Framework oder Blazor in .NET. Das heißt,

[16:32] viele Menschen haben schon was für mich programmiert, was ich einfach nutzen kann, damit ich es einfacher

[16:36] habe. Und das ist einfach Teil dieses Ökosystems, zum Beispiel von Java. Das heißt, wenn ich jetzt in

[16:42] einem neuen Unternehmen zum Beispiel starte als Java-Entwickler, dann sollte ich mich unbedingt

[16:45] auch darum kümmern, wie das Ökosystem aussieht. Also arbeite ich zum Beispiel mit Maven oder Gradle?

[16:49] Das sind schon relativ unterschiedliche Tools. Wie werden die Dependencies verwaltet? Welches

[16:53] Test-Framework wird eingesetzt? Das heißt, es reicht heute eigentlich nicht mehr, nur die Sprache an

[16:57] sich zu kennen, also nur Java zu kennen, sondern ich muss die ganzen Klassenbibliotheken kennen,

[17:02] die ganzen Klassen, die eingebaut sind, die Build-Tools und so weiter und so fort. Also es

[17:06] gibt viel mehr drumherum als nur die reine Sprache, die man kennen muss. Trotzdem wollen wir uns jetzt

[17:12] heute einmal in dieser Episode auf die Sprache an sich fokussieren. Und das ganze Ökosystem drumherum

[17:17] müsste man sich auch jedes Mal angucken, aber das führt einfach viel zu weit. Das kann ich hier

[17:21] ganz sicher nicht leisten und ist übrigens auch nicht Teil der Prüfung, denn wir wollen ja nicht

[17:25] produktspezifisch irgendwie was lernen, sondern wir wollen die Kerne des Ausbildungsinhalts hier

[17:30] uns mal anhören. Und wenn ich dann frage, was unterscheidet diese Sprachen, dann will ich jetzt

[17:34] nicht wissen, welche Klassen es hier gibt und welche Klassen in der anderen Bibliothek oder

[17:39] sonst wo, sondern ich will auf den Kern der Programmiersprachen hinaus, was die unterscheidet.

[17:42] Und das, das hören wir uns gleich mal an, was das jetzt ist. Gut, dann fangen wir doch vielleicht

[17:47] erst mal mit dem ersten Punkt an, und zwar ganz grob der Einsatzzweck. Ja, was will ich eigentlich

[17:52] mit dieser Sprache machen? Und wenn man jetzt nach Einsatzzwecksprachen unterscheidet, dann

[17:58] kann man zum Beispiel sich überlegen, welche Schwerpunkte diese Sprachen bilden. Es gibt zum

[18:03] Beispiel C, ja, damit kann ich ganz hardware-nah programmieren. Das heißt, wenn ich jetzt zum

[18:08] Beispiel, das ist immer mein Lieblingsbeispiel, eine Waschmaschine programmieren möchte, dann

[18:12] nehme ich wahrscheinlich C und nicht Java, weil die dafür einfach nicht gedacht ist. Also C ist

[18:16] sehr hardware-nah, Java ist vielleicht eher geeignet für so eine Enterprise-Anwendung oder

[18:20] für eine Web-Anwendung zum Beispiel. Also viele Sprachen wurden entwickelt mit einem bestimmten

[18:25] Hintergrund, mit einem Ziel, was sie da erreichen wollten. Es gibt auch viele Sprachen, die alles

[18:29] abdecken, überhaupt keine Frage, aber viele Sprachen haben so einen Schwerpunkt. Wenn man

[18:33] jetzt mal guckt, was so der Einsatzzweck heute sein könnte, da kann man sich unterscheiden,

[18:37] eine Web-Anwendung. Will ich eine klassische Web-Anwendung bauen, nehme ich zum Beispiel PHP

[18:41] oder Ruby, ja. Möchte ich zum Beispiel eine App entwickeln, dann gucke ich, auf welcher Plattform.

[18:44] Bin ich zum Beispiel auf dem iPhone unterwegs, brauche ich Swift, die Standardsprache für iOS-Anwendung.

[18:50] Wenn ich eine Desktop-Anwendung bauen will, also eine Windows-Anwendung zum Beispiel, dann nehme

[18:54] ich vielleicht am besten C-Sharp, weil C-Sharp ist dafür optimiert. Hat ganz viele, jetzt mal nur als

[18:58] Beispiel, ganz viele Bibliotheken, um halt mit Windows-Funktionalität zu interagieren. Das ist

[19:03] mit anderen Programmier-Sprachen einfach schwieriger. Oder wenn ich eine Server-Anwendung bauen will,

[19:06] weiß ich nicht, ein Microservice, der über eine REST-Schnittstelle irgendwas entgegennimmt, dann nehme ich

[19:09] vielleicht Java, weil Java halt sehr, weiß ich nicht, performance-optimiert ist und auf dem Server wenig

[19:14] Speicher braucht und schnell ist und ja, was auch immer. Also jede Programmier-Sprache hat vielleicht so

[19:18] ein bisschen ihre grundsätzliche Ausrichtung und danach könnte man sie schon als erstes unterscheiden.

[19:24] Dann kann man heutzutage natürlich, wenn wir im Web unterwegs sind, Frontend und Backend sehr gut

[19:28] unterscheiden. Frontend gibt es Stand heute, ich nehme das 2023 auf, ja, eigentlich nur JavaScript,

[19:34] was überhaupt möglich ist im Browser. Es kommt langsam so ein bisschen dazu, das Web-Assembly,

[19:38] das ist so die Alternative, aber in der Breite, glaube ich, ist heute immer noch JavaScript das

[19:44] dominierende oder die dominierende Programmier-Sprache. Es gibt gar keine andere, die der Browser ausführen

[19:48] kann. Das heißt, wir haben JavaScript im Frontend und im Backend, das heißt auf Server-Seite, also

[19:53] nicht im Browser, ja, da haben wir dann vielleicht eine ganz andere Sprache. Da nutzen wir vielleicht

[19:56] ein Java-Backend oder ein C-Sharp-Backend oder eben auch JavaScript. Inzwischen gibt es mit

[20:00] Node.js zum Beispiel auch eine Runtime, um JavaScript auf dem Server zu betreiben. Das geht auch.

[20:06] Dann gibt es so einen Begriff, den hast du sicher schon mal irgendwo gehört, das ist eine

[20:09] Skriptsprache. Eine Skriptsprache, das ist gar nicht so genau definiert, was damit eigentlich

[20:14] gemeint ist oder wie genau man das klassifizieren kann. PHP oder Ruby sind zum Beispiel Skriptsprachen,

[20:20] Bash sind auch Skriptsprachen. Das ist alles immer nicht ganz so trennscharf. Was die oftmals

[20:25] gemeinsam haben, ist, dass wir mit ganz wenig Programmieraufwand schnell sichtbare Ergebnisse

[20:30] produzieren möchten. Das heißt, als Gegenbeispiel, ich habe Java, da brauche ich erstmal einen Compiler,

[20:35] da muss ich alles 100% korrekt eintippen. Ich muss jede Semikolon richtig setzen,

[20:39] sonst funktioniert es nicht. Und wenn ich vielleicht eine Skriptsprache habe,

[20:42] dann verzeiht die mir vielleicht mal einen Fehler oder ich habe verschiedene Möglichkeiten,

[20:45] Sachen zu formulieren. Ich kann vielleicht Klammern weglassen oder ich kann, ja, kleine

[20:50] syntaktische Sachen machen, damit mir das Leben halt einfacher gemacht wird und ich mich nicht

[20:54] so ganz strikt an Regeln halten muss. Damit ich einfach schnell eben was Skripten mal eben

[20:59] schnell programmieren kann. Ganz oft sind das Interpretersprachen, die eben nicht kompiliert

[21:04] werden müssen, sondern ich schreibe den Sourcecode und kann ihn direkt ausführen. Also,

[21:09] das ist alles mit diesem Ziel, ich will schnell Ergebnisse produzieren. Da hindert mich der

[21:14] Compiler dran, der mir erstmal 100 Fehler um die Ohren wirft. Ganz oft sind die auch dynamisch

[21:19] typisiert, damit ich eben Variablen keine Typen geben muss, weil das wird mich ja wieder aufhalten.

[21:23] Ich sage einfach Variable gleich Wert und dann wird das da drin gespeichert. Das funktioniert

[21:28] dann einfach. Wir gehen später nochmal auf die Typisierung ein. Meist ist es so, dass diese

[21:33] Sprachen dynamisch typisiert sind, weil ich dann einfach schneller programmieren kann. Ich muss

[21:36] halt weniger tippen. Ich muss nicht vor jeden String nochmal String schreiben, weil die

[21:39] Programmiersprache macht das einfach für mich so. Beispiel, die ich jetzt nennen würde als

[21:44] übliche Skriptsprachen heutzutage, wären sicherlich die PowerShell oder Bash-Skripts.

[21:48] Die heißen ja sogar so, wenn du Linux skriptest. Oder eben auch PHP. PHP ist auch eine Skriptsprache,

[21:53] damit, wenn man sich überlegt, wann die erfunden wurde und wofür die erfunden wurde, da wollte

[21:58] einfach jemand, jetzt habe ich den Namen vergessen, wer PHP erfunden hat, auf jeden Fall wollte der

[22:02] nicht mit C irgendwelche Web-Server-Anwendungen programmieren, weil es viel zu aufwendig war.

[22:05] Deswegen hat er sich PHP ausgedacht, die auf C basiert, um eben einfach und schnell programmieren

[22:11] zu können. Deswegen hat die auch ganz andere Eigenschaften als C, weil sie nämlich genau das,

[22:15] was C schlecht gemacht hat, besser machen wollte. Deswegen ist sie zum Beispiel anders typisiert.

[22:20] Ja und ein weiteres Beispiel ist eine Web-Programmiersprache. Das sind so die üblichen

[22:26] Programmiersprachen, die heute in Web-Projekten eingesetzt werden. Das sind oft auch selber

[22:30] wieder Skriptsprachen. Und was hier der Vorteil ist, die bringen meist sehr umfangreiche Bibliotheken

[22:35] mit oder sogar ganze Frameworks für Web-Anwendungen. Das heißt, ich habe ein Rahmenwerk vorgegeben und

[22:41] klinke mich da rein und dann kann ich relativ schnell gut sichtbare Ergebnisse produzieren,

[22:46] dadurch, dass die Sprachen so darauf optimiert sind. Und da sind die üblichen sowas wie PHP,

[22:51] das ist sicherlich die dominierende Sprache im Web. Ich weiß nicht, wie viel Prozent, ein sehr großer

[22:55] Anteil aller Websites der Welt läuft auf PHP. Dann haben wir aber auch Ruby oder Python. Letztlich

[23:01] kann man heute auch in jeder anderen Programmiersprache eine Web-Anwendung bauen. Das

[23:04] müsste inzwischen so jede Sprache können. Aber die klassischen Web-Programmiersprachen sind

[23:08] sicherlich ganz weit vorn PHP und dann Python, Ruby, vielleicht noch Perl. Die genannte

[23:16] Klassifizierung dieses Einsatzzwecks ist vielleicht so ein bisschen schwammig. Das würde ich jetzt

[23:21] vielleicht auch nicht als allererstes in so einer Prüfung machen oder sagen. Aber das, was jetzt

[23:25] kommt, wird dann schon ein bisschen trendschärfer. Und das ist jetzt unser nächster Punkt. Das ist

[23:29] das Programmierparadigma. Ein Programmierparadigma, wie zum Beispiel die Objekteorientierung, das

[23:35] kennst du sicherlich, das gibt uns die grundsätzliche Art und Weise vor, wie wir mit

[23:39] einer Programmiersprache arbeiten. Also das definiert, wie zum Beispiel grundlegend herangegangen wird

[23:45] an die Problemlösung, welche Prinzipien wir bei der Softwareentwicklung anwenden, aber auch ganz

[23:50] konkret, wie die Syntax aussieht. Was können wir mit der Sprache überhaupt machen? Also was gibt es

[23:55] in der Sprache? Arbeiten wir zum Beispiel mit Objekten in der Objektorientierung, also Objekte,

[24:00] die Attribute und die zugehörigen Funktionen kapseln? Oder arbeiten wir vielleicht mit

[24:04] Funktionen, wie in der funktionalen Programmierung, wo dann zum Beispiel gar keine Daten dabei sind,

[24:09] sondern eben nur die reine Implementierung, die Funktion. Das heißt, welche Dinge sind die

[24:15] sogenannten First Class Citizens der Sprache? Also was ist das Ding, was die Sprache definiert? Was

[24:22] zum Beispiel, First Class Citizen heißt dann auch, ich kann diese Dinge zum Beispiel in einer Variablen

[24:27] ablegen. In Java kann ich Objekte in Variablen speichern. In funktionalen Sprachen kann ich auch

[24:33] Funktionen in einer Variable speichern. Das geht in Java nicht. Ja, ich weiß, in eurer Version von

[24:38] Java ab 8 geht das hintenrum schon, aber eigentlich nicht wirklich, denn die Funktion als solches ist

[24:45] in Java eben kein First Class Citizen, sondern ich brauche immer ein Objekt drumherum, weil die

[24:51] Sprache so gebaut ist, weil sie nämlich intern objektorientiert arbeitet und eben nicht funktional.

[24:56] In funktionalen Programmiersprachen geht das aber. Da kann ich einfach sowas sagen wie Variable a

[25:00] gleich und dann schreibe ich da eine Funktion hin und dann ist die Variable mit dieser Funktion

[25:04] initialisiert und dann kann ich die auch zum Beispiel als Parameter durch die Gegend reichen,

[25:09] wenn ich das möchte. Jetzt gibt es einen Begriff, den man sich dann hier auch gut merken sollte und

[25:15] zwar die idiomatische Programmierung. Englisch idiom. Das ist das, wie man in der Programmiersprache

[25:21] programmieren sollte. Ich habe gerade schon gesagt, ich kann in Java so ein bisschen hintenrum

[25:26] neuerdings auch Funktionen in Variablen speichern. Das sind dann zum Beispiel Lambda-Ausdrücke, die

[25:30] aber eigentlich nur im Hintergrund vom Compiler wieder in Klassen umgewandelt werden und dann

[25:35] werden doch am Ende wieder Objekte in den Variablen gespeichert. Aber es sieht so aus, als wären das

[25:40] Funktionen. Und jetzt könnte ich auf die Idee kommen, wenn beides geht, also Objekte und so

[25:44] hintenrum Funktionen, dann nehme ich doch mal das eine oder mal das andere oder ich nehme jetzt

[25:48] einfach nur noch Funktionen. Und wenn jetzt andere Entwickler dieser Programmiersprache deinen Code

[25:53] lesen, dann werden sie sich fragen, warum machst du das jetzt so? Eigentlich macht man das in Java

[25:58] doch so und so. Und das ist die idiomatische Programmierung. Jetzt mal als Beispiel, wenn

[26:05] du in einer funktionalen Programmiersprache eine Vorschleife programmierst, dann machst du schon

[26:10] was falsch, weil funktionale Programmierung hat als wichtige Eigenschaft die Immutability, also die

[26:15] Unveränderbarkeit von Variablen. Aber was brauchst du bei einer Vorschleife? Eine Iterationsvariable,

[26:21] die heißt meistens i und die wird durchgezählt. for int i gleich 1 bis 10, das heißt i, 1, 2, 3, 4,

[26:27] 5 bis 10 wird verändert und das will die Programmiersprache nicht, wenn sie funktional ist.

[26:32] Die will nämlich keine veränderbaren Variablen haben, eigentlich. Das heißt, wenn du jetzt eine

[26:36] Vorschleife in einer funktionalen Sprache programmierst, dann programmierst du nicht

[26:39] idiomatisch, weil die Sprache eigentlich nicht will, dass du Vorschleifen programmierst. Auch wenn

[26:45] du das darfst, auch wenn der Compiler sagt, mach ich für dich, ist das nicht idiomatisch. Und

[26:50] diese Programmierparadigmen, die geben uns eben vor, wie wir in dieser Sprache programmieren

[26:56] sollten. Viele Sprachen heutzutage sind sogenannte Multiparadigmen-Sprachen, wie Java inzwischen

[27:03] auch. Java ist im Kern objektorientiert, aber ich habe halt inzwischen auch ganz viele funktionale

[27:07] Aspekte da drin oder teilweise sogar prozedurale Aspekte. Ich kann ja auch einfach zum Beispiel,

[27:12] du kennst vielleicht die Main-Methode, den zentralen Einstiegspunkt in jedes Java-Programm,

[27:16] da kann ich auch so ein 500-Zeilen-Main-Ding draus machen, was einfach von oben nach unten

[27:20] abgearbeitet wird. Habe ich quasi prozeduralen Code. Das heißt, es ist manchmal nicht immer so

[27:24] ganz klar, welches Paradigma wirklich in der Programmiersprache bewendet wird, aber ganz

[27:28] viele Sprachen haben so ein dominierendes Paradigma, haben aber drumherum ganz viele

[27:33] Möglichkeiten auch aus anderen Paradigmen übernommen. Und das sieht man heutzutage gerade,

[27:37] die funktionalen Möglichkeiten, die werden auch in viele objektorientierte Sprachen übernommen,

[27:42] zum Beispiel C-Sharp und Java. Die haben sich ganz viel funktional quasi abgeguckt und in die

[27:47] Sprache mit reingebracht. Also, Multiparadigmen-Sprache heißt, ich kann auf mehrere Arten

[27:55] und Weisen programmieren. Es gibt trotzdem immer noch so meistens eben das eine, was eigentlich

[28:00] dominierend ist, in Java weiterhin die Objektorientierung zum Beispiel. Das heißt,

[28:03] ich könnte mich jetzt entscheiden, in Java nehme ich jetzt die Vorschleife oder nehme ich vielleicht

[28:07] doch eine rekursive Lösung. Entweder das eher objektorientierte oder eher das Funktionale. Das

[28:13] ist jetzt nicht so trendscharf, aber es gibt eben, wie gesagt, in Java eher den Fokus auf die

[28:18] Objektorientierung. Also im Zweifel nehme ich lieber das, weil das eigentlich der Sinn der

[28:22] Sprache mal war. So, bevor wir uns jetzt wirklich ein paar konkrete Paradigmen anschauen, noch mal

[28:29] einmal eine grundsätzliche Unterteilung. Das ist nicht das eine Paradigma oder nicht. Es gibt aber

[28:35] noch eine Einteilung, wie man die Paradigmen auch unterscheiden kann, und zwar imperative und

[28:40] deklarativ. Das ist nicht für sich allein stehend ein Paradigma, aber das unterscheidet so ein

[28:45] bisschen auch die Programmierweise. Und imperative Programmierung, das ist so das Klassische,

[28:50] was du wahrscheinlich auch schon mal im Programmierkurs gelernt hast. Mach, mach, mach,

[28:54] if, for, etc. Also dem Computer genau sagen, was er tun soll. Imperativ kennst du vielleicht noch aus

[29:02] dem Deutschunterricht. Das ist ja die Befehlsform. Mach, geh, putz die Wohnung, was auch immer. Und

[29:09] das kommt vom lateinischen imperare. Das bedeutet befehlen. Also sag dem Computer, befiehl dem

[29:14] Computer, was er machen soll, und zwar exakt in welcher Reihenfolge er was wie tun soll. Das ist

[29:20] die imperative Programmierung. Und das findest du wieder, wenn du so was machst wie Sequenzen,

[29:24] Wiederholung und Verzweigung, weil das ist genau das. Nimm die Äpfel, schäle die Äpfel,

[29:29] leg die Äpfel auf den Teig. Mach, mach, mach, mach. Imperativ. Dem gegenüber gibt es aber auch

[29:34] das deklarative Programmieren. Das kommt vom lateinischen deklarare. Das heißt erklären.

[29:40] Kennst vielleicht auch deklarieren von Variablen. Da legt man Variablen fest,

[29:45] gibt ihr einen Datentyp und einen Namen. Und dabei programmiert man nicht, indem man dem Computer

[29:52] sagt, was er tun soll, also oder wie er es tun soll, sondern man sagt lediglich, was man von

[29:56] dem Computer haben will. Und als Beispiel kannst du SQL nehmen. Bei SQL sagst du nicht, geh in die

[30:03] Datenbank, such jede Tabelle durch, guck in Spalte X, ob der Wert 5 ist und wenn ja, packst in die

[30:09] Liste. Dann gib die Liste zurück und sortier die Liste absteigend. Sowas machst du doch nicht,

[30:13] sondern du sagst in SQL, gib mir bitte aus der Kundentabelle alle Kunden mit Nachnamen Macke.

[30:19] Und dann macht die Datenbank das einfach für dich. Wie die das konkret macht, siehst du gar

[30:23] nicht. Du sagst nur, was du haben willst. Alle Kunden mit Nachnamen Macke. Was jetzt die Datenbank

[30:28] im Hintergrund macht, da sie eine Datei aufmachen muss, wo die ganzen Kunden drin sind. Da muss sie

[30:32] die durchlesen. Da muss sie im Nachnamen gucken, ob da Macke drin steht. Wenn ja, packt es das in

[30:36] die Liste. Wenn nicht, nächster Datensatz etc. Also alles das, was du sonst händisch,

[30:40] imperativ programmieren müsstest, das musst du da nicht. Das überlässt du einfach der

[30:44] Datenbank. Deswegen ist SQL zum Beispiel eine deklarative Sprache, weil du gar nicht genau

[30:49] sagen kannst, was der Computer tun soll, wenn er das ausführt, sondern du sagst nur, was das

[30:53] Endergebnis sein soll. Der Computer liefert dir das. Das ist erstmal eine coole Idee, aber du

[31:00] hast halt weniger Kontrolle darüber. Du kannst bei deinem SQL-Befehl zum Beispiel nicht sagen,

[31:05] dass er es auf eine bestimmte Art und Weise machen soll, weil du weißt, dass es dadurch

[31:08] schneller wird, sondern du musst die ganze Kontrolle abgeben. Die Datenbank entscheidet

[31:12] selbst, wie sie das macht. Die gibt dir nur das erwartete Ergebnis. Das kann man jetzt aber auch

[31:17] auf – wir hatten ja schon gelernt, SQL ist keine Programmiersprache – deswegen kann man das auch

[31:20] auf echte Programmiersprachen übertragen. Ich nehme einfach wieder ein simples Java-Beispiel,

[31:24] die Vorschleife von eben. Lauf mal bitte durch die Liste, fang bei Index 0 an, zähle bis 10,

[31:29] gehe durch die Liste durch und gebe mir das Element an der jeweiligen Position aus. Das ist

[31:33] eine klassische imperative Programmierung. Definitive Variable, lauf die Liste durch,

[31:38] gebe das aus. Ich kann aber in modernem Java auch einfach sowas machen wie List.forEach und

[31:45] dann System.out.println. Und dann ist das fertig. Das heißt, da muss ich mich gar nicht darum

[31:49] kümmern, wie lang die Liste ist, ich brauche keinen Index, ich muss nicht gucken, dass ich

[31:52] plus-minus-eins-fehler abfange etc. Sondern ich sage einfach, hey Liste, iterier mal über dich

[32:00] und für jedes Element gibst du das Ding einfach aus. Das ist das, was ich der Liste nur noch sagen

[32:06] muss und dann macht die das einfach. Und wo sie anfängt zu zählen, welche Reihenfolgen, wo sie

[32:09] aufhört, habe ich gar keine Kontrolle mehr drüber. Der Vorteil dabei ist jetzt in modernen Sprachen,

[32:14] zum Beispiel auch in Java, wenn ich so programmiere, dann könnte ich mit einer einzigen Zeile Code

[32:20] diese Bearbeitung, die ich gerade erklärt habe, die Listenbearbeitung, auch parallelisieren. Denn

[32:24] ich habe gar keine Kontrolle mehr darüber, wie über die Liste gelaufen wird. Also könnte der

[32:28] Computer auch einfach sagen, dass er mit zwei Threads gleichzeitig über die Liste läuft. Der

[32:32] eine fängt vorne an, der andere fängt hinten an und wenn sie sich in der Mitte getroffen haben,

[32:35] dann ist Feierabend. Und so kann man zum Beispiel eine Liste auf zwei Prozessoren gleichzeitig

[32:40] durchlaufen, was vorher sehr sehr schwierig war. Denn bei der Vorschleife kann ich nicht sagen,

[32:44] bei int i gleich 1 gehst du auf den einen Prozessor, bei 2 gehst du auf den anderen Prozessor, bei 3

[32:50] gehst du wieder auf den einen. Das kannst du gar nicht programmieren oder jedenfalls nicht so

[32:53] einfach. Und wenn ich der Programmiersprache diese Iterationen überlasse, indem ich einfach

[32:58] sage, lauf drüber und mach was, aber wie du es machst, interessiert mich nicht, könnte der

[33:02] Computer ja auch sagen, dann mache ich es halt einfach parallel. Kommt ja zum gleichen Ergebnis.

[33:06] Du siehst das gar nicht, wie der Computer das ausführt und du kannst es auch gar nicht

[33:10] beeinflussen, sage ich mal. Das ist dann hier der Vorteil. Der Nachteil ist gleichzeitig genau das,

[33:15] was ich gesagt habe, du kannst es nicht beeinflussen. Denn wenn du es beeinflussen

[33:18] musst, weil du genau programmieren musst, was wie zu passieren hat, dann geht das halt bei der

[33:23] deklarativen Programmierung nicht mehr. Das heißt, das werden wir heute auch noch öfter hören,

[33:26] es gibt eigentlich immer so Trade-Offs. Es gibt nicht die eine perfekte Lösung,

[33:31] sondern die haben immer auch Nachteile. Imperative Programmierung hat ganz ganz viele Nachteile,

[33:35] aber auch ganz ganz viele Vorteile, genau wie bei den deklarativen. Es ist immer genau das

[33:39] Gegenteil. Der Vorteil der Imperativen ist gleichzeitig der Nachteil der deklarativen und

[33:42] umgekehrt. Das heißt, man kann ja nicht sagen, das eine ist besser oder schlechter, sondern es

[33:46] kommt, wie immer, auf den Einsatzzweck an. Und genau deswegen mache ich heute auch die Episode

[33:50] hier. Denn wenn wir für unser Projekt eine Programmiersprache aussuchen wollen, dann sollten

[33:54] wir vielleicht wissen, welche die beste geeignet ist. Und es gibt über 200 verschiedene

[33:58] Programmiersprachen. Das heißt, da müsste ich dann vielleicht mal ein bisschen einschätzen

[34:01] können für mein konkretes Problem, welche Sprache ist denn jetzt besser geeignet. Und wenn ich zum

[34:06] Beispiel super super hardware-nah auf einem kleinen Mikroprozessor was programmiere und

[34:10] ich exakt bestimmen können muss, wie viel Speicher belegt wird, wie viele CPU-Zyklen

[34:16] was berechnet wird, dann nehme ich vielleicht keine deklarative Programmiersprache, die das

[34:20] alles vor mir verbirgt und wo ich das gar nicht bestimmen kann, sondern nehme ich vielleicht

[34:23] lieber eine Imperative, wo ich genau sagen kann, mach das, mach das, mach das. Weil die Plattform

[34:27] das einfach erfordert zum Beispiel. Also das ist ganz wichtig. Deswegen auch dieses, wir müssen

[34:34] Programmiersprachen unterscheiden können im Ausbildungsrahmenplan. Denn wenn ich sie nicht

[34:37] unterscheiden kann und gar nicht weiß, was die Vor- und Nachteile sind, dann kann ich für mein

[34:40] konkretes Problem ja auch keine aussuchen. Das heißt, ich muss erst mal verstehen, was die

[34:43] Unterschiede sind und dann kann ich im zweiten Schritt bewerten, welche Sprache für mein

[34:47] konkretes Projekt jetzt am geeignetsten ist. So, dann kommen wir jetzt mal zu den konkreten

[34:52] Programmierparadigmen, die es da so gibt. Und da erzähle ich meinen eigenen Zubis auch immer so

[34:59] ein bisschen geschichtsunterrichtsmäßig immer dran denken, wie sich das so entwickelt hat mit

[35:04] der Programmierung. Dann kann man auch mit ein bisschen üben, die alle nacheinander aufzählen.

[35:08] Dann kann man sich so eine kleine Geschichte daraus machen. Und zwar fangen wir mal ganz ganz

[35:11] vorn an bei den ersten Computern, die man überhaupt programmieren konnte. Und da gab

[35:16] es die sogenannte unstrukturierte Programmierung. Dort wurde zum Beispiel eine Fallunterscheidung

[35:21] und eine Wiederholung mit einem sehr beliebten Statement gemacht und zwar mit dem sogenannten

[35:25] Go-To. Mit dem Go-To konnte ich von einem Punkt im Code zu einem anderen Punkt im Code springen.

[35:34] Ein simples Beispiel. Ich sage in Zeile 20, ich hätte gerne wieder in Zeile 10,

[35:39] er wäre gerne wieder in Zeile 10, dann springt er wieder dahin. Und in Zeile 10 mache ich dann zum

[35:43] Beispiel irgendwie, keine Ahnung, Output Hello und also das Programm würde so aussehen. 10,

[35:48] Output Hello, 20, Go-To 10. Das heißt, er geht wieder hoch. Das heißt, es wird eine Endlosschleife,

[35:53] die immer wieder Hallo, Hallo, Hallo, Hallo, Hallo ausgibt. Damit könnte ich eine Wiederholung

[35:57] programmieren mit diesem Go-To. Ich kann aber auch bedingte Sprünge machen. Ich könnte zum

[36:02] Beispiel sagen, wenn Alter Größe 18, dann springen die Zeile. Wenn nicht, dann springen

[36:07] die andere Zeile. Und so kann ich dann, ja, alles abbilden, was ich in einer poemischen Sprache

[36:11] abbilden muss, nämlich Sequenzen, Sprünge, also Verzweigung und Wiederholung. Das kann ich alles

[36:15] mit diesem einen Statement machen, mit Go-To. Das Blöde bei dem Go-To ist aber, dass man im

[36:20] Nachhinein gar nicht mehr so gut herausfinden kann, wie das Programm eigentlich abgelaufen ist,

[36:24] denn wenn ich jetzt in Zeile 20 gerade Code ausführe, habe ich keine Ahnung, wie ich

[36:28] dahin gekommen bin. Kann sein, dass das Programm gerade zum ersten Mal ausgeführt wird und in

[36:31] Zeile 20 landet. Kann aber auch sein, dass ich aus irgendeinem If oder irgendeiner Wiederholung

[36:37] wieder in Zeile 20 gelandet bin. Das heißt, ich kann nicht mehr rückwirkend nachvollziehen,

[36:41] wie ich dahin gekommen bin. Und das ist ganz, ganz schlecht, denn wenn ich wissen will,

[36:44] wie das Programm funktioniert hat, um zum Beispiel bei einem Fehler zu landen, dann muss

[36:48] ich das nachvollziehen können. Und das kann ich aber mit einem Go-To nicht. Und deswegen hat ein

[36:52] sehr berühmter Mathematiker, der Herr Deigstra, mal einen Artikel geschrieben, Go-To considered

[36:59] harmvoll. Da hat er gesagt, Go-To, das ist eigentlich kein so gutes Statement, denn wenn

[37:03] wir das benutzen, dann kann kein Mensch mehr unsere Programme nachvollziehen. Und das ist

[37:06] nicht so gut. Dem Computer ist das ziemlich egal, aber der Mensch, der das liest, nicht so gut.

[37:11] Deswegen wollen wir Go-To nicht mehr einsetzen. Und das war dann der Beginn der sogenannten

[37:15] strukturierten Programmierung. Dort hat man jetzt gesagt, ich verzichte auf Go-To und

[37:20] stattdessen nehme ich Kontrollstrukturen, wie zum Beispiel If und While. Beim If und beim While,

[37:25] da ist es eindeutig, wenn ich es im Code sehe, wie ist der Code dahingekommen, wie oft wurde was

[37:29] gemacht, warum wurde was gemacht. Es ist nicht, ja, ich will jetzt nicht sagen zufällig, zufällig ist

[37:34] beim Computer nichts, aber es ist nicht mehr so schwierig nachzuvollziehen, warum ein Programm wie

[37:39] ausgeführt wurde. Und das ist gut fürs Verständnis. Deswegen, strukturierte Programmierung. So,

[37:44] jetzt hat man dann schnell aber festgestellt, strukturierte Programmierung ist super,

[37:47] aber ständig programmieren wir hier Sachen doppelt und dreifach, wenn wir Sachen doppelt

[37:50] und dreifach machen müssen. Das ist irgendwie nicht gut. Lass uns doch mal was einbauen,

[37:54] dass wir solche kleinen Unteralgorithmen so auslagern können, dass wir sie wieder aufrufen

[37:58] können. Und das war der Beginn der prozeduralen Programmierung. Diese kleinen wiederverwendbaren

[38:03] Codeschnipsel, die hat man nämlich Prozeduren genannt und diese Prozeduren konnte man einfach

[38:08] aufrufen und da musste man nicht ständig copy und paste programmieren. Das heißt,

[38:12] ich habe jetzt die Möglichkeit quasi Unterprogramme zu erstellen, eben diese Prozeduren. Den konnte ich

[38:17] dann auch einen Namen geben und schon wurde mein Programm viel, viel, viel verständlicher. Wenn

[38:22] ich nämlich meine kleine Subroutine irgendwie ziehe Wurzel nenne, dann ist das schon deutlich

[38:26] sprechender, als wenn ich irgendwelche wilden mathematischen Sachen mache und man muss jedes

[38:30] Mal wieder verstehen, was da eigentlich gemacht wird. Ach, die Wurzel ziehen, ja. Wäre doch schön,

[38:34] wenn es auch drüber stehen würde und das geht jetzt bei der prozeduralen Programmierung.

[38:37] Übrigens kleiner Exkurs, Prozeduren, die keine Rückgabewerte haben, heißen tatsächlich Prozeduren

[38:44] und die Rückgabewerte haben, die heißen Funktionen. Also wenn du es mal auf Java zum Beispiel überträgst,

[38:50] die Void-Funktionen, das sind eigentlich Prozeduren. Ja, die heißen eigentlich Prozeduren. Gut, ich

[38:56] mache sehr viele Exkursionen heute. Ich sehe mal zu, dass es weitergeht. Deswegen kommen wir zum

[39:00] nächsten Paradigma und zwar hat man sich dann immer gesagt, so Prozedurale Programmierung ist

[39:06] eigentlich schon eine ganz coole Sache, aber irgendwie bildet das nicht so ganz das ab,

[39:10] was wir eigentlich in der Realität haben. Und viele Programme, um nicht zu sagen alle,

[39:14] sollen ja irgendeinen Teil der Realität modellieren. Dafür bauen wir ja diese Programme.

[39:19] Und dann wäre es doch gut, wenn das, was wir in der Poämischsprache nutzen könnten,

[39:23] auch irgendwie der Realität entsprechen würde. Und siehe da, die Objektorientierung wurde geboren.

[39:28] Denn was sehen wir in der Realität? Da haben wir immer irgendwelche Dinge, mit denen wir arbeiten.

[39:32] Und diese Dinge haben Eigenschaften und Funktionen. Ja, ich sehe jetzt gerade vor mir einen Tisch. Der

[39:37] Tisch hat eine Farbe, das ist das Attribut. Der Tisch hat aber auch eine Funktion. Ich kann zum

[39:42] Beispiel den Tisch, das ist jetzt ein schlechtes Beispiel, zusammenkloppen und dann haue ich ihn

[39:48] kaputt. Ja, wenn ich das möchte, kann ich das machen. Das kann ich aber auf jeden Fall mit

[39:51] einem Tisch tun. Warum kann ich das also nicht in meiner Programmiersprache so abbilden? Nehmen wir

[39:55] mal ein sinnvolleres Beispiel. Ich habe ein Auto, das Auto hat eine Farbe. Das Auto kann aber auch

[40:00] fahren oder bremsen. Das ist offensichtlich eine Funktion, die dieses Auto hat. Und jetzt wäre

[40:06] es doch schön, wenn meine Programmiersprache das auch abbilden könnte, dass ich …

[40:09] Daten, nenne ich die Attribute, mit den dazugehörenden Funktionen zusammen als Einheit modellieren kann.

[40:17] Und das war die Idee oder ist die Idee der Objektorientierung. Das ist die erste Säule der Objektorientierung, die Kapselung.

[40:23] Ich kapsele die Attribute, also die Daten, mit denen ich arbeite, zusammen mit den Funktionen, die mit diesen Daten arbeiten, in einem Ding.

[40:33] Und dieses Ding nenne ich dann Objekt und schon habe ich die Objektorientierung.

[40:38] Das versucht also, die Realität bestmöglich abzubilden, so wie wir sie kennen.

[40:42] Und deswegen ist es auch heutzutage immer noch das dominierende Paradigma, weil es halt diese Realwelt so gut beschreibt,

[40:48] weil wir als Menschen das halt so kennen, dass Dinge Eigenschaften und Funktionen haben.

[40:52] Und das kann ich nur in der Objektorientierten Programmierung so umsetzen.

[40:57] Objektorientierung, ganz wichtiges Prüfungsthema, habe ich auch schon viele Podcast-Episoden zu aufgenommen.

[41:02] Kurzer Hinweis nochmal, die Kapselung hatte ich gerade grob erklärt.

[41:05] Es gibt natürlich als die anderen beiden Säulen die Vererbung und die Polymorphie.

[41:09] Die soll man auch erklären können, die kann ich heute aber jetzt nicht nochmal durchkauen zum nächsten Mal.

[41:13] Dafür reicht die Zeit einfach nicht. Aber höre dir das unbedingt an, weil das ist auch zentraler Prüfungsbestandteil.

[41:18] Die Objektorientierung musst du rauf und runter kennen.

[41:20] So, parallel zur Objektorientierung hat sich aber noch ein anderes Paradigma entwickelt, und zwar die funktionale Programmierung.

[41:27] Denn es gibt tatsächlich auch einen Bereich in der realen Welt, wo Daten gar nicht so interessant sind,

[41:31] sondern mehr die Funktionen, die man auf diesen Daten ausführt, nämlich die Mathematik.

[41:35] Die Mathematik kennst du vielleicht noch aus dem Schulunterricht.

[41:37] Die gute alte, löse doch diese Formel nach X auf.

[41:41] Und dann gibt es die Mitternachtsformel hier für quadratische Gleichungen, um die aufzulösen und solche Sachen.

[41:46] Und diese mathematische Welt passt jetzt nicht so gut zu dieser Objektorientierung.

[41:51] Denn da haben wir halt eben mathematische Funktionen.

[41:55] Und es wäre ja jetzt schön, wenn wir mit diesen Funktionen als First Class Citizen arbeiten können, wie vorhin schon beschrieben.

[42:02] Und da hat sich dann jemand die funktionale Programmierung ausgedacht.

[42:05] Und da gibt es dann ganz andere Herangehensweisen bei der Programmierung.

[42:09] Nur mal als Stichwort, wie bei der Objektorientierung, wenn man Vererbung und Polymorphie nennt,

[42:13] dann nennt man bei der funktionalen Programmierung zum Beispiel higher order functions,

[42:16] das heißt Funktionen, die andere Funktionen als Parameter bekommen.

[42:20] Das ist nämlich dann die Möglichkeit, um immer abstrakter zu werden, wie bei der Objektorientierung, wo es dann anders gelöst wird.

[42:27] Oder eben sowas wie Immutability, also die Unveränderbarkeit.

[42:30] Und daraus folgend dann zum Beispiel der Fokus auf die Rekursion statt auf die Iteration.

[42:35] Also statt einer Vorschleife würde ich halt in der funktionalen Programmierung eher rekursive Aufrufe programmieren.

[42:41] Es gibt noch ein paar weitere Merkmale, da mache ich jetzt hier mal eine Episode zu.

[42:44] Funktionale Programmierung wird heutzutage immer, immer, immer wichtiger.

[42:47] Denn der große Vorteil ist, ich kann diese Programme perfekt parallelisieren.

[42:51] Denn der große Nachteil der Objektorientierung sind genau diese Daten, die da in den Objekten drin stehen.

[42:56] Denn wenn diese Daten gleichzeitig von mehreren Prozessoren zum Beispiel gelesen und geändert werden,

[43:01] dann haben wir ein Problem in unserem Programm.

[43:04] Denn das ist dann gar nicht mehr so gut vorhersehbar, wie die Daten am Ende aussehen,

[43:08] wenn zwei Prozessoren gleichzeitig da irgendwie drauf rumwirkeln.

[43:11] Und sowas soll ausgeschlossen werden in der funktionalen Programmierung.

[43:15] Deswegen wird dort einfach anders programmiert.

[43:17] Deswegen nochmal, Programmierparadigma sagt, wie ich mit der Sprache überhaupt arbeiten kann.

[43:22] Und einige funktionale Programmiersprachen verbieten mir zum Beispiel, dass ich Variablen überhaupt ändern kann.

[43:27] Also gibt es gar keine Variablen in dem Sinne, weil das dann die Auswirkung hätte,

[43:32] dass vielleicht bei nebenläufiger Abarbeitung bei änderbaren Daten auf einmal Murks passiert.

[43:39] Da sieht man, wie stark einschränkend vielleicht so ein Paradigma auf meine Programmiertätigkeit auch sein kann.

[43:47] Parallel hat sich dann aber noch ein weiteres Paradigma entwickelt, und zwar die logische Programmierung.

[43:52] Und da arbeitet man auf Basis von mathematischen Aussagen.

[43:56] Da hast du bestimmt schon mal was von gehört.

[43:58] Eine Aussage kann eben eine Aussage, die wahr oder falsch sein kann.

[44:02] Wie zum Beispiel, die Erde ist eine Scheibe.

[44:05] Diese Aussage ist definitiv falsch.

[44:07] Ich hoffe, du als Hörer dieses Podcasts weißt das und erzählst mir jetzt nicht das Gegenteil.

[44:12] Das heißt, ich habe bestimmte Aussagen, die können wahr oder falsch sein.

[44:16] Und aus diesen Aussagen kann ich dann quasi Schlussfolgerungen machen.

[44:19] Mein sehr einfaches Beispiel, um das zu erklären, wäre, Hans ist der Vater von Peter.

[44:25] Peter ist der Vater von Klaus.

[44:27] Also ist Hans der Großvater von Klaus.

[44:31] Ich hoffe, ich habe jetzt alle Namen richtig auf der Kette gehabt.

[44:34] Das heißt, wenn ich mit dieser Ist-Vater-von-Aussage arbeite und ich dann zwei hintereinander habe,

[44:40] dann kann ich daraus die Schlussfolgerung machen, dass ich der Großvater von jemandem ist.

[44:44] Diese Person zum Beispiel.

[44:45] Und aus diesen Aussagen setze ich jetzt mein Programm zusammen.

[44:48] Und am Ende kann ich dann so etwas, also jetzt mal ganz einfach.

[44:52] Ich habe so was wie Ist-Vater-von, gibt es als Beziehung.

[44:55] Und dann kann ich sagen, Großvater bedeutet Ist-Vater-von plus Ist-Vater-von.

[45:00] Also quasi zwei Generationen weiter.

[45:02] Und das definiere ich in meinem Programm.

[45:04] Und jetzt füttere ich das Programm in eine Datenbasis und sage immer nur,

[45:07] hm, Ist-Vater-von, hm, Ist-Vater-von, hm, Ist-Vater-von, also Bob von Klaus und Klaus von Peter und ich weiß nicht was.

[45:12] Und dann kann ich am Ende das Programm dann fragen, wer ist der Großvater von Timmy?

[45:17] Und dann kann das Programm die Schlussfolgerung aus dieser Datenbasis ziehen,

[45:21] ohne dass ich irgendwie programmieren muss, wie das Programm dahin kommt.

[45:24] Das heißt, ich muss dem Programm nicht sagen,

[45:26] geh mal bitte alle Vaterbeziehungen durch und dann immer noch eine Ebene weiter

[45:30] und dann weißt du, wer der Großvater ist, sondern das macht das Programm selbst.

[45:34] Das heißt, die Herangehensweise ist auch eher deklarativ als imperative.

[45:38] Ich definiere nur, wie meine Daten zusammenhängen und das Programm schlussfolgert selbst

[45:44] und findet selber die Lösung für meine Anfrage.

[45:49] Das lässt sich erstaunlich selten in der Realität nutzen, dieses Vorgehen, ja.

[45:53] Deswegen ist die logische Programmierung jetzt auch nicht so verbreitet.

[45:56] Programmiersprache, die du vielleicht schon mal gehört hast, ist Prolog.

[45:59] Das ist eine logische Programmiersprache.

[46:01] Funktionale Programmiersprachen sind jetzt auch nicht so verbreitet in der Realität,

[46:05] also zumindest nicht rein funktionale Programmiersprachen.

[46:08] Java und C Sharp und so, die haben ja alle funktionale Aspekte,

[46:11] sind aber im Kern weiterhin objektorientiert.

[46:13] Das heißt, wenn man einfach mal auf den Markt guckt, so eine ganz grobe,

[46:16] also ich will keine Zahlen nennen, aber der Großteil der Programme da draußen

[46:20] wird objektorientiert sein.

[46:22] Dann kommt eventuell mal irgendwie ein bisschen funktional,

[46:24] wahrscheinlich vorher noch sogar prozedural,

[46:26] weil C zum Beispiel ist eine prozedurale Programmiersprache

[46:29] und ganz, ganz viel Embedded Code, zum Beispiel im Auto oder in der Waschmaschine und so,

[46:33] ist in C programmiert.

[46:34] Also wenn ich eine Rangfolge geben müsste, und das ist einfach nur Bauchgefühl,

[46:38] ich habe keine Zahlen, die das untermalen,

[46:41] würde ich sagen, mit weitem Abstand vorne objektorientiert,

[46:43] dann prozedural, dann funktional und dann eventuell mal irgendwann logisch,

[46:47] aber wahrscheinlich mit sehr, sehr großem Abstand.

[46:49] Trotzdem gibt es diese verschiedenen Paradigmen und man sollte die kennen,

[46:53] gerade wenn heute in modernen Sprachen mehrere dieser Paradigmen möglich sind,

[46:57] sollte man das vielleicht einmal unterscheiden können.

[47:00] So, damit schließen wir ein Kriterium ab, nämlich das Paradigma

[47:05] und kommen hier zur nächsten Unterscheidung, und zwar Compiler- oder Interpretersprache.

[47:09] Compilersprachen funktionieren so, dass ein zusätzliches Programm,

[47:13] nämlich der Compiler, benötigt wird, um aus dem Quellcode,

[47:16] den wir da programmieren, den zu übersetzen in Maschinen- oder Bytecode

[47:20] bei vielen heutigen Plattformen wie .NET und Java zum Beispiel.

[47:23] Das heißt, ich habe immer einen Schritt dazwischen,

[47:25] zwischen Programmieren und Ausführen des Codes,

[47:27] weil es muss erst übersetzt werden vom Compiler und kann danach erst ausgeführt werden.

[47:32] Dem gegenüber steht der Interpreter.

[47:34] Der Interpreter interpretiert, deswegen heißt er so,

[47:37] den Quellcode einfach Zeile für Zeile, geht von oben nach unten durch

[47:40] und führt den einfach aus, während der den noch liest.

[47:43] Das heißt, so was wie ein Bash-Skript zum Beispiel.

[47:46] Das wird einfach von oben nach unten abgearbeitet

[47:48] und wenn du zum Beispiel in der 17. Zeile einen Fehler gemacht hast,

[47:51] dann werden erstmal alle 16 davor ausgeführt und in der 17. stürzt das Ding dann einfach ab,

[47:55] weil der Interpreter sagt so, oh, hier habe ich einen Fehler,

[47:57] aber bis dahin ist er erstmal gekommen und hat alles ausgeführt.

[48:00] Wenn du ein Java-Programm hast und das hat in Zeile 17 einen Fehler,

[48:04] dann sagt der Compiler, übersetze ich den nicht, Pech gehabt.

[48:06] Das heißt, du kannst das Ding nicht mehr ausführen.

[48:08] Das ist schon ein Unterschied bei der Programmierung.

[48:11] Der Compiler ist immer ein Schritt mehr.

[48:13] Das heißt, bei der Programmierung bist du ein bisschen langsamer.

[48:16] Dafür bist du bei der Ausführung aber schneller,

[48:18] weil das Programm halt nicht mehr interpretiert werden muss,

[48:20] sondern einfach ausgeführt werden kann.

[48:21] Das heißt auch hier wieder, Trade-Off.

[48:23] Der Compiler hat Vorteile, die gleichzeitig der Nachteil der Interpreter sind und umgekehrt.

[48:26] Das heißt, wenn ich schnell ein Ergebnis haben will,

[48:29] nehme ich den Interpreter, ich programmiere und führe das Ding sofort aus,

[48:33] ohne Kompilierschritt.

[48:34] Ich muss auch nicht auf Fehler achten.

[48:35] Wie gesagt, wenn ich ganz unten im Coden Fehler einbaue,

[48:38] wird bis dahin erstmal alles ausgeführt.

[48:40] Also deutlich einfacher bei der PureMU.

[48:42] Während der Compiler natürlich erstmal Fehler findet,

[48:44] die dann vielleicht sonst erst zur Laufzeit gefunden würden.

[48:47] Das ist natürlich auch ein schöner Vorteil bei der PureMU.

[48:50] Es gibt inzwischen auch so Zwischendinger.

[48:52] Das ist der JIT-Compiler, der Just-in-Time-Compiler.

[48:55] Insbesondere interessant auf Plattformen wie Java.

[48:58] Java wird da kompiliert zu Bytecode

[49:00] und der Bytecode wird dann von der Plattform erst ausgeführt

[49:03] und, Überraschung, dabei interpretiert.

[49:06] Weil der Bytecode ist auch nichts anderes als eine abstrakte Form von Befehlen für den Computer.

[49:11] Aber die müssen ja erst noch übersetzt werden in konkrete Maschinenbefehle

[49:15] für den ganz konkreten Prozessor, der in dem Rechner drin steckt.

[49:18] Und das übernimmt dann der Interpreter,

[49:21] der auf der JVM dann den Bytecode interpretiert.

[49:24] Und jetzt haben wir aber gerade gelernt,

[49:26] Interpreter ist aber ja langsam.

[49:27] Das heißt, er liest immer durch,

[49:28] übersetzt das quasi Zeile für Zeile in Maschinencode.

[49:32] Und das ist halt langsam.

[49:33] Und deswegen gibt es den JIT-Compiler, den Just-in-Time-Compiler,

[49:36] der findet zur Laufzeit raus,

[49:38] welcher Teil des Codes zum Beispiel besonders häufig durchlaufen wird

[49:41] und dann kompiliert er den, bevor das Ding ausgeführt wird,

[49:45] sodass nicht jedes Mal wieder jede Zeile interpretiert werden muss,

[49:48] sondern das Ding wird quasi on the fly vorkompiliert,

[49:51] damit es einfach schneller ist.

[49:52] Das heißt, ich habe dann nur noch einmal den Compile-Schritt

[49:54] und nicht jedes Mal, wenn die Zeile wieder durchlaufen wird.

[49:58] Trotzdem habe ich weiterhin eine Interpretation des Codes

[50:01] und ich habe weiterhin auch den Compile-Schritt vorher.

[50:04] Bei Java wäre es also so,

[50:05] ich schreibe meinen Quelltext, dann schmeiße ich den Compiler an.

[50:08] Einmal.

[50:09] Der erzeugt mir den Bytecode

[50:10] und der Bytecode wird jetzt von einem Interpreter

[50:12] Zeile für Zeile durchlaufen und übersetzt.

[50:14] Wenn der aber feststellt,

[50:15] dass bestimmte Codezeilen sehr häufig durchlaufen werden,

[50:18] dann kompiliert er das vor,

[50:20] sodass ich dann beim nächsten Mal

[50:21] einfach das fertige Ding wieder aufrufen kann

[50:23] und nicht die Zeile nochmal übersetzen muss.

[50:26] Das ist dann so die Kombination aus Compiler, Interpreter und JIT-Compiler.

[50:30] Und das hat man zum Beispiel bei Java,

[50:31] aber auch bei anderen Plattformen sehr häufig heute.

[50:35] Dann kommen wir jetzt zu meinem Lieblingsthema,

[50:37] was wir auch in den Fachgesprächen in den letzten Jahren ständig fragen

[50:42] und was leider immer,

[50:43] ja, immer ist nicht richtig,

[50:45] aber sehr häufig nicht gut beantwortet wird.

[50:47] Und das ist die Frage nach der Typisierung.

[50:49] Und die Typisierung hat so viel Auswirkungen

[50:51] auf unsere tägliche Programmierung,

[50:52] deswegen sollte man sich damit unbedingt beschäftigen.

[50:54] Weil das ist das, was ich mit als erstes sehe,

[50:57] wenn ich mit der Programmiersprache arbeite.

[50:59] Zum Beispiel muss ich vor meine Variablen einen Datentyp schreiben.

[51:02] Wenn ja, ist das natürlich erstmal ein gewisser Overhead,

[51:04] weil ich muss es halt da hinschreiben.

[51:06] Auf der anderen Seite gibt es mir natürlich auch eine gewisse Sicherheit,

[51:08] weil dieser Datentyp danach normalerweise nicht wieder geändert wird.

[51:11] Und ich weiß, wenn ich es als String deklariere,

[51:13] bleibt es auch ein String

[51:14] und ist nicht magischerweise auf einmal ein Integer.

[51:16] Das heißt, es gibt ganz, ganz viele konkrete, praktische Auswirkungen,

[51:20] aber auch viele Fehlerquellen,

[51:22] die durch die Typisierung entstehen bzw. verhindert werden können,

[51:25] sodass ich unbedingt empfehlen würde,

[51:27] dass du dir diese Typisierung einmal anschaust.

[51:29] Und nicht nur für deine konkrete Sprache,

[51:31] sondern auch für so ein paar allgemein bekannte Sprachen.

[51:34] PHP, Java, C Sharp, Ruby, so verbreitete Sprachen.

[51:37] Da darf man gerne wissen, wie die typisiert sind.

[51:39] Weil das für die Entwickler zumindest ein ganz zentraler Punkt ist,

[51:44] wenn ich Programmiersprachen unterscheide.

[51:46] Schauen wir uns einmal die Typisierung an.

[51:48] Die kann man auf zwei Arten unterscheiden.

[51:51] Einmal die statische und die dynamische Typisierung.

[51:53] Und davon jetzt erstmal komplett unabhängig die starke und schwache Typisierung.

[51:58] Das heißt, die beiden unterschiedlichen Klassifizierungen

[52:00] haben erstmal nichts miteinander zu tun.

[52:02] Es gibt Programmiersprachen, die für alle vier möglichen Kombinationen

[52:06] aus diesen vier Typisierungen einklassifiziert werden können.

[52:10] Das kannst du dir vorstellen,

[52:12] du hast auf der einen Achse eines Koordinatensystems

[52:14] statisch und dynamisch typisiert

[52:16] und auf der anderen Achse hast du stark und schwach.

[52:19] Und jetzt kannst du zu jeder Kombination,

[52:21] also statisch stark, statisch schwach, dynamisch stark, dynamisch schwach,

[52:26] Programmiersprachen finden, die das unterstützen.

[52:28] Das heißt, diese beiden Typisierungsformen

[52:31] haben erstmal nichts miteinander zu tun

[52:33] und die darfst du auch nicht durcheinander bringen.

[52:35] Die sagen ganz viele Prüflinge auch,

[52:37] das ist statisch typisiert, also stark typisiert.

[52:41] Stark und statisch wird dann oft durcheinander gebracht.

[52:44] Das ist nicht dasselbe.

[52:46] Statisch und dynamisch sind eine Klassifizierung

[52:48] und stark und schwach sind eine andere Klassifizierung.

[52:51] Und Programmiersprachen können dann halt

[52:53] eben aus diesen Schnittmengen eine Typisierung bestimmen.

[52:56] Fangen wir erstmal vorne an.

[52:58] Statisch und dynamisch, das ist das, was man im Code als erstes sieht.

[53:01] Denn statische Typisierung bedeutet,

[53:03] alle Datentypen stehen schon zur Compilezeit fest.

[53:07] Das heißt insbesondere alle meine Variablen,

[53:10] und das ist ganz egal, ob Instanzvariablen, lokale Variablen, Parameter,

[53:13] die haben alle einen Datentyp, der feststeht.

[53:16] Und meistens sieht man das auch, indem man das davor schreibt.

[53:19] Das heißt, da steht in Java zum Beispiel String s.

[53:22] Und dann ist die Variable s eben ein String.

[53:25] Die hat diesen fixen Datentyp String, der sich auch nicht ändert.

[53:29] In dynamischen Programmiersprachen muss ich keine Datentypen angeben.

[53:33] Das heißt nicht, dass es keine Datentypen gibt.

[53:35] Die stehen bloß nicht zur Compilezeit fest,

[53:37] sondern erst zur Laufzeit.

[53:39] Das heißt, in PHP zum Beispiel kann ich schreiben $s="Hallo".

[53:44] Dadurch wird s, die Variable s, zu einem String,

[53:48] weil halt Hallo drinsteht,

[53:50] aber das wird halt erst zur Laufzeit relevant.

[53:53] Wenn ich dann zum Beispiel mit diesem String irgendwas machen will,

[53:56] wie zum Beispiel, ich rechne den String "-3",

[53:58] dann wird die Programmiersprache sagen, Moment mal,

[54:00] String "-3", kann ich nicht, geht nicht.

[54:02] Dann gibt es einen Laufzeitfehler.

[54:04] In Java wäre das gar nicht möglich, weil der Compiler schon sieht,

[54:06] du hast hier einen String, du musst ja String hinschreiben,

[54:08] das geht ja gar nicht ohne.

[54:09] Und wenn du jetzt hier "-3", geht das nicht,

[54:11] weil String "-Integer", das knallt.

[54:14] Das heißt, aus diesen Typen leiten sich ganz, ganz viele konkrete Sachen

[54:18] für die alltägliche Programmierung ab.

[54:20] Ich kann bestimmte Dinge gar nicht machen, wenn ich statisch typisiert bin.

[54:23] In dynamischen Sprachen kann ich das machen,

[54:25] es fliegt mir aber eventuell trotzdem um die Ohren,

[54:27] und zwar erst zur Laufzeit.

[54:28] Das heißt, diese grundsätzliche Unterscheidung,

[54:31] muss ich Typen hinschreiben oder nicht?

[54:33] Das ist erstmal die klassische Unterscheidung der Typisierung,

[54:37] die man auf jeden Fall drauf haben sollte.

[54:40] Und das erkennst du sehr schnell,

[54:42] indem du siehst, ob vor den Variablen halt eben Datentypen stehen oder nicht.

[54:46] Und ich nenne mal ein paar Beispiele,

[54:48] C Sharp zum Beispiel oder Java, die sind statisch typisiert,

[54:51] da muss ich Typen angeben.

[54:52] Dynamische Programmiersprachen sind zum Beispiel Ruby oder PHP.

[54:55] PHP ist der Klassiker.

[54:56] $A, da muss ich nicht davor schreiben,

[54:58] dass es ein String, ein Integer, irgendwas ist.

[55:00] Ich mache einfach $A, dann habe ich halt eine Variabel.

[55:03] So, jetzt habe ich gerade gesagt, du siehst das daran, dass da Typen stehen.

[55:06] Das ist heutzutage nicht mehr ganz richtig,

[55:08] weil viele Programmiersprachen, und Java gehört dazu,

[55:11] haben ein Feature, das nennt sich Typ-Inferenz.

[55:13] In Java kann ich seit Java 11 schreiben,

[55:16] var s, also var, V-A-R,

[55:19] V-A-R, s, gleich Hallo.

[55:22] Das heißt, ich definiere eine Variable s mit dem Inhalt Hallo,

[55:26] und der Compiler inferiert, also er leitet ab,

[55:30] aus der rechten Seite, aus dem Hallo,

[55:32] dass das jetzt ein String sein muss,

[55:34] und danach hat meine Variable den Typ String.

[55:37] Das heißt, dieses Typ-Inferenz-Ding

[55:39] bedeutet nicht, dass meine Programmiersprache

[55:41] auf einmal dynamisch typisiert ist,

[55:42] denn es stehen ja keine Typen mehr da.

[55:44] Das heißt einfach nur,

[55:45] dass ich den Typen nicht mehr hinschreiben muss,

[55:47] weil er redundant ist.

[55:48] Denn wenn ich auf der rechten Seite

[55:49] den String Hallo hinschreibe,

[55:51] was soll dann auf der linken Seite

[55:53] die Variable für den Typ bekommen?

[55:54] Double, Int, das kann ja nicht,

[55:56] weil es muss ja ein String drin gespeichert werden können.

[55:58] Also kann der Compiler sagen,

[56:00] okay, wie wird nochmal die Zuweisung ausgewertet?

[56:02] Von rechts nach links.

[56:03] Was steht auf der rechten Seite des Gleichheitszeichens?

[56:05] Ein String.

[56:06] Dann muss auf der linken Seite

[56:08] eine Variable vom Typ String stehen.

[56:10] Was steht da?

[56:11] Ein s, davor steht ein war.

[56:13] Okay, da war er wohl zu faul,

[56:14] String hinzuschreiben,

[56:15] also mache ich das jetzt mal.

[56:16] Bei String spare ich mir zwei Buchstaben,

[56:19] oder s, t, r, ne, drei sogar,

[56:21] indem ich war schreibe statt String.

[56:23] Das ist jetzt nicht der Mega-Gewinn,

[56:24] aber wenn man sich die üblichen Business-Anwendungen anguckt,

[56:27] wo die Klassennamen irgendwie 30 Zeichen lang sind,

[56:30] dann kann man damit schon mal sehr viel Tipparbeit sparen.

[56:33] Das bedeutet aber eben nicht,

[56:34] dass meine Sprache jetzt auf einmal dynamisch typisiert ist.

[56:36] Ich kann jetzt nicht einfach in der nächsten Zeile machen,

[56:38] ach, jetzt habe ich keinen Bock mehr auf String,

[56:39] jetzt ist das s einfach ein Integer.

[56:41] So, nein, das funktioniert so nicht.

[56:43] Und das siehst du auch, wenn du in deiner IDI arbeitest

[56:45] und zum Beispiel die Maus jetzt über die Variable hältst,

[56:48] dann wird dir jede vernünftige IDI,

[56:50] Eclipse, IntelliJ, was auch immer du nutzt,

[56:51] anzeigen, dass das Ding ein String ist.

[56:53] Und es bleibt auch ein String.

[56:54] Also bitte nicht Typ-Inferenz mit dynamischer Typisierung vergleichen.

[56:58] Bitte, bitte nicht, das hat nichts miteinander zu tun.

[57:00] Typ-Inferenz ist nur syntaktischer Zucker.

[57:03] Also die Programmiersprache macht es dir einfach,

[57:06] bestimmte Dinge zu programmieren, zu schreiben,

[57:09] für die du sonst eben mehr Text brauchst.

[57:11] Und da ist das VAR, drei Buchstaben,

[57:14] halt deutlich cooler als, weiß ich nicht,

[57:17] meine tolle Autoklasse dahin zu schreiben.

[57:20] Bitte nutze nicht meine tolle Autoklasse

[57:22] als Namen für eine Klasse.

[57:23] Ja, das ist ein ganz schlechtes Beispiel.

[57:25] Mir ist bloß leider keine typische Enterprise-Klasse gerade eingefallen,

[57:27] die 30 Zeichen lang ist.

[57:29] Also, ich wiederhole es nochmal, weil es so wichtig ist.

[57:31] Statische Typisierung.

[57:32] Alle Datentypen stehen schon zur Compile-Zeit fest.

[57:35] Und das heißt, ich muss sie hinschreiben.

[57:37] Dynamisch, Datentypen werden erst zur Laufzeit geprüft.

[57:41] Das heißt, ich sehe im Code erstmal keine Datentypen

[57:43] oder ich muss sie auch nicht hinschreiben.

[57:45] Das ist der zentrale Unterschied.

[57:47] Und jetzt komme ich zur zweiten Klassifizierung.

[57:49] Das ist die starke und die schwache Typisierung.

[57:51] Und das kann man jetzt nicht so trennscharf machen

[57:53] wie statisch und dynamisch.

[57:54] Das ist eher so eine Art Spektrum.

[57:56] Also, anstatt zu sagen, die Sprache ist stark typisiert,

[58:00] ist es eher so, dass ich sage,

[58:01] sie ist etwas stärker typisiert als eine andere Sprache.

[58:04] Oder sie ist etwas schwächer typisiert.

[58:06] Das ist also nicht so schwarz-weiß,

[58:08] stark typisiert, schwach typisiert,

[58:10] sondern, ja, es ist so ein fließender Übergang

[58:12] und es gibt eben stärkere und schwächer typisierte Sprachen.

[58:16] Fangen wir aber erstmal ganz vorne an.

[58:18] Was ist überhaupt starke Typisierung?

[58:20] Stark bedeutet, dass keine Typumwandlung möglich ist.

[58:24] Das heißt, wenn eine Variable einen Typen hat,

[58:27] dann wird der nicht sich magischerweise irgendwie ändern.

[58:30] Wenn ich einen String habe,

[58:31] wird das nicht auf einmal ein Integer.

[58:33] Das hört sich erstmal logisch an,

[58:35] dass Datentypen sich nicht magischerweise ändern können.

[58:38] Aber es gibt ja in vielen Programmiersprachen

[58:40] zum Beispiel so eine Art Cast.

[58:42] Das heißt, ich kann einen Datentyp

[58:43] auf einen anderen Datentyp casten,

[58:45] den also umwandeln.

[58:47] Der Klassiker ist in Java,

[58:49] ich habe ein Double, zum Beispiel 3,5,

[58:51] und ich möchte nur den ganz zahligen Anteil haben,

[58:53] also die 3.

[58:54] Da kann ich einfach machen,

[58:55] die Java-Syntax, die ist in vielen anderen Programmiersprachen auch so,

[58:58] ich schreibe den Datentyp in runden Klammern davor

[59:01] und mache dann sowas wie,

[59:02] Klammer auf, Int, Klammer zu, 3,5.

[59:05] Und dann wird die 3,5, eigentlich ein Double,

[59:08] gecastet auf den Datentyp Int.

[59:10] Und das bedeutet,

[59:11] dass zum Beispiel ein Nachkommateil dann weggeschmissen wird.

[59:14] Und das ist schon eine Typumwandlung.

[59:16] Das heißt, in einer 100% stark typisierten Programmiersprache

[59:21] wäre das nicht erlaubt,

[59:22] weil es ist halt eine Typumwandlung.

[59:24] Typen dürfen nicht umgewandelt werden.

[59:25] Da sieht man schon,

[59:26] also eine komplett starke Typisierung ist eher selten.

[59:29] Zumindest kenne ich jetzt keine Sprache,

[59:30] wo das nicht erlaubt ist,

[59:32] ein Cast zu machen,

[59:33] aber ich kenne auch nicht alle 200 Programmiersprachen auswendig.

[59:36] Das heißt, auch wenn zum Beispiel in Java

[59:39] ein Cast möglich ist,

[59:41] also eine explizite Typumwandlung,

[59:43] explizit, weil ich es in den Code hinschreiben muss.

[59:46] Das steht in runden Klammern Int.

[59:48] Das ist explizit hingeschrieben.

[59:50] Das ist ein Cast, explizite Typumwandlung.

[59:53] Trotzdem ist Java stark typisiert.

[59:57] Warum?

[59:58] Das erkennen wir gleich,

[59:59] wenn wir uns jetzt die schwache Typisierung angucken.

[1:00:00] Denn die schwache Typisierung bedeutet,

[1:00:02] dass es implizite Typumwandlungen durch die Sprache gibt.

[1:00:05] Implizit ist immer, was ich nicht hingeschrieben habe.

[1:00:08] Explizit, runde Klammern Int,

[1:00:10] dann steht das da im Code.

[1:00:11] Ich kann das lesen.

[1:00:12] Wenn ich das dann nicht hinschreibe

[1:00:14] und die Sprache macht es einfach so,

[1:00:16] dann ist es implizit,

[1:00:17] weil ich kann es nicht sehen.

[1:00:18] Es steht da nicht.

[1:00:19] Und das funktioniert in einigen Sprachen.

[1:00:22] Und zwar ziemlich seltsam,

[1:00:24] wenn man sich bestimmte Sprachen mal anguckt.

[1:00:26] Da werden Wildtypen miteinander umgewandelt,

[1:00:28] wo man nicht unbedingt dran denkt als Entwickler.

[1:00:30] Zum Beispiel kann ich in einigen Sprachen

[1:00:32] so etwas schreiben wie if in Klammern 1.

[1:00:37] Und das war's. Aus Java kennst du das ganz sicher nicht, weil da wird ein Typfehler kommen. Denn

[1:00:43] if erwartet natürlich einen Boolchen-Ausdruck. If true, if false. Aber ich kann doch nicht so

[1:00:48] was wie if 1 schreiben. Ich kann ja auch nicht if hallo schreiben. Also was soll da rauskommen?

[1:00:53] Aber es gibt Programmiersprachen, wo dann diese Werte umgewandelt werden in einen passenden

[1:00:59] Boolchen-Wert. Zum Beispiel aus Zahlen, die nicht 0 sind, wird dann ganz oft true gemacht. Das heißt,

[1:01:07] das if in Klammern 1 ist eine kürzere Schreibweise für if in Klammern true. Denn wenn der Compiler

[1:01:13] jetzt sieht, oh, da steht eine 1, 1 ist ja gar kein Boolcher-Wert. Ja, dann versuche ich doch

[1:01:18] einfach mal, die 1 umzuwandeln in einen Boolchen-Wert. Und welcher wäre am passendsten? Ja,

[1:01:22] nehmen wir mal einfach true. So, das heißt, es gibt natürlich bestimmte Regeln dafür. Der macht

[1:01:26] das nicht einfach irgendwie random, logischerweise. Aber da gibt es zum Beispiel die Regel, und das

[1:01:29] ist tatsächlich jetzt so eine, alle Zahlen, die nicht 0 sind, werden automatisch true. Und 0 wird

[1:01:35] halt zu false. Es gibt aber noch andere Regeln. Und am wildesten ist eigentlich JavaScript. Da

[1:01:39] habe ich bei Twitter mal irgendwie so einen Tweet gesehen. Was man dort alles in true und false

[1:01:44] umwandeln kann, das ist ja völliger Wahnsinn. Also ich glaube, das war eine Matrix mit irgendwie 30

[1:01:48] Zeilen und Spalten. Völlig verrückt. Da werden dann zum Beispiel Arrays umgewandelt werden in

[1:01:53] Boolcher-Ausdrücke oder eben Strings oder nil und null und ich weiß nicht was. Also die wildesten

[1:01:58] Sachen, die man da umwandeln kann. Und das ist natürlich alles andere als gut nachvollziehbar,

[1:02:01] was da im Code steht. Ich meine, bei if 1 ist es vielleicht noch einigermaßen nachvollziehbar,

[1:02:06] aber wenn ich stattdessen eine Variable in dem if abfrage und vielleicht, weil die Sprache auch

[1:02:11] noch dynamisch typisiert ist, weiß ich gar nicht, welchen Datentyp die hat und da steht jetzt einfach

[1:02:15] ein String drin, dann wird das if vielleicht als true ausgewertet, weil ein zum Beispiel nicht

[1:02:20] leerer String als true gilt. Habe ich jetzt aber eine 3 da drin stehen, wird es auch als true

[1:02:25] ausgewertet. Habe ich jetzt eine 0 drin stehen oder einen leeren String, ist es auf einmal false.

[1:02:29] Und das ist ja jetzt nur, also so will ich normalerweise nicht programmieren. Ich will,

[1:02:33] dass das Programm nachvollziehbar ist und verständlich ist und ich möchte nicht durch

[1:02:37] solche impliziten Typumwandlungen meine Sprachkonstrukte hier unnötig verkomplizieren.

[1:02:42] Das hat aber auch Vorteile, denn diese Typprüfung ist natürlich wieder ein Hindernis. Wenn ich jetzt

[1:02:48] wirklich eine komplett stark typisierte Sprache hätte, dann könnte ich ja nicht mal aus einem

[1:02:53] Double ein Integer machen. Ich könnte nicht einfach den Nachkommanteil abschneiden, weil

[1:02:56] die Sprache sagt, sorry, das sind zwei unterschiedliche Typen, das geht nicht. Das

[1:03:00] heißt, in bestimmten Situationen ist natürlich so eine Typumwandlung auch mal ganz nett in meinem

[1:03:05] Programm, weil ich es sonst sehr umständlich programmieren muss. Das heißt, ja, ich muss

[1:03:08] mir entscheiden, was will ich? Wie immer ein Trade-off, durch die implizite Typumwandlung

[1:03:13] habe ich natürlich ganz viele Möglichkeiten, Fehler in meinen Code einzubauen, weil, das ist

[1:03:18] so der Klassiker, wenn ich den Vergleichsoperator, der in vielen Programmiersprachen das doppelte

[1:03:23] Gleichheitszeichen ist, nehme und ich schreibe zum Beispiel in PHP einen Vergleich, mache aber

[1:03:28] nur ein Gleichheitszeichen, dann habe ich da gerade keinen Vergleich programmiert, sondern eine

[1:03:32] Zuweisung, weil auch in PHP ist das einfache Gleichheitszeichen die Zuweisung. Das heißt,

[1:03:38] wenn jetzt in einer Klammer stehen würde, if $s == 1, dann würde das trotzdem ausgeführt,

[1:03:46] weil die Zuweisung hat als Ergebnis den Wert der rechten Seite der Zuweisung. Das heißt,

[1:03:53] dieses $i == 1, war das glaube ich gerade, hätte als Ergebnis eine 1 und 1 würde PHP implizit

[1:04:00] in true konvertieren. Das heißt, ich habe gerade eine Abfrage programmiert, die immer true ist,

[1:04:06] weil auf der rechten Seite 1 steht. Das ist aber natürlich nicht das, was ich erwarte, denn wenn

[1:04:10] die Variable i jetzt den Wert 3 hat und ich lasse den Debugger durchlaufen und stelle fest,

[1:04:15] da steht schon eine 3 drin und warum wird jetzt 3 gleich 1 true? Wie kann das sein? Das ist doch

[1:04:20] nicht richtig. Da kann ich stundenlang den Fehler suchen, bis ich dann irgendwann herausfinde,

[1:04:24] ich habe ein Gleichheitszeichen vergessen. Ja, das ist manchmal nicht so offensichtlich,

[1:04:28] wie es vielleicht jetzt in diesem Beispiel erscheint. Das heißt, schwache Typisierung

[1:04:32] hat gewisse Nachteile, hat natürlich auch gewisse Vorteile, weil die mir viel durchgehen lässt,

[1:04:37] sage ich mal. Aber der Nachteil ist, es ist nicht immer so einfach Fehler zu finden,

[1:04:41] wenn diese implizit Hypermalung dazwischen funkt. Von daher muss man immer wissen,

[1:04:46] was man will. Deswegen gibt es auch verschiedene Kombinationen. Es gibt viele Sprachen,

[1:04:49] die schwach typisiert sind, aber auch viele, die stark typisiert sind. Ich habe in den Shownotes

[1:04:54] zu der Episode auch ein paar Code-Beispiele aus verschiedenen Sprachen mit aufgeführt. Die

[1:04:58] brauchst du nicht alle vorlesen, kannst du dir am besten angucken. ITberufepodcast.de

[1:05:01] slash 182, da findest du das alles. Aber wir gehen mal ein paar beliebte Kombinationen durch,

[1:05:07] beziehungsweise alle Kombinationen mit ein paar beliebten PoA-Mischsprachen. Und der Klassiker

[1:05:10] ist statisch und stark. Das heißt, ich muss alle Variablen oder allen Variablen einen Datentypen

[1:05:16] geben und die werden auch nicht magischerweise einfach umgewandelt. Das ist die klassische,

[1:05:20] ich sag mal, Enterprise-Welt. Da ist zum Beispiel Java, aber auch C-Sharp einsortiert,

[1:05:25] bei statisch und stark. Bei statisch und schwach, das gibt es auch, sollte man nicht glauben. Da ist

[1:05:32] zum Beispiel C einsortiert. C ist auch statisch, ich muss allen Variablen einen Datentypen geben,

[1:05:36] aber C erlaubt so komische Sachen wie if1. Das funktioniert einfach, dann wird das umgewandelt.

[1:05:42] Dann gibt es dynamisch und stark typisierte Sprachen. Das ist zum Beispiel Ruby. In Ruby

[1:05:47] muss ich keine Datentypen benutzen, wenn ich eine Variable deklariere. Ich kann aber nicht irgendein

[1:05:51] Magic machen wie zum Beispiel if1. Da schmeißt mir der Compiler was um die Ohren und sagt,

[1:05:54] sorry, was machst du denn da? Das geht nicht, das ist kein Bool. Integer habe ich gekriegt,

[1:05:58] Bool will ich haben, das konvertiere ich dir nicht. Also dynamisch stark gibt es auch. Dann

[1:06:03] haben wir dynamisch und schwach. Das sind zum Beispiel PHP und JavaScript, die Klassiker. Da

[1:06:07] brauche ich keine Variablen oder da brauche ich keine Datentypen angeben und ich habe halt die

[1:06:12] wildesten impliziten Typ-Kommentierungen, gerade in JavaScript. Das ist völlig wahnsinnig, was da

[1:06:16] alles möglich ist. Das heißt, auf deutsch gesagt kann ich da alles mögliche machen und irgendwie

[1:06:20] funktioniert immer. Ich weiß, das ist fies. Und das heißt, wenn man sich jetzt mal anguckt in

[1:06:25] dieser Matrix, was sich halt krass gegenübersteht, ist einmal statisch und stark die guten alten

[1:06:32] Enterprise-Sprachen, wo mir der Compiler alles abnimmt, aber auch um die Ohren haut, wenn ich

[1:06:36] Fehler mache. Und komplett gegenüber habe ich dynamisch und schwach sowas wie PHP oder JavaScript,

[1:06:41] wo halt irgendwie gar nichts typisiert ist. Jetzt mal ganz hart gesagt. Und das ist schon eine ganz

[1:06:46] andere Art und Weise der Programmierung. Denn wenn ich jetzt überlege, nehmen wir mal nur die

[1:06:49] Statisch-Typisierung, der Compiler nimmt mir ganz ganz ganz viel ab, weil ich kann ganz viele

[1:06:54] Typ-Fehler nicht machen. Ich kann nicht einen String deklarieren und dem dann eine Zahl zuweisen.

[1:07:00] Das funktioniert einfach nicht. In PHP geht das aber. Das heißt, wenn ich jetzt so programmiere,

[1:07:06] dass ich dadurch auch Fehler machen kann, wie vermeide ich diese Fehler? Weil der Compiler

[1:07:09] verhindert sie nicht. Es ist ja erlaubt. Das heißt, ich muss dann in dynamischen Sprachen,

[1:07:13] und das ist so die Konsequenz, sehr sehr viel mit Unit-Tests machen, beziehungsweise einfach so mit

[1:07:18] allgemeinen Tests eben. Weil der Compiler prüft halt viele Sachen nicht, die aber in meinem

[1:07:24] Programm natürlich nicht passieren dürfen. Ich darf nicht einen String oder einen Integer addieren,

[1:07:27] da kommt Müll bei raus. Deswegen brauche ich für solche Konstellationen dann Tests, weil der

[1:07:31] Compiler es halt eben nicht verhindert, dass ich sowas mache. Dafür kann ich halt eben schnell und

[1:07:36] dreckig runterprogrammieren und bin sicherlich vielleicht auch schneller fertig mit meinem

[1:07:39] Programm als der Java-Entwickler. Die Frage ist nur, übersteht das Programm dann auch die nächsten

[1:07:42] 20 Jahre? Verstehe ich dann selber noch, was passiert ist? Und die Laufzeitfehler, die mir um

[1:07:46] die Ohren fliegen, wie behandle ich die? Also ist so eine Glaubensfrage, wie Tabs und Spaces. Der

[1:07:54] eine nimmt das, die andere nimmt das andere. Es gibt Programmiersprachen, die sich in all diesen

[1:07:59] vier Kategorien einsortieren lassen. Nimm einfach die, die für deine Problemstellung die passendste

[1:08:04] ist. Jetzt haben wir es einmal durchgekaut, welche Arten von Typisierung es gibt. Das nächste

[1:08:09] Kriterium auf meiner Liste, das ist die Syntax. Und da gibt es im Prinzip eigentlich nur zwei Arten,

[1:08:14] wie die sich unterscheiden. Und zwar kann man Sprachen einsortieren in c-ähnlich oder eben

[1:08:19] c-ähnlich. C ist ja eine sehr verbreitete und wichtige Programmiersprache und viele

[1:08:24] Programmiersprachen haben sich die Syntax dort abgeschaut. Also das, was du wahrscheinlich heute

[1:08:28] kennst, was wir jetzt schon ein paar mal hatten, if in Klammern und dann geschweifte Klammer auf

[1:08:32] und Einrückung und so weiter, das kommt alles aus c. Und sehr viele Sprachen, zum Beispiel Java

[1:08:36] und C-sharp, haben sich das da einfach abgeguckt, weil das war dann bekannt, warum was Neues ausdenken.

[1:08:41] Also entweder ist eine Sprache c-ähnlich und das bedeutet halt insbesondere diese ganzen Klammern

[1:08:45] und die Blöcke, die mit geschweiften Klammern umschlossen werden, die ganzen Schlüsselwörter,

[1:08:50] also if und for und Datentypen wie integer und double und so was. Das kommt alles aus c. Und

[1:08:58] das finden wir dann auch in vielen Sprachen eben wieder. Auf der anderen Seite gibt es Sprachen,

[1:09:01] die sich halt gedacht haben, ach, c finde ich doof, ich mache es anders. Und da habe ich dann

[1:09:05] zum Beispiel Ruby oder Python, die arbeiten halt eben nicht mit diesen Klammern, zum Beispiel mit

[1:09:10] Schlüsselwörtern wie def und end in Ruby oder indem ich halt die Einrückung mache, wie in Python.

[1:09:15] Python hat ja whitespace für die Einrückung, der auch verpflichtend ist. Das heißt, dort gehe ich

[1:09:20] ganz anders an die Struktur meines Programms ran, beziehungsweise an das, was ich da hinschreiben

[1:09:24] muss, also an die Syntax. Ja, und das war es eigentlich auch schon. Also entweder sieht die

[1:09:28] Sprache so aus wie c oder eben halt nicht. So, die komischen Geräusche, die da gerade im

[1:09:33] Hintergrund waren, das waren zwei meiner Hunde, die meinten genau jetzt während der Aufnahme hier

[1:09:36] ein bisschen Drama zu machen. Ich hoffe, die sind jetzt ruhig und das hat dich nicht zu sehr gestört.

[1:09:41] Bei der Syntax gibt es noch eine ganz krasse Alternative, und zwar grafische Programmiersprachen.

[1:09:46] Die sind nicht sehr verbreitet, aber die gibt es und die sehen natürlich dann komplett anders aus.

[1:09:50] Hast du vielleicht schon mal gesehen, so Einsteigerkurse mit Programmierungen mit grafischen

[1:09:53] Programmiersprachen wie Scratch? Da wird kein Text geschrieben, sondern wird quasi in so einer

[1:09:58] grafischen Oberfläche werden so Bausteine zusammengeklickt oder, sage ich mal, so Puzzlestücke,

[1:10:02] die dann ineinander greifen. Das ist eine grafische Programmierung, die gibt es auch und Scratch ist

[1:10:07] nicht nur ein Beispiel dafür. Ich selber arbeite mit einer Programmiersprache, die heißt Flow, die

[1:10:11] arbeitet in unserem Enterprise-Service-Bus und die muss man sich auch zusammenklicken. Das heißt,

[1:10:17] da zieht man dann zum Beispiel Pfeile, wenn Daten von A nach B fließen sollen und solche Sachen.

[1:10:21] Das ist nochmal eine Alternative, ist aber nicht sehr verbreitet. Der größte Teil der

[1:10:26] Programmiersprachen sind textuelle Programmiersprachen, die man wirklich als Text in den Computer eingeben

[1:10:30] muss. Gut, nächstes Kriterium wäre das Abstraktionsniveau der Sprache bzw. die

[1:10:37] Sprachhöhe. Und da gibt es, je nachdem wie abstrakt die Sprache ist, die erste, zweite, dritte oder

[1:10:43] vierte Generation von Sprachen. Auch hier wieder, wenn man sich so ein bisschen an der Historie von

[1:10:48] Computern und Programmiersprachen entlanghangelt, die allererste Generation von Programmiersprachen

[1:10:54] waren Maschinensprachen. Das heißt, ich habe wirklich mit Nullen und Einsen programmiert.

[1:10:59] Ich war vor kurzem noch im Computermuseum in Oldenburg, falls du in der Region wohnst,

[1:11:04] richtig cool. Da konnte man einen richtigen alten Computer sehen, den man mit Nullen und Einsen

[1:11:09] programmieren musste. Da gab es acht kleine Tasten, die jeweils für einen Bit standen. Und

[1:11:14] dann muss man die richtigen Tasten drücken und hat quasi aus acht Bits ein Byte produziert und

[1:11:19] das Byte entspricht dann einem Befehl in diesem Computer. Das heißt, ich musste wirklich wissen,

[1:11:23] welche Nullen und Einsen stehen für welchen Befehl und das habe ich dann dort programmiert. Das heißt,

[1:11:29] da ist nichts mit For und If und While, sondern Nullen und Einsen programmiere ich da. Also

[1:11:33] wirklich direkt hart an der Maschine dran. Und das ist die Programmiersprache der ersten

[1:11:38] Generation, die 1GL, die First Generational Language, 1GL abgekürzt, Maschinensprache.

[1:11:46] Irgendwann hat man dann gesehen, so Nullen und Einsen ist ja super, aber wenn ich jetzt drei

[1:11:49] verschiedene Prozessoren habe, die alle unterschiedliche Befehle haben, dann muss

[1:11:52] ich ja dreimal das gleiche programmieren in unterschiedlichen Sprachen. Das ist ziemlich

[1:11:57] ja Overhead und das rafft dann irgendwann keiner mehr. Und dann hat man das erste

[1:12:01] Abstellationsniveau eingeführt, die 2GL-Sprache, also Second Generational Language. Und das ist

[1:12:07] dann quasi Assembler. Hast du vielleicht auch schon mal irgendwo gesehen. Ist etwas abstrakter,

[1:12:11] sehr kurze, sehr kryptische Befehle, so MV, um irgendwas zu verschieben oder JP,

[1:12:18] um irgendwo hin zu jumpen und solche Sachen. Also sehr kurze, knackige Befehle. Besser als

[1:12:24] Nullen und Einsen, keine Frage, aber immer noch sehr, sehr, sehr dicht an der Hardware und halt

[1:12:28] sehr kryptisch, weil die Befehle sehr kurz sind und immer noch an bestimmte Prozessoren gebunden,

[1:12:33] außerdem auch noch. Das heißt, es ist ein bisschen abstrakter als Maschinencode,

[1:12:37] aber jetzt auch nicht so der richtig große Wurf. Trotzdem hat man jahrelang auch damit

[1:12:41] programmiert und sogar heute programmiert man teilweise noch damit, zum Beispiel bei

[1:12:44] Spielen, bei Computerspielen, die das letzte aus der Performance rauskitzeln müssen. Da

[1:12:48] wird immer noch mit Assembler gearbeitet, weil dichter am Prozessor kannst du nicht

[1:12:53] programmieren als mit Assembler. Also es ist immer noch nicht tot, es gibt es immer noch.

[1:12:56] Ja, und dann kommen wir aber irgendwann zur dritten Generation, der Third Generation Language

[1:13:01] und das sind die modernen Hochsprachen, nennt man sie auch, wie C, Java, C-Sharp, Ruby, Python,

[1:13:07] PHP. Also vermutlich alles das, was du im Alltag benutzt, wird eine 3GL-Sprache sein. Das sind die

[1:13:13] modernen Sprachen mit for, while, if. Ja, wir haben vorhin gelernt, nicht jede Sprache hat das. Okay,

[1:13:19] aber du weißt, was ich sagen will. Also du kannst den Code lesen und ihn auch verstehen und musst

[1:13:23] nicht noch in einem Lexikon nachgucken, was die Befehle heißen. Ich glaube, das ist so das,

[1:13:29] was hier gemeint ist. So, jetzt gibt es aber auch sogar noch eine noch abstraktere Sprachgruppe und

[1:13:35] das ist dann die 4GL, die Fourth Generation Languages und das sind dann Sprachen, die einen

[1:13:40] Fokus auf einem bestimmten Anwendungsbereich haben, zum Beispiel SQL. SQL hat als Ziel,

[1:13:46] Datenbank abzufragen und zwar relationale Datenbanken. Das heißt, damit kann ich nicht

[1:13:50] einfach irgendwie ein Programm programmieren, kann ich ja sowieso nicht, weil SQL ist ja nicht

[1:13:53] Turing-Complete, das hatten wir schon, aber ich kann damit eben nur dieses eine machen,

[1:13:57] nämlich Datenbank abfragen. Dafür ist die aber sehr abstrakt. Wir hatten ja vorhin schon gelernt,

[1:14:02] die ist auch deklarativ. Ich sage ja, was ich am Ende haben will. Das heißt, ich kann mit SQL

[1:14:08] gar nicht imperativ programmieren, aber ich muss es auch nicht. Ich sage einfach, was ich haben will

[1:14:11] und dann liefert mir die Datenbank das. In einer 3GL-Sprache müsste ich das halt bis ins Feinste

[1:14:17] ausimplementieren. Die 4GL-Sprache, SQL, ist darauf optimiert, relationale Datenbanken abzufragen. Das

[1:14:23] heißt, das kann die super gut und ich kann ganz, ganz wenig Code schreiben, ein Select Statement und

[1:14:28] da kommt sofort die Tabelle zurück, die ich haben will und muss das eben nicht mit 27 Zeilen in

[1:14:33] Java ausprogrammieren. Das heißt, sie sind super gut geeignet für einen bestimmten Anwendungsbereich,

[1:14:37] aber sobald ich diesen Anwendungsbereich verlasse, kann ich halt nichts mehr damit anfangen. Also

[1:14:41] SQL, Datenbanken, super, aber sonst kann ich halt nichts damit machen. Es gibt noch andere

[1:14:47] 4GL-Sprachen. Das Ziel ist meistens, abstrakter zu werden und das heißt eigentlich fast immer,

[1:14:53] dass ich weniger Code brauche, um zum gleichen Ergebnis zu kommen wie in einer 3GL-Sprache. Da

[1:14:58] gibt es zum Beispiel noch die Sprachen Natural, damit arbeiten wir tatsächlich in der Versicherung

[1:15:02] und ABAP, hast du vielleicht schon mal gehört, eine Programmier-Sprache von SAP, in der auch

[1:15:07] jahrelang SAP halt eben programmiert wurde und die ist auch eine 4GL-Sprache. Natural und ABAP

[1:15:12] sind nämlich darauf ausgelegt, die üblichen Business-Anwendungen, die wir so brauchen,

[1:15:16] nämlich Datenbankzugriff, Datensätze ausgeben, ändern, löschen, tralala, das können diese

[1:15:21] Sprachen mit ganz, ganz wenigen Befehlen. Ich selber habe viele Natural entwickelt,

[1:15:24] das heißt, wenn ich da in Natural eine Adabas-Tabelle lesen möchte, Adabas ist eine Datenbank, die mit

[1:15:30] Natural gut zusammenarbeitet, dann ist das eine Zeile Code. Da schreibe ich einfach read

[1:15:34] Tabellenname und dann ist das fertig und da läuft das Ding einfach die ganze Tabelle durch. Wenn ich

[1:15:39] das in Java programmieren würde, da bräuchte ich erstmal einen Datenbank-Connection-Objekt,

[1:15:43] da müsste ich wahrscheinlich ein Statement formulieren, dann muss das irgendwie 37 mal

[1:15:48] kombiniert werden und irgendwelche Parameter noch reingebaut werden. Da brauche ich irgendwie 27

[1:15:52] Zeilen, um diese Tabelle zu durchlaufen und in Natural ist das halt eine Zeile Code. Dafür

[1:15:57] kann ich halt auch überhaupt nicht bestimmen, wie diese Tabelle ausgelesen wird und so weiter.

[1:16:01] Also die Kontrolle über das, was der Computer eigentlich macht, geht mir dadurch natürlich

[1:16:05] ein bisschen verloren. Es ist halt abstrakter. Genauso wie ich halt in 3GL nicht mehr so

[1:16:10] hardware-nah programmieren kann, wie ein Assembler in 2GL. Das heißt, ich gewinne

[1:16:15] immer etwas, nämlich meistens Produktivität. Ich brauche weniger Code, um zum gleichen Ziel zu

[1:16:20] kommen, aber ich verliere auch ein wenig die Kontrolle, weil ich muss mich darauf verlassen,

[1:16:24] dass die Programmiersprache das schon irgendwie richtig machen wird. Ich habe weniger Möglichkeiten,

[1:16:28] einzugreifen. Also 1GL, Maschinensprache, 2GL, Assembler, 3GL sind unsere heutigen

[1:16:35] Programmiersprachen und 4GL sind so Nischensprachen, die noch abstrakter sind,

[1:16:39] in der Realität aber eigentlich kaum vertreten. Eigentlich arbeiten fast alle Entwickler und

[1:16:44] Entwicklerinnen heute mit 3GL-Sprachen. So, das nächste Kriterium wäre General Purpose

[1:16:51] vs. Domain-Specific. Das heißt, es gibt GPL-Sprachen, General Purpose Language,

[1:16:58] aber es gibt auch DSL, Domain-Specific Languages. Was ist hier der Unterschied? Erstmal vorweg,

[1:17:05] die meisten Sprachen, die du kennst, sind General Purpose Languages. Das bedeutet,

[1:17:09] General Purpose, allgemeingültiger Zweck. Ich kann mit den Dingern alles programmieren,

[1:17:14] was ich als Algorithmus formulieren kann, beziehungsweise ich kann damit eine Web-Anwendung

[1:17:18] bauen oder eine Konsolen-Anwendung, also irgendwas. Ich kann irgendein Problem damit lösen. Das sind

[1:17:24] so ziemlich alle Sprachen, die du kennst, PHP, Java, C-Sharp, so alle, die ich heute aufgeführt

[1:17:28] habe, sind eigentlich GPL-Sprachen. Es gibt aber auch Domain-Specific, also domänen-spezifische

[1:17:35] Sprachen. Die Abkürzung DSL kennst du aus dem IT-Umfeld halt vielleicht auch, falls du nicht

[1:17:40] schon Glasfaser hast. Da musst du ein bisschen aufpassen. Hier in diesem Fall heißt DSL eben

[1:17:44] Domain-Specific Language und das ist eine Programmiersprache, die für einen konkreten

[1:17:48] Zweck oder eine Domäne, einen genau abgegrenzten Bereich definiert wurde. Man könnte also sagen,

[1:17:54] SQL ist zum Beispiel auch eine DSL, weil die ist halt nur für relationale Datenbanken definiert

[1:18:00] worden. Ich kann damit halt keine Web-Anwendung programmieren. Das kann ich mit der Sprache

[1:18:04] halt eben nicht. Die ist nicht dafür da. Dafür habe ich aber, ich sag mal, eine Art perfekte

[1:18:10] Syntax für die Probleme, die ich lösen will. Select Sternchen from Kunde. Das ist die perfekte

[1:18:15] Syntax, weil das ist eine Zeile Code und es wird mir die ganze Tabelle sofort ausgegeben. Wenn ich

[1:18:20] das mit einer GPL programmiere, wie ich eben in einem anderen Beispiel schon hatte, brauche ich

[1:18:23] halt vielleicht 27 Zeilen Code, weil die dafür halt eben nicht vorgesehen ist, für diesen konkreten

[1:18:29] Anwendungsfall. Dafür kann ich mit Java halt noch andere Sachen machen, außer relationale

[1:18:33] Datenbanken abfragen. Also, man muss immer gucken, kann ich mit der Programmiersprache alles Mögliche

[1:18:38] programmieren, dann ist es eine GPL oder ist sie nur für einen speziellen Aufgabenbereich vorgesehen,

[1:18:43] wie zum Beispiel SQL, dann ist es halt eben eine DSL, eine Domain-Specific-Language. Es gibt,

[1:18:49] wenn man das noch etwas näher unterscheiden möchte, bei der DSL noch zwei Untergruppen,

[1:18:54] nämlich einmal eine interne DSL und eine externe DSL. Eine interne DSL kannst du dir quasi selber

[1:19:00] bauen. Du könntest, wenn du dein Programm programmierst mit Java zum Beispiel, deine APIs

[1:19:04] so gestalten, dass sie fachlich sehr dicht an dieser Domäne sind, sodass du Domänenprobleme

[1:19:10] sehr gut damit programmieren kannst. Dann hättest du dir quasi in deiner Programmiersprache Java

[1:19:15] eine Art eigene fachliche API gebaut. Das wäre eine interne DSL. Es gibt aber auch externe DSLs

[1:19:24] und das sind wirklich komplett eigene Programmiersprachen mit eigenem Compiler, mit eigener

[1:19:27] Syntax, wie zum Beispiel SQL. Hat jetzt keinen Compiler, okay, aber eine komplett eigene Syntax.

[1:19:33] Das heißt, dieses Select-Sternchen from und so was, das ist eine komplett eigene Sprache und das

[1:19:39] ist eine externe DSL. So, dann kommen wir zum letzten Punkt. Ich habe jetzt alle großen durch,

[1:19:46] jetzt habe ich eigentlich nur noch so was wie weitere Unterscheidungsmöglichkeiten. Die kann

[1:19:49] man auch anführen bei bestimmten Sprachen, wenn man die erklären will, kann man tatsächlich mal

[1:19:52] einen Satz dazu sagen, aber ja, das geht vielleicht nicht unbedingt für alle Programmiersprachen. Ich

[1:19:56] habe es mal mit aufgeführt, kurz und knackig gehen wir die Sachen mal durch. Zum einen kann

[1:20:00] ich gucken, wie portable die Programmiersprache ist. Ist sie zum Beispiel sehr, sehr, sehr hardware-nah

[1:20:05] wie C oder ist es eine virtuelle Maschine dazwischen, wie bei Java oder C-Sharp. Je nachdem,

[1:20:10] was ich erreichen will, wenn ich eine Waschmaschine programmiere, dann nehme ich halt die hardware-nahe

[1:20:14] Programmierung, habe dann aber vielleicht auch sehr viel Friemelei, weil ich muss halt extrem

[1:20:18] dicht an der Hardware programmieren. Habe ich halt eine ganz allgemeine Web-Anwendung zum Beispiel

[1:20:23] und es ist mir auch egal, ob die auf Windows, auf Linux läuft oder sonst wo und ich muss die

[1:20:27] von einem Server zum anderen transportieren, dann nehme ich vielleicht eine Abstraktion dazwischen

[1:20:31] mit einer virtuellen Maschine, also zum Beispiel Java oder C-Sharp. Je nachdem, was ich brauche,

[1:20:34] eine virtuelle Maschine ist immer ein Overhead, das heißt, die muss per Definition langsamer sein

[1:20:38] als eine hardware-nahe Sprache. Meine Waschmaschine wird wahrscheinlich hardware-nah auch programmiert,

[1:20:43] damit sie schnell reagiert, wenn zum Beispiel die Trommel raushüpft oder was auch immer. Da

[1:20:48] will ich vielleicht nicht nur den Overhead einer virtuellen Maschine haben.

[1:20:50] Okay, ehrlich gesagt, virtuelle Maschinen, insbesondere Java, sind heutzutage so optimiert,

[1:20:56] dass gewisse Programme in gewissen Konstellationen sogar schneller laufen als in C programmierte

[1:21:01] Sachen. Aber wie gesagt, es kommt immer auf das konkrete Szenario an. Pauschale Aussagen sind

[1:21:07] immer, immer schwierig. Was man auch noch unterscheiden kann, ist, ob die Sprache managed

[1:21:12] oder unmanaged ist. Hier bezieht sich das auf den Speicher, auf den Arbeitsspeicher. Wird der

[1:21:17] Arbeitsspeicher von der Sprache verwaltet, also gemanaged, oder nicht? Was bedeutet das?

[1:21:22] Manuelle Speicherverwaltung hat zum Beispiel wieder C. In C, wenn ich mir da Speicher hole,

[1:21:28] weil ich ihn zum Beispiel für eine Variable brauche, dann muss ich diesen Speicher selber

[1:21:32] auch wieder freigeben, wenn ich die Variable nicht mehr brauche. Wenn ich das nicht mache,

[1:21:36] dann bleibt der Speicher belegt und wenn das Programm länger läuft und ich reserviere mir

[1:21:39] da ständig Speicher, um mir den freizugeben, dann ist einfach irgendwann der Speicher voll

[1:21:43] und dann macht der Rechner die Grätsche. Das heißt, das ist vielleicht nicht so gut.

[1:21:47] Deswegen haben ganz, ganz viele Sprachen und wahrscheinlich auch die meisten, die du einsetzt,

[1:21:52] namentlich Java, C Sharp, PHP, etc. gar nicht die Möglichkeit, manuell auf den Speicher zuzugreifen.

[1:21:58] Ja, ich kann zum Beispiel nicht einfach sagen, reserviere den Speicher und gib den wieder frei.

[1:22:01] Der Klassiker in C wäre da der Befehl free. Mit free kann man Memory wieder freigeben. Ja,

[1:22:08] das muss man aber auch tun, wenn man das nicht macht, weil man zum Beispiel eine falsche

[1:22:11] Fehlerbehandlung macht. Ich habe eine Variable deklariert und dann tritt ein Fehler auf und ich

[1:22:15] vergesse bei der Fehlerbehandlung, die Variable wieder freizugeben. Das kann man relativ schnell

[1:22:20] reinprogrammieren, so ein Fehler. Dann habe ich einen Speicher-Lag, weil der Speicher immer ansteigt

[1:22:24] und sich nicht selber wieder freigibt. Während bei Sprachen wie Java oder C Sharp, da habe ich

[1:22:29] einen sogenannten Garbage-Collector, der die ganze Zeit im Hintergrund guckt, ob er Variablen

[1:22:33] vielleicht wieder freigeben kann. Das sind nicht Variablen, sondern Speicherbereiche. Wie funktioniert

[1:22:37] das? Ganz einfach gemacht, das kann ich jetzt hier nicht in ein paar Minuten erklären. Angenommen,

[1:22:41] ich habe eine Variable deklariert und dort zum Beispiel einen Wert im Speicher abgelegt. Der

[1:22:46] Garbage-Collector prüft jetzt, ob es irgendwo noch eine Referenz auf diesen Wert gibt. Also,

[1:22:51] wenn ich zum Beispiel die Variable a deklariert habe, die auf den Speicher zeigt, und das ist

[1:22:56] eine lokale Variable, die nur in einer Methode definiert ist, und die Methode wird beendet,

[1:23:01] dann gibt es diese Referenz a nicht mehr, weil der Scope der Variablen verlassen wird,

[1:23:05] wenn die Methode endet. Das heißt, auf diesem Speicherbereich zeigt keine Variable mehr,

[1:23:10] weil die Variable a abgeräumt wird, wenn die Methode beendet wird. Das erkennt der

[1:23:15] Garbage-Collector und sieht, ich habe hier was im Speicher stehen, da zeigt aber keiner mehr drauf.

[1:23:18] Und wenn darauf keiner zeigt, dann wird es auch wohl keiner mehr benutzen, weil es kommt ja keiner

[1:23:23] mehr hin. Und dann erkennt er, dass er diesen Speicher abräumen kann, und dann wird halt der

[1:23:27] Speicher von alleine geleert. Das kannst du dir aber vorstellen, muss ja auch irgendwie ermittelt

[1:23:32] werden. Das ist nicht umsonst zu haben. Deswegen braucht der Garbage-Collector auch Laufzeit. Der

[1:23:38] Garbage-Collector, das kannst du dir so vorstellen, unterbricht zu bestimmten Zeiten dein Programm,

[1:23:43] guckt kurz im Speicher, ob noch alles referenziert wird, und wenn nein, räumt er das ab und erst

[1:23:48] danach läuft dein Programm weiter. Da reden wir von Millisekunden, aber immerhin wird dein

[1:23:54] Programm angehalten, während der Garbage-Collector läuft. Und wenn du sehr großen Speicher hast und

[1:23:59] einen sehr schlechten Garbage-Collector, dann merkt man das halt doch. Dann bleibt dein Programm

[1:24:03] wirklich stehen für ein paar, im schlimmsten Fall Sekunden. Und das ist vielleicht nicht so gut,

[1:24:07] wenn du gerade eine Maschinensteuerung programmierst, wo die Maschine dem Mitarbeiter die Hand einquetscht,

[1:24:12] wenn nicht rechtzeitig das Ding anhält. Das heißt, in solchen Fällen nimmst du vielleicht

[1:24:18] doch besser eine Sprache, die keinen Garbage-Collector hat, weil da ist zum Beispiel für Echtzeitsysteme,

[1:24:23] also gerade für technische Steuerung, stell dir mal vor, du fährst mit einem selbstfahrenden Auto

[1:24:26] und vor dir läuft ein Kind auf die Straße, aber gerade läuft während der Berechnung der

[1:24:31] Abstandskontrolle der Garbage-Collector. Und da wird einfach mal kurz angehalten. Oh, das Kind kann

[1:24:35] ich gerade nicht erkennen, denn ich muss noch ein paar Variablen aufräumen. Das wird, glaube ich,

[1:24:39] in der Realität nicht so gut ankommen. Deswegen sollte man da vielleicht nicht mit gemanagten

[1:24:44] Sprachen arbeiten, sondern mit angemanagten. Dann sollte man natürlich gut darauf gucken,

[1:24:48] dass man keine Fehler einbaut und das alles immer sauber aufräumt, klar. Dafür habe ich aber hier

[1:24:52] wieder die volle Kontrolle und kann eben auch das Programm dauerhaft laufen lassen, ohne dass der

[1:24:58] Garbage-Collector mit dazwischen funkt. Auf der anderen Seite, ich sage jetzt einfach mal in einer

[1:25:03] ausgedachten Zahl, 95 Prozent der Anwendungen, die wir halt meist so bauen, wenn wir nicht gerade für

[1:25:07] einen Autohersteller arbeiten, ist es völlig egal, ob die Anwendung mal für drei Millisekunden

[1:25:12] angehalten wird, weil da Variablen abgeräumt werden müssen. Das interessiert keinen Menschen,

[1:25:16] weil der HTTP-Request, den ich gerade ausgelöst habe, dauert schon drei Sekunden, also irgendwie

[1:25:21] drei Milliarden mal so lange wie die Prüfung des Garbage-Collectors. Okay, drei Milliarden war

[1:25:26] übertrieben, es sind nur ein paar tausend, aber trotzdem, du weißt, worauf ich hinaus will. Also

[1:25:30] es ist völlig irrelevant, ob unser Programm mal für drei Millisekunden nichts macht, weil der

[1:25:34] Garbage-Collector läuft. Also, wenn du nicht gerade Echtzeitsysteme programmierst, wirst du ein

[1:25:38] Gutes daran tun, Garbage-Collector-Sprachen zu benutzen, weil du willst nicht diese Fehlerquellen

[1:25:43] in deinem Programm haben, dass du irgendwo vergisst, einen Speicher wieder freizugeben. Das kann der

[1:25:47] Garbage-Collector für dich machen oder soll er auch machen, wie gesagt, außer du programmierst

[1:25:52] irgendwas fürs Auto oder so. Ja, und letzter Punkt der allgemeinen Unterscheidungsmöglichkeiten,

[1:25:56] die Performance, beziehungsweise der Speicherverbrauch. Durch die, ja, oft durch eine

[1:26:02] Kombination der verschiedenen Eigenschaften, die wir jetzt hier kennengelernt haben, ergibt sich

[1:26:06] eine unterschiedliche Performance, beziehungsweise unterschiedlicher Speicherverbrauch der einzelnen

[1:26:10] PoAmir-Sprachen. Zum Beispiel, jetzt statisch typisierte PoAmir-Sprachen, da muss halt zur

[1:26:15] Laufzeit nicht geprüft werden, welcher Datentyp gerade vorliegt. Das hat halt der Compiler alles

[1:26:20] schon vorher gemacht. Das heißt, die werden bei der Ausführung einfach schneller sein, weil bestimmte

[1:26:24] Prüfungen einfach nicht mehr gemacht werden müssen, weil die wurden ja schon vorher gemacht

[1:26:27] durch den Compiler. Auf der anderen Seite kannst du da vielleicht schneller programmieren mit

[1:26:32] dynamischen Sprachen, weil du halt nicht auf die ganzen Typen immer achten musst. Also es kommt

[1:26:36] halt immer darauf an, aber auch Performance wirklich bei der Ausführung unterscheidet sich,

[1:26:40] je nachdem, was für eine PoAmir-Sprache ich habe. Wenn ich zum Beispiel dynamische Typisierung habe,

[1:26:44] wie gesagt, gerade keine Typprüfung zur Compile-Zeit, aber eben zur Laufzeit, wird es halt langsamer.

[1:26:50] Wenn ich eine Interpretersprache habe, muss langsamer sein, weil es wird ja erst zur Laufzeit

[1:26:53] interpretiert, kompiliert, ausgeführt. Bei Compilersprachen ist das alles schon fertig

[1:26:57] und es wird einfach sofort ausgeführt. Also das kann alles Auswirkungen darauf haben. Außerdem,

[1:27:02] wenn wir eine Managed-Sprache haben, wie gerade beschrieben, dann läuft da halt die ganze Zeit

[1:27:05] ein Garbage-Collector mit, der ja auch irgendwie Laufzeit frisst und auch Speicher frisst offensichtlich,

[1:27:10] weil der läuft ja nicht umsonst irgendwo. Also sowas muss man dann berücksichtigen,

[1:27:14] wenn man solche Anforderungen hat. Ich sag mal, für die üblichen Business-Anwendungen oder

[1:27:18] Web-Anwendungen oder sowas, da wird das wahrscheinlich niemanden interessieren,

[1:27:21] ob da ein Garbage-Collector mitläuft oder nicht, weil wir merken das gar nicht. Weil es gibt ganz

[1:27:25] viele andere Sachen, die viel, viel länger dauern, die viel, viel mehr Performance fressen,

[1:27:29] als der Garbage-Collector, der im Hintergrund läuft. Und die Dinger sind ja auch komplett

[1:27:33] optimiert. Da hat sich nicht einfach irgendwer hingesetzt, ja, wir machen jetzt mal eine

[1:27:37] Vorschleife über alle Variablen und gucken, ob da noch Referenz… Also das sind hoch optimierte

[1:27:42] Konstrukte, die da laufen. Das heißt, das kriegen wir in normalen Umgebungen eigentlich gar nicht

[1:27:46] mit, dass die da sind. Aber wenn du halt in einer besonderen Umgebung bist, Stichwort Echtzeit-Umgebung,

[1:27:51] ja, dann geht das halt vielleicht nicht, weil du halt solche, und wenn es auch nur Millisekunden

[1:27:56] sind, Aussätze hast. Und in diesen Aussätzen könnte halt, ja, weiß ich nicht, die Stanze halt

[1:28:00] schon zugestanzt haben, wenn die menschliche Hand dazwischen ist. Und das ist eine schlechte Idee.

[1:28:05] Also muss man berücksichtigen, aber sicherlich nicht bei jedem Projekt, sondern nur in besonderen

[1:28:10] Konstellationen. Gut, zum Abschluss. Ich glaube, es reicht jetzt auch für heute. Ja,

[1:28:15] haben wir noch mal ein paar Beispiele mitgebracht für Poamir-Sprachen. Wichtig,

[1:28:19] die Liste ist nicht vollständig. Bitte schreibt mir keine Mail mit, du hast aber Poamir-Sprache

[1:28:23] Y vergessen. Das ist mir völlig klar. Ich habe nur ein paar Beispiele mitgebracht,

[1:28:27] damit du mal welche gehört hast. Die ist nicht vollständig, diese Liste, ja. Fangen wir oben an.

[1:28:31] Web-Sprachen, die wir häufig im Internet sehen. PHP, sehr verbreitet, viel Unterstützung für

[1:28:38] übliche Anforderungen, zum Beispiel super easy auf den Query-String der URL zugreifen etc. Also

[1:28:43] mit wenig Code kriege ich da eine lauffähige Web-Applikation hin. Ruby, eine super Poamir-Sprache

[1:28:49] mit ganz, ganz toller Syntax und ganz vielen coolen Features. Und mit Ruby on Rails als

[1:28:53] Web-Framework auch sehr cool, um schnell super gute, stabile Prototypen für Websites zum Beispiel

[1:29:00] zu bauen. Python kennen wir heutzutage auch aus dem KI-Umfeld, auch eine dynamische und

[1:29:05] Skript-Sprache, die auch aus dem Web eigentlich oder auch fürs Web gemacht wurde, weiß ich nicht,

[1:29:10] aber da auch eingesetzt wurde. Heutzutage eher weniger im Web, aber dafür eher im KI-Umfeld

[1:29:14] verbreitet. JavaScript, die einzige Poamir-Sprache, die überhaupt im Frontend läuft. Abgesehen von

[1:29:19] WebAssembly, aber das dauert noch, bis sich das durchgesetzt hat. Das heißt, da kommen wir gar

[1:29:22] nicht dran vorbei, wenn du irgendwas im Frontend machen willst. TypeScript als Aufsatz auf

[1:29:27] JavaScript. TypeScript kompiliert zu JavaScript, weil der Browser ja nur JavaScript ausführen

[1:29:32] kann. Und TypeScript ist eine statisch typisierte Alternative zu JavaScript. Das heißt, du hast alle

[1:29:37] Vorteile der statischen Typisierung. Das kompiliert, beziehungsweise eigentlich nennt man das transpiliert

[1:29:42] zu JavaScript, weil es kompiliert ja nicht zu Bytecode oder zu Maschinencode, sondern in eine

[1:29:47] andere Poamir-Sprache. Deswegen trans, also von der einen Poamir-Sprache in die andere Poamir-Sprache.

[1:29:51] Also TypeScript transpiliert zu JavaScript, weil JavaScript halt eben so dominant ist, aber eben

[1:29:58] durch die schwache und dynamische Typisierung auch ein paar Nachteile hat, gerade in großen

[1:30:02] Projekten. Denn gerade in großen Enterprise-Projekten, da wünschen wir uns doch sehr

[1:30:08] schnell dann auch die statische Typisierung zurück, damit wir halt diese ganzen Typfehler

[1:30:11] nicht machen können, für die wir dann ja Tests schreiben müssen. Und das bezahlt uns dann halt

[1:30:15] keiner. Das ist immer schwierig. Dann haben wir so die klassischen Enterprise-Sprachen, also das,

[1:30:20] was so in Unternehmen eingesetzt wird, in vielen zumindest. Java ist sicherlich die dominante

[1:30:25] Enterprise-Sprache, riesen Ökosystem, super langlebig. Also man kann heute noch Code ausführen,

[1:30:30] der vor 20 Jahren programmiert wurde mit der Sprache. Ich habe eine hohe Abwägskompatibilität,

[1:30:33] die ist super performant. Also dieses Vorurteil, was es vielleicht noch vor zehn Jahren gab,

[1:30:39] Java ist langsam überhaupt nicht mehr so. Die JVM ist super optimiert inzwischen. Es gibt den JIT-

[1:30:44] Compiler, es gibt superschnelle Garbage-Collector. Also Java ist top Enterprise. Da braucht auch

[1:30:50] keiner sagen, dass es irgendwie veraltet ist oder irgendwas. Die Sprache entwickelt sich aktuell auch

[1:30:54] sehr rasant weiter. Jedes halbe Jahr gibt es ein neues Release. Das heißt, da kann auch keiner

[1:30:58] mehr sagen, alter Features. Java ist immer noch super top-notch und sehr gefragt in der Ausbildung,

[1:31:03] Studium und auch in der Industrie. Sicherlich auch stärker werdend ist C-Sharp, wenn ich halt im

[1:31:09] Windows-Umfeld arbeite. Wenn ich halt die klassischen Windows-Anwendungen mit der Ribbon

[1:31:14] oben machen will, wie so ein Office-Produkt oder so, dann nehme ich halt C-Sharp, weil da ist das

[1:31:18] halt alles eingebaut. Mit Java muss ich mir da halt irgendwie was zurechtzimmern. Außerdem

[1:31:23] natürlich auch eine super gute Sprache, viele moderne Features drin, sehr innovativ, sag ich

[1:31:28] mal, und einfach eine tolle Sprache auf jeden Fall. Wir haben im Enterprise aber auch noch die guten

[1:31:34] alten Sprachen von früher, zum Beispiel Cobol. Eine 4GL-Sprache für klassische Business-Anwendungen,

[1:31:39] die heutzutage immer noch in x-Millionen Unternehmen weltweit im Einsatz ist, insbesondere

[1:31:44] bei Banken und Versicherungen immer noch. Also die ist nicht tot zu kriegen. Will aber auch kein

[1:31:49] jünger oder jüngere Entwickler mehr programmieren. Dann haben wir noch ABAP,

[1:31:55] Programmier-Sprache von SAP. SAP ist halt einfach so dominant am Markt. Jedes Unternehmen gefühlt

[1:32:00] hat ja SAP im Einsatz. Da kommt man dann an ABAP nicht vorbei, auch wenn man inzwischen auch viel

[1:32:03] mit Java machen kann. Was es aber auch noch gibt im Enterprise, das sollte man auch nicht vergessen,

[1:32:07] ist VBA, Visual Basic for Applications. Das ist die Makrosprache von Microsoft Office. Das heißt,

[1:32:13] der klassische, also das klassische Excel-Makro, das ist VBA. Das muss auch irgendwer programmieren.

[1:32:19] Das ist auch immer noch sehr verbreitet. Dann für Apps haben wir natürlich heute Kotlin,

[1:32:23] wenn du auf Android entwickelst, und Swift, wenn du auf iOS entwickelst. Swift ist so der

[1:32:28] Nachfolger von Objective-C. Hat auch viele coole neue Features bekommen. Kotlin sowieso hat auch

[1:32:33] richtig, richtig gute Sachen drin. Das ist das, was man im App-Umfeld vielleicht wiederfinden

[1:32:38] würde. Wenn man jetzt nicht Cross-Platform irgendwie was entwickelt, da hat man noch

[1:32:40] andere Sprachen. Da will ich nicht ohne drauf eingehen. Dann, wenn du Hardware nah entwickelst,

[1:32:45] kommst du um Assembler nicht drum rum, bei der Spieleentwicklung zum Beispiel. Aber das ist

[1:32:48] ein sehr nischiges Produkt. Das werden nicht die meisten Entwickler da draußen machen. Wir haben

[1:32:53] natürlich immer noch viel auf C und den Objektorientierten Aufsatz auf C natürlich C++.

[1:32:58] Das heißt, wenn ich Hardware nah, aber trotzdem Objektorientiert und coole Sachen machen will,

[1:33:02] dann nehme ich halt C++. Und auch C++ ist inzwischen echt super modern. Also,

[1:33:06] die haben ganz viele coole Features, die es auch in anderen Sprachen gibt inzwischen. Das ist also

[1:33:11] auch alles andere als Altbacken. Es hat halt bloß viele, ich sage jetzt nicht diese Altlasten aus

[1:33:16] C, weil es ist ja bewusst, zum Beispiel Memory Management und so, dass ich das da machen muss,

[1:33:19] weil ich ja zum Beispiel Echtzeitsysteme oder auch Betriebssysteme damit programmiere. Aber

[1:33:25] es sind viele auch moderne Sprachfeatures dazugekommen, sodass ich also nicht mehr sagen

[1:33:30] kann, blöd, sondern es gibt auch viel cooles Zeug da drin. Ja, funktionale Sprachen sind jetzt nicht

[1:33:36] so verbreitet in der Realität, aber die gibt es halt auch. Und die funktionale Programmiersprache

[1:33:41] ist natürlich Haskell. Die ist quasi 100% funktional. Das ist immer so die Beispielsprache,

[1:33:46] die genommen wird, wenn man mal zeigen will, wie es richtig geht. Ich kenne aber ehrlich gesagt

[1:33:50] sehr wenige Anwendungen, die in Haskell programmiert sind, aber vielleicht ist das bei dir ja anders.

[1:33:54] Es gibt eine sehr coole funktionale Sprache auch für .NET und zwar F-Sharp von Microsoft. Sehr

[1:33:59] coole Sprache. Habe ich auch schon ein paar Bücher darüber gelesen. Das ist echt, das macht echt Spaß,

[1:34:03] damit zu entwickeln. Es gibt auch Lisp. Lisp ist eine der ältesten Programmiersprachen. Ich glaube,

[1:34:08] aus den 50er Jahren kommt die. Das ist quasi der Urvater der modernen funktionalen

[1:34:13] Programmiersprachen. Darf man auch mal gehört haben, wird in der Realität aber auch wenig

[1:34:16] eingesetzt. Und inzwischen gibt es auch noch was, was ich immer häufiger mitbekomme. Elixir. Das

[1:34:21] basiert auf Erlang und ist sehr, sehr stark bei nebenläufiger Programmierung. Also Erlang ist auch

[1:34:26] eine eigene Programmiersprache und Elixir ist auf Erlang aufgesetzt. Auch noch eine eigene

[1:34:31] Programmiersprache, die so ein bisschen die Syntax von Ruby nimmt und mit den Vorteilen von Erlang

[1:34:36] kombiniert. Das heißt, ich habe eine mega coole Syntax, kann super coole Sachen machen und Erlang

[1:34:40] als Sprache darunter, als Plattform darunter, ist super für nebenläufige Programmierung. Das heißt,

[1:34:44] ich kann dort Millionen von Prozessen parallel starten und das ist überhaupt kein Problem. Das

[1:34:50] funktioniert einfach. Wenn ich das in Java machen würde, dann würde ich wahrscheinlich noch ein

[1:34:54] paar tausend Prozesse in der Rechner abbrauchen. Elixir ist dafür ausgelegt, das zu machen. Das

[1:34:58] heißt, ich kann ganz anders programmieren und ich muss auch anders programmieren, aber es

[1:35:02] funktioniert. Und logisch habe ich eigentlich nur ein Beispiel und zwar Prolog. Die hatte ich

[1:35:06] vorhin schon mal erwähnt. Das ist diese Prädikatenlogik. A ist Vater von und so weiter

[1:35:10] und so fort. Auch eine sehr, sehr coole Sprache. Wenn du mal ein bisschen Zeit hast, kann ich dir

[1:35:15] empfehlen, versuch mal logische Programmierung zu machen. Das ist eine komplett andere Denkweise,

[1:35:20] weil du hast keine Variablen, du hast keine Schleifen. Also das geht, aber du programmierst

[1:35:25] so eigentlich nicht. Das ist wirklich eine komplett andere Welt. Funktional, da findet man

[1:35:30] sich noch so ein bisschen wieder. Ich mache so ein bisschen Rekursiv und Fallunterscheidung. Das geht

[1:35:33] halt alles, aber bei Prolog Wahnsinn. Da musst du komplett umdenken und das ist eigentlich eine

[1:35:38] super Bereicherung, wenn du mal ein bisschen üben möchtest, wie man Probleme löst. Weil da muss man

[1:35:43] komplett anders rangehen, als du es in allen Sprachen wahrscheinlich kennst, die du bisher gesehen hast.

[1:35:47] Kann ich dir nur empfehlen. Ich hatte es im Studium als eigene Vorlesung. Hat mir mega Spaß gemacht.

[1:35:52] Ja, in der Realität habe ich es nie wieder gebraucht, aber von der Denkweise her und so,

[1:35:56] ich habe ganz viel mitgenommen, wo ich heute noch dran denke, weil mir das echt Spaß gemacht hat.

[1:35:59] Kann ich dir nur empfehlen. Und wenn wir schon dabei sind, wie du in so Programmiersprachen einsteigst,

[1:36:03] ich habe eine super Buchempfehlung für dich. Und zwar 7 Languages in 7 Weeks. Das Buch ist schon

[1:36:09] ein bisschen älter, ist aber eine super geile Sache, weil, wie der Name schon sagt, es werden

[1:36:14] sieben Programmiersprachen vorgestellt mit ganz unterschiedlichen Paradigmen, Stärken und Schwächen

[1:36:19] und so weiter. Und auf ein paar Seiten pro Sprache werden so die Killer Features hervorgehoben und

[1:36:25] dann verglichen mit den anderen Sprachen. Das ist richtig cool. Das hat richtig Spaß gemacht, das zu

[1:36:28] lesen, auch wenn du danach nicht in den Sprachen programmierst. Aber einfach, um diese Unterschiede

[1:36:32] noch mal auch in Syntax dann zu sehen, was das heißt und für welche Probleme sich welche Sprache

[1:36:37] gut eignet, fand ich mega gut. Und das kann ich dir nur empfehlen. Es gibt inzwischen noch viel

[1:36:41] mehr Bücher aus diesem 7 in 7 Weeks, zum Beispiel 7 Databases. Da werden dann No-Secret-Datenmang

[1:36:47] vorgestellt, 7 Webframeworks, 7 ich weiß nicht was alles. Also echt cool. Diese Buchreihe kann

[1:36:52] ich nur empfehlen von den Pragmatic Programmers. Link und so weiter findest du ja in den Shownotes,

[1:36:58] hatte ich schon gesagt. itberufe-podcast.de slash 182. So, damit wäre ich jetzt am Ende der heutigen

[1:37:06] Episode. Die ist glaube ich wieder mal ein bisschen länger geworden. Ich fasse trotzdem noch mal kurz

[1:37:09] zusammen. Wenn du in einer Prüfung gefragt wirst, wie würdest du denn deine Programmiersprache

[1:37:13] beschreiben, dann würde ich als allererstes mal darauf eingehen, wofür wird sie eingesetzt. Ist

[1:37:20] es eher für Web-Anwendungen, ist es eher für Desktop, Frontend, Backend, so erstmal so der

[1:37:23] grobe Einsatzzweck. Und auf die harten Fakten kommen wir dann. Programmierparadigma. Ist das

[1:37:29] eher Imperativ oder Deklarativ, so als allgemeiner Einstieg? Und dann konkret, ist es unstrukturiert,

[1:37:34] strukturiert, prozedural, funktional, objektorientiert oder logisch? Das sind die Paradigmen, die es so

[1:37:38] gibt. Ist es eine Compilersprache oder Interpretersprache? Also wird sie übersetzt oder wird

[1:37:43] sie erst zur Laufzeit ausgeführt? Typisierung. Statisch dynamisch typisiert und davon jetzt

[1:37:49] völlig losgelöst, das haben wir jetzt mehrfach betont, stark oder schwach typisiert. Beides

[1:37:54] musst du erklären können. Es reicht nicht nur das eine, wir wollen beides hören, gerade im

[1:37:57] Fachgespräch. Dann haben wir die Syntax. Sieht die aus wie C, also so wie sehr viele Enterprise

[1:38:03] Sprachen oder nicht? Wie zum Beispiel Ruby und Python, die haben halt eine andere Syntax. Ist

[1:38:08] es vielleicht sogar eine grafische Programmiersprache, dann solltest du das vielleicht

[1:38:10] als allererstes sagen, weil davon gibt es nicht allzu viele Programmiersprachen. Das ist schon

[1:38:15] ein Alleinstellungsmerkmal, sag ich mal. Dann, welche Sprachhöhe haben wir? Welches

[1:38:19] Abstraktionsniveau? 1GL, 2GL, 3GL, 4GL? Ich sag mal so, die meisten Sprachen, die wir einsetzen,

[1:38:24] sind eine 3GL-Sprache. Das heißt, wenn du 4GL einsetzt, solltest du vielleicht das auch als

[1:38:28] erstes sagen. So, wenn ich ABAP zum Beispiel klassifizieren müsste, würde ich wahrscheinlich

[1:38:31] als allererstes sagen, das ist eine 4GL-Sprache für SAP, weil das ist das, was diese Sprache so

[1:38:37] besonders macht. Wie gesagt, ich habe keine Zahlen, aber von den über 200 Programmiersprachen sind

[1:38:41] wahrscheinlich 200 3GL-Sprachen, um das mal so ins Verhältnis zu setzen. Dann ist es eine GPL

[1:38:47] oder DSL. Auch hier würde ich als erstes sagen, wenn es eine DSL ist, weil davon gibt es auch

[1:38:52] deutlich weniger als von GPL-Sprachen, weil die meisten sind halt für alles Mögliche einsetzbar,

[1:38:56] Java, C, C-Sharp, etc. Das heißt, Domain-Specific würde ich dann auch zu Beginn sagen, wenn es

[1:39:01] eine wäre. Und dann kannst du nur unterscheiden, wie Portabilität, Laufzeit, Umgebung. Ist sie

[1:39:06] Hardware oder virtuelle Maschine dazwischen? Ist sie managed oder unmanaged? Hat sie besondere

[1:39:10] Eigenschaften bezüglich Performance oder Speicherverbrauch? Und dann haben wir eigentlich

[1:39:15] schon eine ganz gute Klassifizierung, würde ich sagen. Also, kurz und knackig würde ich

[1:39:20] wahrscheinlich als allererstes sagen, wenn ich eine Programmiersprache beschreiben muss,

[1:39:22] zum Beispiel Java. So, beschreibt doch mal Java. Was ist das denn für eine Programmiersprache? Dann

[1:39:27] würde ich sagen, das ist eine objektorientierte Programmiersprache, die mit einer virtuellen

[1:39:32] Maschine arbeitet. Das heißt, die ist plattformunabhängig, kann auf mehreren

[1:39:40] Plattformen laufen, weil das ist das, wofür Java auch geschaffen wurde. Deswegen würde ich das mit

[1:39:43] als erstes nennen. Die hat inzwischen verschiedene Paradigmen, ist eigentlich objektorientiert,

[1:39:48] hat aber auch funktionale Aspekte mit drin. Ist also eigentlich eine Multi-Paradigmen-Sprache,

[1:39:53] wird kompiliert zu Bytecode, wobei der Bytecode dann noch interpretiert wird,

[1:39:58] aber eben um einen JIT-Compiler zur Laufzeit ergänzt, um Performance rauszuholen. Die ist

[1:40:03] statisch typisiert und stark typisiert, also klassisch wie die üblichen Enterprise-Sprachen

[1:40:09] Die sieht aus wie C. Es ist quasi 1 zu 1 C-Syntaxi, die da benutzt wird. Das ist eine ganz normale

[1:40:16] 3GL-Sprache und eine GPL-Sprache. Das heißt, ich kann damit sehr viele verschiedene Sachen machen.

[1:40:20] Und du siehst jetzt schon, als allerletztes würde ich jetzt erst darauf eingehen, was ich noch mit

[1:40:24] Java machen kann. Java ist im Prinzip eine sehr verbreite Sprache, die wird viel für Enterprise-

[1:40:28] Anwendungen eingesetzt, aber auch für Web-Anwendungen. Das heißt, es ist wirklich eine Sprache, die ich

[1:40:31] in vielen Bereichen einsetzen kann. Ich kann ja auch sogar Apps damit nativ für Android entwickeln.

[1:40:36] Das ist eigentlich eine Sprache, mit der ich alles machen kann. Die hat bestimmt auch gewisse

[1:40:41] Schwächen, aber grundsätzlich gibt es eigentlich fast nichts, was ich mit Java nicht machen kann.

[1:40:47] So, das wäre jetzt so meine etwas ausgeführte Antwort in so einem Fachgespräch. Ja,

[1:40:51] wahrscheinlich stellen wir in Fachgesprächen eher konkret die Frage, wie es denn deine Sprache

[1:40:56] typisiert. So, weil es ist das meistens, was am meisten Auswirkungen auf den Code hat, den ich

[1:41:01] sehe. Weil ich da halt konkret was ableiten kann, ob ich da was hinschreiben muss, nämlich die Typen

[1:41:05] oder eben nicht. Das heißt, das würde ich mir auf jeden Fall angucken. Aber du hast jetzt heute

[1:41:10] auch noch viele andere Kriterien kennengelernt, wie man Proben die Sprache unterscheiden kann.

[1:41:13] Und ich hoffe, ich konnte sie dir einigermaßen verständlich rüberbringen. Wenn nicht,

[1:41:17] dann hakt gern nach. Schreib mir einen Kommentar auf der Website, schick mir eine Mail,

[1:41:21] schreib mich per Instagram, wo auch immer an. Grundsätzlich antworte ich eigentlich auf alles,

[1:41:25] was ich kriege. Es kann immer nur ein bisschen dauern, weil ich habe ja noch einen Job neben

[1:41:28] diesem Podcast. Also von daher melde dich gerne, wenn du noch Fragen hast oder was du ergänzen

[1:41:32] hast. Am besten als Kommentar, weil dann können auch die anderen Leute das lesen. Und hier

[1:41:36] wiederhole ich nochmal, die Shownotes findest du unter itberufepodcast.de slash 182. Und wenn du

[1:41:41] bist auf der Seite, nochmal letzte Empfehlung, kannst du gern meinen Newsletter abonnieren. Gerade

[1:41:45] wenn du noch in der Ausbildung bist, im IT-Beruf oder selber sogar Ausbilder oder Ausbilderin. Ich

[1:41:49] habe nämlich in meinem Newsletter, ja, den habe ich so konzipiert, dass du quasi jede Woche von

[1:41:54] mir eine Info kriegst, passend zu deinem aktuellen Ausbildungsstand. Das heißt, im ersten Ausbildungsjahr

[1:41:59] gehen wir zum Beispiel das IT-Handbuch durch. Im dritten Ausbildungsjahr bereiten wir dann auch

[1:42:02] das Fachgespräch vor, so dass es genau zum Ausbildungsstand passt und als Ausbilder,

[1:42:06] Ausbilderin eben auch zum Ausbildungsstand deiner Azubis. Von daher melde dich da gerne an. Es

[1:42:11] ist komplett kostenfrei. Wenn du keinen Bock mehr drauf hast, dann melde dich einfach ab. Ist

[1:42:14] überhaupt kein Thema. Und ja, würde mich freuen, denn da habe ich, ja, sehr viel Herzblut reingesteckt,

[1:42:20] das so zu überarbeiten oder so überhaupt erst mal zu erstellen, dass du die ganzen drei Jahre

[1:42:25] deiner Ausbildung durch meinen Newsletter begleitet wirst. Eigentlich, glaube ich, eine ganz coole

[1:42:28] Sache. Ja, das soll es jetzt für heute gewesen sein. Ich habe lange genug geredet über Programmiersprachen.

[1:42:32] Ich hoffe, es war interessant für dich. Wir hören uns beim nächsten Mal wieder. Ich sage für heute

[1:42:36] erst mal vielen Dank fürs Zuhören und bis zum nächsten Mal. Tschüss!

Polyglot Clean Code Developer
About the Author
Ausbildungsleiter für Fachinformatiker:innen Anwendungsentwicklung, IHK-Prüfer und ehemaliger Hochschuldozent für Programmierung und Software-Engineering.

1 comment on “Eigenschaften und Unterscheidung von Programmiersprachen – IT-Berufe-Podcast #182”

  1. Arley sagt:

    Hallo Stefan,

    Der Podcast gefällt mir sehr und obwohl manche Konzepte dieser Episoden mit etwas bekannt waren, habe ich gerne die ganze Episode gehört.

    Eins würde ich mir noch wünschen. Es wäre einfach Klasse wenn die Kapitel auch zur Verfügung in meiner Podcast-App stehen.

    Vielen Dank für Ihre tolle Arbeit!

    Als Notiz würde ich hinzufügen dass ich noch die Sprache lerne und daher entschuldige ich mich für die Rechtschreibfehlern diejenigen auf meinem Kommentar liegen könnten.

    Grüße aus dem Norden!

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert