2 Punkte von GN⁺ 2025-07-11 | Noch keine Kommentare. | Auf WhatsApp teilen
  • Flix ist eine von der Aarhus University und der Open-Source-Community entwickelte effektorientierte Sprache, die funktionale, imperative und logische Programmierung in einer Sprache vereint
  • Im Zentrum steht ein Effektsystem, das Nebenwirkungen auf Typebene behandelt und durch Reinheitsverfolgung, benutzerdefinierte Effekte, Handler und mehrfache Wiederaufnahmen Modularität und bessere Schlussfolgerbarkeit ermöglicht
  • Die Sprachoberfläche ist breit aufgestellt und umfasst algebraische Datentypen, Pattern Matching, erweiterbare Records, Traits, Higher-Kinded Types, assoziierte Typen und Effekte, strukturierte Nebenläufigkeit, Java-Interoperabilität und eingebautes Datalog
  • Die Standardbibliothek bietet mehr als 3.100 Funktionen und ermöglicht über Maven auch den Zugriff auf das Java-Ökosystem, wodurch der Einsatz über reine Forschungssprachen hinausgehen soll
  • Der Compiler zielt auf JVM-Bytecode ab und ist parallel sowie inkrementell aufgebaut; auf einer 24-Core-Maschine werden 5x–7x Geschwindigkeitssteigerung sowie ein Durchsatz von 60.159 lines/sec unter Apple M2 Pro/OpenJDK 21 angegeben

Die Ausrichtung von Flix

  • Flix ist eine prinzipienbasierte effektorientierte Sprache, die funktionale, imperative und logische Programmierung kombiniert
  • Entwickelt wird sie von der Aarhus University und der Community der Open-Source-Mitwirkenden
  • Das Effektsystem ist eine zentrale Säule der statisch typisierten Sprache und unterstützt durch explizite Modellierung von Nebenwirkungen Modularität und Programmanalyse
  • Über benutzerdefinierte Effekte und Handler können Programmierer Kontrollstrukturen selbst implementieren
  • Flix hebt sich unter den effektorientierten Sprachen durch eine ausgereifte Implementierung, eine breite Standardbibliothek, ausführliche Dokumentation und Tool-Unterstützung hervor

Typen, Reinheit und Effektsystem

  • Flix unterstützt algebraische Datentypen und Pattern Matching als grundlegende Elemente funktionaler Programmierung
  • Tupel und Records werden nativ unterstützt; Records verwenden strukturelle Typisierung und sind erweiterbar
  • Der Compiler verfolgt die Reinheit aller Ausdrücke im Programm präzise
    • Ist ein Ausdruck rein, ist garantiert, dass er keine Nebenwirkungen hat und referenztransparent ist
  • Auch bei Higher-Order Functions wird Reinheit durch Effektpolymorphie verfolgt
    • So hängt etwa die Reinheit von List.map von der Reinheit der als Argument übergebenen Funktion f ab
  • Algebraische Effekte ermöglichen benutzerdefinierte Effekte und Handler
    • Flix unterstützt dabei insbesondere multi-shot resumptions
    • Effekt-Handler werden genutzt, um Programmanalyse, Modularität und Testbarkeit zu verbessern

Regionsbasierte Mutation und Reinheitsreflexion

  • Flix unterstützt regionsbasierte lokale Mutation, sodass intern veränderbarer Zustand und destruktive Operationen verwendet werden können, nach außen aber weiterhin eine reine Funktion sichtbar ist
  • Das eignet sich für Funktionen, die sich natürlicher mit veränderbaren Daten schreiben lassen, oder für Fälle wie Sortieralgorithmen, bei denen veränderbare Datenstrukturen effizienter sind
  • Reinheitsreflexion ist eine Metaprogrammierungsstruktur, bei der Higher-Order Functions die Reinheit von Funktionsargumenten prüfen und ihr Verhalten davon abhängig machen
    • DelayList.map wechselt je nach Reinheit der Argumentfunktion zwischen sofortiger und verzögerter Auswertung
    • Selbst wenn innerhalb der Bibliothek wahlweise Lazy Evaluation oder parallele Auswertung genutzt wird, muss sich die Bedeutung aus Sicht des Clients nicht ändern

Parallelität, Nebenläufigkeit und Abstraktion

  • Flix macht es leicht, reinen Code parallel auszuwerten, und mit der par-Struktur lässt sich eine parallele Implementierung von List.map schreiben
  • Die par-Struktur verwendet intern leichtgewichtige VirtualThread
  • Es wird strukturierte Nebenläufigkeit unterstützt, sodass Threads, die in einer bestimmten Region erzeugt werden, nicht über den Lebenszyklus dieser Region hinaus bestehen können
    • Im Beispiel werden zwei Threads in einer neuen Region namens rc erzeugt
    • Der Kontrollfluss verlässt die Region erst, wenn beide Threads beendet sind
  • Für Typabstraktionen, die gemeinsame Operationen unterstützen, werden Traits verwendet
    • Das Eq-Trait beschreibt das Konzept von Gleichheit und wird in der gesamten Standardbibliothek verwendet
  • Mit Higher-Kinded Types lassen sich Typkonstruktoren abstrahieren
    • Option und List implementieren beide Foldable
    • Die Standardbibliothek enthält gemeinsame Traits wie Monoid, Functor und Foldable

Assoziierte Typen, assoziierte Effekte und for-yield

  • Flix unterstützt assoziierte Typen, sodass der Typ einer Instanzsignatur vom Instanztyp abhängen kann
    • Im Beispiel des Coll-Traits kann jede Collection-Instanz über den assoziierten Typ Elm ihren Elementtyp definieren
  • Assoziierte Effekte sorgen dafür, dass der Effekt eines Trait-Members vom Instanztyp abhängt
    • Dadurch lassen sich reine und effektbehaftete Operationen sowie veränderbare und unveränderliche Datenstrukturen leichter gemeinsam abstrahieren
    • Fügt man dem Coll-Trait den assoziierten Effekt Aef hinzu, können auch veränderbare Collection-Instanzen ergänzt werden
  • forM-yield ist eine monadische Struktur ähnlich wie for-comprehensions in Scala oder die do-Notation in Haskell
    • Es handelt sich um syntaktischen Zucker für die Nutzung von point und flatMap, die das Monad-Trait bereitstellt
  • forA ist ein applicativer Ausdruck auf Basis des Applicative-Traits
    • Die Struktur hilft dabei, Fehlerbehandlungscode mit dem Datentyp Validation[e, t] einfach zu schreiben

Java-Interoperabilität und Datalog

  • Flix unterstützt Java-Interoperabilität, sodass sich die Java Standard Library und Code aus dem Java-Ökosystem wiederverwenden lassen
    • Einschließlich des Zugriffs auf das Ökosystem über Maven
    • Unterstützt werden Objekterzeugung, Methodenaufrufe, Ausnahmen sowie das Erweitern von Klassen und Interfaces
  • Die eingebaute Unterstützung für Datalog ist eine der besonderen Funktionen von Flix
    • Mit Datalog lassen sich viele Fixpunktprobleme, darunter auch Erreichbarkeitsprobleme in Graphen, prägnant ausdrücken
  • Datalog-Constraints sind Werte erster Klasse
    • Sie können an Funktionen übergeben oder von Funktionen zurückgegeben werden
    • Sie können in Datenstrukturen gespeichert werden
    • Sie können mit anderen Datalog-Constraints kombiniert und gelöst werden
    • Dadurch lassen sich ganze Familien von Datalog-Programmen ausdrücken
  • Flix unterstützt auch Datalog-Constraints mit erweiteter Gittersemantik
    • Es gibt ein Beispiel zur Berechnung von Lieferterminen für Bauteile und Unterbaugruppen
    • Ein Auto hängt von Fahrgestell und Motor ab und kann erst montiert werden, nachdem die Montage aller Komponenten abgeschlossen ist
    • Auch Unterbaugruppen können wiederum von weiteren Unterbaugruppen abhängen, sodass das Problem rekursiv ist
  • Datalog-Constraints mit Gittersemantik gehören zu den fortgeschrittenen Funktionen von Flix und setzen Kenntnisse in Gittertheorie und Fixpunkten voraus

Standardbibliothek und Funktionsliste

  • Flix enthält eine Standardbibliothek mit mehr als 3.100 Funktionen
    • Das Modul List bietet mehr als 100 Funktionen
    • Das Trait Foldable bietet mehr als 47 Funktionen
    • Die gesamte Bibliothek kann unter api.flix.dev erkundet werden
  • Zur Funktionsliste gehören unter anderem
    • algebraische Datentypen, Pattern Matching, Funktionen erster Klasse
    • erweiterbare Records, parametrische Polymorphie
    • Traits, Higher-Kinded Types, assoziierte Typen und Effekte
    • Effektpolymorphie und Sub-Effekte, Reinheitsreflexion
    • Nebenläufigkeit im CSP-Stil, gepufferte und ungepufferte Channels
    • Datalog-Constraints erster Klasse, Java-Interoperabilität
    • unboxed primitive Typen, schlüsselwortbasierte Syntax
    • forM, forA, Expression Holes
    • Kompilierung zu JVM-Bytecode, vollständige Tail-Call-Eliminierung
    • elastische und parallele Compiler-Architektur, menschenlesbare Fehlermeldungen

Compiler-Architektur und Leistung

  • Der Flix-Compiler ist elastisch, inkrementell und parallel aufgebaut
  • Alle Compiler-Phasen laufen parallel, sodass auf einer 24-Core-Maschine die Beschleunigung jeder Phase genutzt werden kann
  • Auf Multicore-Maschinen sind 5x–7x Geschwindigkeitssteigerung möglich
  • Wenn bereits kompilierter Code innerhalb derselben Compiler-Instanz erneut kompiliert wird, kann inkrementelle Kompilierung deutliche Beschleunigungen bringen
  • Auf Basis einer Apple M2 Pro CPU mit 10 Kernen und OpenJDK 21 werden folgende Leistungswerte angegeben
    • Gesamtdurchsatz des Compilers: 60.159 lines/sec
    • Durchsatz nur des Frontends: 140.382 lines/sec
    • Die Reproduktionsbefehle sind java -jar flix.jar Xperf --n 21 und java -jar flix.jar Xperf --frontend --n 21
  • Diese Leistung wird erreicht, obwohl kostenintensive Sprachmerkmale wie Typ- und Effektinferenz, Monomorphisierung und Whole-Program-Optimierung unterstützt werden
  • Die Compiler-Leistung wird hauptsächlich durch CPU-Leistung und Speicherbandbreite bestimmt

Unterstützung für Visual Studio Code und Tool-Integration

  • Der Flix-Compiler ist in Visual Studio Code integriert und stellt damit eine Entwicklungsumgebung bereit
  • Die VSCode-Erweiterung verwendet den echten Flix-Compiler, daher besteht eine 1:1-Entsprechung zwischen Erweiterung und Compiler
    • Wenn VSCode keinen Fehler meldet, gibt es keinen Fehler
    • Wenn kein Fehler vorliegt, meldet VSCode auch keine falschen Fehler
  • Die VSCode-Erweiterung unterstützt folgende Funktionen
    • semantisches Syntax-Highlighting
    • Inline-Diagnosen von Compilerfehlern
    • Autovervollständigung beim Tippen, kontextabhängige Vervollständigung, Vervollständigung von Trait-Instanzen, typbasierte Hole-Vervollständigung
    • Snippets und Inlay-Hints
    • Hover-Anzeigen für Typ und Effekt von Ausdrücken
    • Navigation zu Funktionen, lokalen Variablen und Enum-Definitionen
    • Finden von Referenzen auf Funktionen, lokale Variablen und Enums sowie Finden von Trait-Implementierungen
    • Listen von Dokument- und Workspace-Symbolen
    • Umbenennen lokaler Variablen und Funktionsnamen
    • Ausführen von main und Tests direkt im Editor
  • Flix integriert viele Werkzeuge direkt in den Compiler
    • OCaml nutzt ocaml-lsp als LSP, utop als REPL, dune als Build-Tool und opam als Paketmanager
    • Haskell nutzt HLS als LSP, ghci als REPL, cabal und stack als Build-Tool und Paketmanager sowie Hackage als Paket-Repository
    • Flix stellt Compiler, LSP, REPL, Build-Tool und Paketmanager allesamt über flix bereit, das Paket-Repository ist GitHub

Entwicklungsstand, JVM-Ziel und Projektgröße

  • Flix wird von Forschern im Bereich Programmiersprachen an der dänischen Aarhus University entwickelt und gepflegt
  • Kooperationspartner sind die kanadische University of Waterloo, die deutsche University of Tubingen und die dänische Copenhagen University
  • Die Beteiligung der weltweiten Open-Source-Community am Projekt wächst, Beiträge sind willkommen
  • Die Projektstatistiken lauten wie folgt
    • gemergte Pull Requests: mehr als 4.900
    • gelöste Issues: mehr als 3.100
    • Mitwirkende: mehr als 70
    • Codebasis des Compilers: mehr als 272.000 Zeilen
  • Flix zielt auf die JVM ab
    • Für die JVM gibt es bewährte Open-Source- und kommerzielle Implementierungen wie OpenJDK, J9, Azul und Graal
    • Flix ist unter Mac, Linux und Windows nutzbar
    • Moderne JVMs bieten mehrere aktuelle Garbage Collectors
    • Auch die Unterstützung für Nebenläufigkeit und Parallelität ist stark, einschließlich leichtgewichtiger Threads in Java 21
    • Es gibt Tool-Unterstützung einschließlich Debuggern und Profilern
    • Über die Maven-Integration ist Zugang zum umfangreichen Paket-Ökosystem der Java-Plattform möglich
  • Die Gesamtfinanzierung beträgt 1,1 Millionen Euro und hilft dabei, Kontinuität und Unabhängigkeit des Projekts zu sichern

Noch keine Kommentare.

Noch keine Kommentare.