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

IT-Berufe-Podcast - A podcast by Stefan Macke - Lunedì

Podcast artwork

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)

Visit the podcast's native language site