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) ...
Kommentare (0)
Melde dich an, um einen Kommentar zu schreiben.