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. Inhalt Was ist eine
Programmiersprache? Programmiersprache: „Eine Programmiersprache
ist eine formale Sprach...
1 Stunde 42 Minuten
Podcast
Podcaster
Beschreibung
vor 2 Jahren
Um Eigenschaften und Unterscheidungsmerkmale von
Programmiersprachen geht es in der einhundertzweiundachzigsten
Episode des IT-Berufe-Podcasts.
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:
Build-Tools, z.B. Maven, Gradle
Dependency-Management, z.B. NPM, RubyGems
Test-Frameworks, z.B. JUnit
weitere Frameworks und Libraries, z.B. Spring, Jakarta EE,
Rails, Blazor
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 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 `'
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)*
Links
Permalink zu dieser Podcast-Episode
RSS-Feed des Podcasts
Turing-Vollständigkeit (Wikipedia)
Programmiersprache (Wikipedia)
Einführung in Build-Werkzeuge
Unit-Tests – Häufige Fragen im Fachgespräch
Java EE 7 (Lernzielkontrolle)
HTML
Buchclub: Handbuch für Fachinformatiker (Teil 9: XML)
Buchclub: Handbuch für Fachinformatiker (Teil 7: HTML und
CSS)
SQL – Häufige Fragen im Fachgespräch
Variablen und Operatoren (Lernzielkontrolle)
Algorithmen und Methoden (Lernzielkontrolle)
Objektorientierung Teil 1 (Lernzielkontrolle)
Markus Amshove über Domänenspezifische Sprachen
Weitere Episoden
5 Minuten
vor 3 Wochen
11 Minuten
vor 4 Monaten
8 Minuten
vor 4 Monaten
8 Minuten
vor 4 Monaten
10 Minuten
vor 5 Monaten
In Podcasts werben
Kommentare (0)