1 Punkte von GN⁺ 2025-10-17 | 1 Kommentare | Auf WhatsApp teilen
  • Mit Elixir 1.19 lassen sich durch ein stärkeres Typsystem und verbesserte Compiler-Performance mehr Bugs schneller erkennen
  • Die Typinferenz wurde auf anonyme Funktionen und Protokolle ausgeweitet, wodurch eine deutlich umfassendere automatische Prüfung auch ohne Typannotationen der Nutzer möglich ist
  • In großen Projekten wird eine bis zu 4-fach höhere Kompiliergeschwindigkeit erreicht, einschließlich Optimierungen bei paralleler Kompilierung und Code-Laden
  • Auch das Ökosystem und die Transparenz der Lieferkette wurden gestärkt, unter anderem durch Unterstützung für Erlang/OTP 28 und die Einführung der OpenChain-Zertifizierung
  • Darüber hinaus sind zahlreiche weitere Funktionen enthalten, etwa verbessertes Option Parsing, bessere Debug-Eigenschaften von ExUnit und eine verbesserte Zugänglichkeit shell-basierter Dokumentation

Wichtige Verbesserungen in Elixir 1.19

Verbesserungen am Typsystem

Typinferenz für alle Bestandteile

  • Type inference (Typinferenz) ist eine Funktion, die den Typ von Ausdrücken zur Compile-Zeit automatisch bestimmt
  • Bisher sollte die Typinferenz vor allem für Pattern, Guards und Rückgabewerte unterstützt werden, in diesem Release wurde jedoch Typinferenz für alle Bestandteile (außer Guards) eingeführt
  • Da bei der Typinferenz auch Funktionsaufrufe innerhalb von Modulen sowie Aufrufe von Funktionen der Elixir-Standardbibliothek berücksichtigt werden, können Funktionen, die früher als dynamic() -> boolean() inferiert wurden, nun präziser als etwa integer() -> boolean() inferiert werden
  • Typinferenz bringt verschiedene Trade-offs mit sich, etwa bei Kompiliergeschwindigkeit, Ausdrucksstärke, inkrementeller Kompilierung und Klarheit von Fehlermeldungen; künftig sollen daher auch Guard-Typinferenz und Typinformationen aus Abhängigkeiten einbezogen werden
  • Wenn für eine Funktion eine Typsignatur explizit angegeben ist, arbeitet das System nicht mit Typinferenz, sondern mit einer expliziten Typprüfung, die nur Typen zulässt, die zur Annotation des Nutzers passen

Typprüfung bei Protokoll-Dispatch und Implementierungen

  • Elixir wendet jetzt Typprüfungen bei Protokollaufrufen und -implementierungen an
  • Wird zum Beispiel ein Typ, der das Protokoll String.Chars nicht implementiert, an String-Interpolation übergeben, wird eine Warnmeldung ausgegeben
  • Auch in for comprehensions wird eine Warnung erzeugt, wenn ein Typ, der das Protokoll Enumerable nicht erfüllt, als Generator übergeben wird
  • Mit diesen Typprüfungen lassen sich mehr Bugs bereits zur Compile-Zeit verhindern

Typinferenz und -prüfung für anonyme Funktionen

  • Elixir 1.19 unterstützt Typinferenz und Typprüfung für anonyme Funktionen
  • Wird etwa an eine anonyme Funktion, die den Typ %{} erwartet, ein falscher Typ wie "hello" übergeben, kann das sofort als Warnung zur Compile-Zeit erkannt werden
  • Auch bei Function Captures (&String.to_integer/1 usw.) wird Typinferenz angewendet, wodurch der Umfang automatisierter Typprüfung erweitert wird

Referenzen und Partner

  • Dieses Typsystem wurde in einer Partnerschaft zwischen CNRS und Remote entwickelt
  • Fresha, *Starfish* *, Dashbit und weitere haben das Projekt unterstützt

Schnellere Kompilierung in großen Projekten

Beseitigung von Bottlenecks beim Code-Laden

  • Bisher wurden Module direkt nach ihrer Definition geladen, in diesem Release wurde dies auf eine Lazy-Loading-Strategie umgestellt
  • Dadurch wird der Code-Server entlastet, die parallele Kompilierung verbessert und die Kompiliergeschwindigkeit großer Projekte um mehr als das Doppelte erhöht
  • Zwei wichtige Hinweise:
    • Wenn während der Kompilierung ein separater Prozess erzeugt wird und dieser auf Module desselben Projekts zugreift, kann das Laden ausbleiben; als Workaround können Kernel.ParallelCompiler.pmap/2 oder Code.ensure_compiled!/1 verwendet werden
    • Innerhalb eines @on_load-Callbacks kann beim Aufruf von Modulen desselben Projekts ein Fehler auftreten; falls nötig, kann die Option @compile {:autoload, true} verwendet werden
  • In beiden Fällen konnten früher nicht deterministische Kompilierfehler auftreten, mit dieser Verbesserung wird nun jedoch eine deterministische (reproduzierbare) Kompilierumgebung gewährleistet

Parallele Kompilierung von Abhängigkeiten

  • Über die Umgebungsvariable MIX_OS_DEPS_COMPILE_PARTITION_COUNT wird die parallele Kompilierung von Abhängigkeiten unterstützt
  • Da mehrere OS-Prozesse gleichzeitig verwendet werden, um Abhängigkeiten parallel zu kompilieren, kann sich die Kompilierleistung je nach Projektgröße und Anzahl der CPU-Kerne um bis zu das 4-Fache verbessern
  • Experimentell hat sich gezeigt, dass ein Wert von etwa der Hälfte aller verfügbaren Kerne für die Ressourcennutzung effektiv ist
  • Durch die Parallelisierung kann sich der Speicherverbrauch erhöhen, weshalb bei der Nutzung in CI oder auf Build-Servern Vorsicht geboten ist

Unterstützung für Erlang/OTP 28

  • Elixir 1.19 unterstützt offiziell Erlang/OTP 28.1+
  • Aufgrund von Änderungen an der Darstellung regulärer Ausdrücke in Erlang/OTP 28 können reguläre Ausdrücke nicht mehr als Standardwert in Structs verwendet werden
  • Bei der Initialisierung von Structs können reguläre Ausdrücke weiterhin verwendet werden

Einführung der OpenChain-Zertifizierung

  • Dieses Release ist die erste Version, die mit der Einhaltung des OpenChain-Standards beginnt
  • Jedes Release enthält ein SBoM (Source Bill of Materials) im Format CycloneDX 1.6/SPDX 2.3
  • Das erhöht die Transparenz der Lieferkette bei Release-Bestandteilen und Lizenzen und trägt zu einer strengeren Verwaltung bei
  • Diese Arbeit wurde von Jonatan Männchen durchgeführt und von der Erlang Ecosystem Foundation unterstützt

Weitere Verbesserungen

  • Hinzu kommen verschiedene Verbesserungen an Tools und Bibliotheken, darunter Option Parsing, Debugging und Performance von ExUnit sowie die Zugänglichkeit shell-basierter Dokumentation
  • Ausführlichere Release Notes finden sich im CHANGELOG

1 Kommentare

 
GN⁺ 2025-10-17
Hacker-News-Kommentare
  • Es wird betont, dass die schrittweise Einführung automatischer Typprüfung in Elixir ein hervorragendes Beispiel für eine Sprachverbesserung ist, an dem sich auch andere Programmiersprachen orientieren können; es gab viele Fälle, in denen Ökosysteme durch große Veränderungen in zwei Lager gespalten wurden, und es ist beruhigend, dass José bereits 2018 klar gesagt hat, dass die Sprache selbst im Wesentlichen fertig ist; Sprache und Core werden nicht mehr aufbrechend verändert, was viel Stabilität vermittelt. Empfohlen wird auch dieser Vortrag. Die konsistente und hervorragende Steuerung beeindruckt.

    • Als Beispiele für eine Spaltung des Ökosystems durch große Änderungen in wichtigen Sprachen fallen mir nur Python 3 und Perl 6 ein. Weil diese beiden Umstellungen so einschneidend waren, wirken Veränderungen in anderen Sprachen vermutlich ebenfalls riesig.
    • Bei Elixir hat man nie das Gefühl, ständig zu einem Versions-Upgrade gedrängt zu werden; man schaut sich die eingeführten Änderungen an und bekommt Lust auf ein Upgrade, weil nützliche neue Funktionen dabei sind. Es fühlt sich nicht beunruhigend oder stressig an, wie wenn man zu einem Versionswechsel gezwungen wird.
    • Ich nutze Elixir seit 2017 in Produktionsumgebungen, und jedes Upgrade verlief deutlich reibungsloser als erwartet. Tatsächlich waren eher Erlang/OTP-Upgrades wegen Kompatibilitätsproblemen häufiger komplizierter. Deshalb nutze ich meist die neueste Elixir-Version, warte bei der OTP-Version aber noch ein oder zwei Monate, bis mögliche Konflikte behoben sind, und upgrade erst dann.
    • Elixir ist weiterhin in mancher Hinsicht noch unreif und wenig komfortabel, daher braucht es klare Leitlinien zum Erreichen bestimmter Ziele und mehr Stabilisierung im Ökosystem. Viele Pakete sind verwaist oder schlecht dokumentiert, sodass es schwer ist, mit dem Wandel im Phoenix-Ökosystem Schritt zu halten. Viele wollen weder LiveViews noch bestimmte Komponentensysteme, und die Einstiegshürde für die Kompatibilität mit anderen Tools und Technologien ist hoch. Bei Python 3 war der Wechsel von 2 auf 3 zwingend nötig und mit automatisierten Migrationswerkzeugen insgesamt vergleichsweise gut gelöst, auch wenn es viele Reibungen gab. Ruby 3 hingegen hat mit externen Typdateien und einer Zersplitterung der Tools eher Verwirrung gestiftet; dazu kamen Boilerplate, Governance-Probleme und gekaperte Gems, was insgesamt zu negativen Erfahrungen führte und dazu, dass ich Ruby kaum noch nutze. Selbst eine großartige Sprache kann durch unreife Steuerung ruiniert werden, daher sind reife Zusammenarbeit, Kommunikation und gutes Change-Management entscheidend. Änderungen am Sprachdesign sollten ausreichend vorab erprobt und vorsichtig eingeführt werden, und die Nutzer sollten früh genug informiert werden, damit unnötige Verwirrung minimiert wird. Ich hoffe, dass Elixir/Phoenix/OTP künftig noch einfacher, leistungsfähiger, produktiver und performanter wird, sodass verschiedenste Nutzer es mit gutem Gefühl einsetzen können. Empfehlenswert sind Ressourcen wie Livebook und der Exercism-Elixir-Track.
  • Elixir liefert weiterhin konstant großartige Funktionen und Verbesserungen und entwickelt sich stabil weiter. Die Spracharchitektur ist hervorragend, und die Gründer geben kontinuierlich die richtige Richtung vor; wirklich beeindruckend. Schade ist eher, dass man im Alltag nicht öfter Gelegenheit hat, Elixir zu verwenden.

    • Ich wollte unbedingt Elixir nutzen und habe dafür sogar meinen Job gekündigt und selbst ein Startup gegründet.
  • Es werden experimentelle Daten zur Kompiliergeschwindigkeit von Phoenix-Abhängigkeiten geteilt. Auf einem Mac M1 Max wurden bei einer kleinen App, die nur die Standard-Phoenix-Abhängigkeiten enthält, je nach Wert der Umgebungsvariable MIX_OS_DEPS_COMPILE_PARTITION_COUNT folgende Kompilierzeiten gemessen:

    PARTITION_COUNT=1:  12.336초 (유저 32.30s, 시스템 7.23s, CPU 320%)
    PARTITION_COUNT=5:  6.970초 (유저 0.37s, 시스템 0.49s, CPU 12%)
    PARTITION_COUNT=10: 7.236초 (유저 0.38s, 시스템 0.50s, CPU 12%)
    

    Dazwischen wurde jedes Mal mit dem Befehl rm -rf _build der Cache gelöscht.

    • Die späteren Läufe scheinen mit aktivem Cache gemessen worden zu sein; möglicherweise wurde die native Kompilierung direkt im dep-Ordner ausgeführt, sodass in _build keine Spuren verblieben.
    • Ich verstehe nicht, warum Benchmarks zu dieser Funktion des Releases Downvotes bekommen. Vielleicht kann jemand in den Kommentaren erklären, warum.
  • In den letzten Monaten habe ich Gleam wirklich schätzen gelernt. Ich begrüße zwar auch die Einführung eines Typsystems in Elixir, aber genau dieser Punkt war früher ein Hauptgrund, Elixir nicht zu übernehmen. Ich würde Elixir irgendwann gern noch einmal ausprobieren, habe aber die Sorge, dass es am Ende wie bei JavaScript mit TypeScript nur äußerlich typisiert ist und in vielen Libraries oder Paketen doch alles als dynamic/any endet. Ich frage mich, ob diese Sorge unbegründet ist. BEAM ist wirklich großartig.

    • Die Ausgangslage ist eine andere als bei TypeScript. Dank Pattern Matching dürfte sich in bestehenden Elixir-Codebasen zumindest für etwa 50 % der Fälle eine Typinferenz ableiten lassen, und weil Vanilla-Elixir Typen von Haus aus unterstützt, wird sich in gepflegtem Code die Typisierung wohl schnell durchsetzen. Ich bevorzuge eigentlich keine Typsysteme und nutze nur JS, aber bei Elixir ergibt sich die Typisierung ganz natürlich. Bei TypeScript breitet sie sich eher nach oben aus, bei Elixir eher natürlich nach unten.
    • Gleam kann die eigentlichen Stärken von OTP/BEAM nicht vollständig ausschöpfen. Das ist ein Reiz, den nur Elixir bietet.
    • Elixir hatte schon immer Typkonzepte wie primitive Typen, Structs und shape-basierte Destrukturierung, und mit Tools wie Dialyzer oder TypedStruct ließ sich bereits Typprüfung durchführen. Es ist keine absurd untypisierte Sprache wie JavaScript.
    • Gleam ist ebenfalls gut, aber auf der JVM gibt es mit Kotlin eine typsichere Sprache mit Ruby-ähnlicher Syntax, die auch compile-to-JS kann.
  • Elixir wirkt auf mich wie die vielversprechendste Umgebung für Webentwicklung. Jedes Mal, wenn ich im Berufsalltag auf Organisationen oder Teams treffe, die Elixir nutzen, scheint ihr Niveau höher zu sein als gewöhnlich. Ich denke, Elixir gibt in Umgebungen mit kontinuierlicher Weiterentwicklung weiterhin Richtung und Standards vor.

  • Es wird vorgestellt, dass das Elixir-Release nun Source-SBoM-Formate ab CycloneDX 1.6 und SPDX 2.3 unterstützt. Es ist wirklich großartig, dass SBOM-Management auf Sprachebene stattfindet. Leider nutzt mein aktuelles Unternehmen Elixir nicht.

  • Wer zu einem praxisnahen Open-Source-Elixir-Projekt beitragen möchte: Eine frühere Hauptkomponente von Mozilla Hubs wird als eigenständiges Projekt weiterhin in Elixir entwickelt, siehe Hubs Foundation/reticulum.

  • Auf Basis der Elixir-Standardbibliothek ist eine Compile-Time-Typinferenz möglich, die in anwendungsspezifischen Situationen dynamische Typen als Boolesche Werte oder etwa Integer als Boolesche Werte behandeln kann.

  • Ich habe keine Erfahrung in der Elixir-Entwicklung, bin aber ein Fan. Früher mochte ich die Praxisnähe und Schönheit von Ruby, habe dann aber wegen meiner Begeisterung für Typsysteme die Sprache gewechselt. Sowohl Elixir als auch Ruby haben Typsysteme eingeführt, aber heute nutze ich meist Kotlin, das sich syntaktisch wie „typisiertes Ruby“ anfühlt.

    • Kotlin ist fast genau das Gefühl von JRuby, das wir uns eigentlich immer gewünscht haben.
  • Ich nutze Soketi zusammen mit dem Pusher-SDK für Event-Broadcasting. Die App hat eine gemischte Struktur aus Echtzeit- und REST-Endpunkten, und die Last durch Echtzeitberechnungen ist nicht besonders hoch, aber falls nötig würde ich diesen Teil separat in Go umsetzen. Demnächst sollen auch Kollaborationsfunktionen hinzukommen, und ich frage mich, ob es in so einer Situation sinnvoll ist, Phoenix einzuführen.