3 Punkte von GN⁺ 2023-07-19 | 1 Kommentare | Auf WhatsApp teilen
  • Hylo zielt auf sichere System- und generische Programmierung auf Basis von Wertsemantik; Compiler und Standardbibliothek befinden sich noch in einer frühen Phase, aber Beispiele lassen sich im Compiler Explorer ausführen
  • Die Sprachforschung konzentriert sich auf Themen wie die Erweiterung von Swifts subscript um inout projection, method bundles, strukturierte Nebenläufigkeit und doppelt verkettete Listen auf Basis von Wertsemantik
  • Der Compiler verwendet LLVM und behandelt zugleich generische Kompilierung mit Coherence, Caching und Serialisierung von Programmzustand sowie Forschung zur C-Interoperabilität
  • Die Entwicklungsumgebung bietet eine VSCode-Erweiterung, einen Dokumentations-Compiler und einen Language-Server-Prototyp und unterstützt SPM/CMake, Ninja/Xcode, Windows/Linux/macOS sowie Docker-Toolchain-Images für die Entwicklung
  • Die Beispiele machen über sichere projection und sink methods Eigentums- und Freigaberegeln auf Code-Ebene sichtbar und zeigen, wie eine Systemsprache Sicherheit erzwingen kann

Umfang und aktueller Stand von Hylo

  • Compiler und Standardbibliothek von Hylo befinden sich noch in einer frühen Phase
  • Fortgeschrittene Hylo-Codebeispiele lassen sich im Compiler Explorer ausführen
  • Schon auf der Startseite gibt es einen Link, um Hylo im Compiler Explorer auszuprobieren

Wertsemantik und Sprachforschung

Compiler und Standardbibliothek

  • Die Arbeit am Compiler umfasst LLVM-basierte Kompilierung, Generics, Zustandsverwaltung und C-Interoperabilität
    • Kompilierung mit LLVM
    • Neue Technik für generische Kompilierung mit Coherence
    • Caching und Serialisierung des Programmzustands im Compiler
    • Forschung zu C interop
  • Auf Seiten der Standardbibliothek werden derzeit Dokumentation zur Implementierung und Arbeiten zu Collection-Algorithmen veröffentlicht

Developer Experience und Build-Umgebung

  • Es werden auch Tools für Editor, Dokumentation und Sprachserver bereitgestellt
  • Build- und Entwicklungsumgebung unterstützen mehrere Betriebssysteme und containerbasierte Workflows
    • Unterstützung für Development Containers verkürzt den Einstieg
    • Unterstützung für SPM/CMake, Ninja/Xcode, Windows/Linux/macOS
    • Compiler-Plugin zur Testgenerierung
    • Vorgebaute Docker-Images der Hylo development toolchain
    • Der Compiler ist in Swift 6.2 geschrieben

Forschung und Vortragsmaterial zu Hylo

Codebeispiele: sichere projection und explizite Freigabe

  • Das Beispiel Subscripts - A Safe Projection Mechanism zeigt eine Struktur, in der der Typ Angle den Wert radians speichert und die Property degrees über let- und inout-Blöcke bereitstellt
    • Das let von degrees konvertiert radians in degree und gibt den Wert zurück
    • inout legt den temporären degree-Wert d über yield &d offen, konvertiert danach den geänderten Wert zurück in radians und übernimmt ihn in self.radians
    • main holt sich mit inout d = &a.degrees eine projection, setzt d auf 0.0 und prüft anschließend a.radians == 0.0
  • Das Beispiel Sink Methods - Capability for Deinitializing zeigt eine Struktur, in der der Typ Computer shutdown() als sink method bereitstellt
    • shutdown() gibt den Speicherinhalt aus und behandelt danach self.ram als sink
    • test1 erstellt einen Computer und fährt ihn nicht herunter, wodurch Cannot deinit computer entsteht
    • test2 ruft shutdown() nur innerhalb von if random_bool() auf, sodass auf dem Pfad ohne Eintritt in das if weiterhin Cannot deinit computer entsteht
    • test3 ruft shutdown() innerhalb von while auf; dadurch entsteht nach der ersten Iteration ein Problem durch die Nutzung eines bereits konsumierten Objekts, und auf Pfaden ohne Eintritt in das while bleibt die fehlende Deinitialisierung bestehen
  • Weitere Beispiele finden sich in der compiler test suite

1 Kommentare

 
GN⁺ 2023-07-19
Hacker-News-Kommentare
  • Als C++-Nachfolger könnte Val vielleicht sogar spannender sein als Herb Sutters hervorragendes CppFront. Ich habe bisher nur die beiden Vorträge unten gesehen, aber statische Kompilierung, statische Typisierung, C++-Interoperabilität, Speichersicherheit, Typsicherheit und keine Data Races scheinen die Kernelemente zu sein
    Wenn ich es erkläre, sage ich etwa: „Wenn man ein neues C++-Projekt startet und annimmt, dass einem Performance egal ist, wäre es dann nicht schön, alles ohne Pointer oder Referenzen per Wert zu übergeben und per Wert zurückzugeben, sodass man sich keine Sorgen über Seiteneffekte oder Data Races machen muss?“ Interessant an Val ist, dass die Sprache Pointer und Referenzen entfernt, der Compiler aber intern trotzdem const-Referenzübergabe und Return-Value-Optimierung anwendet, sodass die gewünschte Semantik und Performance gleichzeitig erhalten bleiben
    Val: A Safe Language to Interoperate with C++ - Dimitri Racordon - CppCon 2022 https://www.youtube.com/watch?v=ws-Z8xKbP4w
    https://cppcast.com/val-and-mutable-value-semantics/

    • Es lohnt sich, die letzten zwei Episoden des ADSP Podcast zu hören, in denen Sean Parent über Val spricht. Adobe Research Labs fördert die Entwicklung offenbar ziemlich ernsthaft
      https://adspthepodcast.com/
    • Bei „Interoperabilität mit C++“ bin ich skeptisch. Ich kann kaum glauben, dass eine andere Sprache wirklich sauber mit C++ interoperieren kann, wenn schon zwischen C++-Compilern die binäre Kompatibilität bricht und sich mitunter sogar Versionen desselben Compilers unterscheiden
    • Das klingt nach einer Architektur, die dem Compiler zu sehr vertraut. Ich frage mich, ob nicht schon eine kleine Änderung die Optimierung in weit entferntem Code kaputtmachen und damit die Performance ruinieren könnte
    • Wenn man „den ganzen Tag per Wert übergibt und per Wert zurückgibt“, wird es viel schwieriger, innerhalb von Strukturen Referenzen effizient zu verändern oder zu speichern. Sobald ein Programm auch nur leicht unübliche oder komplexe Datenstrukturen braucht, wirkt das wie eine fatale Einschränkung. Andererseits könnte genau das auch ein Vorteil sein, wenn man bedenkt, wie schwer solche Datenstrukturen korrekt zu implementieren sind
    • Ich habe PHP-Programme über Jahre in der Praxis genau so geschrieben und Arrays einfach ständig weitergereicht
      Ich nehme an, dass der PHP-Interpreter schlau genug ist, tatsächlich Copy-on-Write zu verwenden, aber ich habe es nie selbst profiliert. Trotzdem hatte ich nie spürbare Performance-Probleme, obwohl ich bei jedem Seitenaufruf recht komplexe Datenverarbeitung, zeichenweises Parsing einer DSL, dynamische SQL-Erzeugung und das Umarbeiten der Ergebnisse in beliebige Strukturen gemacht habe
      Zu PHP-4-Zeiten verhielten sich sogar Objekte wie in Variablen gespeicherte Werte. Als Objektvariablen später auf Referenzsemantik umgestellt wurden, war es meiner Meinung nach eine verpasste Chance, „Wert, Variablenreferenz und Pointer auf einen Wert“ nicht als Variableneigenschaften orthogonal zum Speichertyp zu gestalten
      $a = $b; // kopiert den Wert von $b nach $a
      $a = &$b; // $a und $b sind jetzt dieselbe Variable
      $a = *$b; // $a zeigt auf dasselbe Objekt wie $b, aber anders als bei $a = &$b sind die Variablen selbst nicht verknüpft
  • Einerseits ist es gut, dass so viele Sprachen für Zero-Cost Abstractions auftauchen, aber andererseits hätte ich gern, dass sich Systemprogrammierer langsam auf einen Sieger einigen. Hoffentlich zersplittert die ohnehin kleine Community der Systemprogrammierer nicht noch weiter in Rust, Zig, Val usw., und die Systemsprachenkriege enden bald

    • Vielleicht wurde einfach zu früh eine Wahl getroffen, und deshalb gab es in diesem Bereich so lange zu wenig Innovation. Ich begrüße den Krieg
    • Zum jetzigen Zeitpunkt ist Rust meiner Meinung nach der Sieger. Es hat bereits die enorme Hürde genommen, tatsächlich in den Linux- und Windows-Kernel aufgenommen zu werden. In diesem Sinne scheint es kaum noch Platz für eine weitere neue Systemprogrammiersprache zu geben
    • Ich glaube nicht, dass das passieren wird. Gerade deshalb gibt es umso mehr Grund, wasm + wasi-Support überall breiter auszurollen
  • So verlief heute mein emotionaler Erstkontakt mit Val: „Oh, eine neue Systemprogrammiersprache. Vielleicht nichts Besonderes, aber schauen wir mal. Die Dokumentation ist ordentlich. Die Ideen rund um Ownership sind ziemlich durchdacht, und die Syntax ergibt Sinn. Aber ist es genug anders, um eine eigene Daseinsberechtigung zu haben? Wer macht das eigentlich?“
    Dann sah ich, dass Dave Abrahams daran arbeitet, und mein Interesse stieg. Ich bin ihm bei Apple einmal begegnet und erinnere mich auch an seinen Crusty-Vortrag über Swift[1]. Seine starken Meinungen mochte ich, aber Apple nahm das Video später herunter, mit der Begründung, es enthalte veraltete Ratschläge. Jetzt ist er also bei Adobe; da fragt man sich, ob das so etwas wie eine Adobe-Sprache ist
    Mein Fazit ist: Es lohnt sich, das im Auge zu behalten, und nach dem verlinkten Vortrag erst einmal abzuwarten
    [1] Ich habe den Crusty-Vortrag gefunden: "I don't do Object Oriented!" https://www.youtube.com/watch?v=p3zo4ptMBiQ

    • David Abrahams war schon vor seiner Zeit bei Apple ein sehr wichtiger Mitwirkender an Boost, Mitglied des C++-Komitees und ein starker Verfechter von Stepanov-artiger generischer Programmierung. Dass er beim Val-Projekt eingestiegen ist, überrascht mich nicht
  • Als Compiler-Entwickler war ich schockiert, als ich die folgenden Issues gesehen habe
    https://github.com/val-lang/val/issues/758
    https://github.com/val-lang/val/issues/711
    Das riecht nach einem schlechten Implementierungsstand. Sie sollten so schnell wie möglich self-hosting werden, dann würden sie mehr solcher grundlegenden Bugs finden. Trotzdem haben sie schon über 500 Sterne

    • Aus Sicht eines anderen Compiler-Entwicklers gibt es kaum einen schädlicheren Fehler als self-hosting zu früh anzugehen. Auch wenn eine Sprache bei kleinen bis mittelgroßen Programmen schon klaren Nutzen bringt, dauert es viel länger, bis sie für große Projekte wie einen Compiler geeignet ist und auch das nötige Tooling hat. Gut, dass sie nichts überstürzen
    • Wenn solche Bugs in einem produktiv eingesetzten Compiler stecken würden, wäre das besorgniserregend, aber für einen Compiler einer Sprache, die noch definiert wird, ist es nicht so schlimm. Wenn man Rust 1.0 und 1.71 vergleicht, sieht man, wie groß die Lücke zwischen dem „ersten stabilen Release“ und dem „Compiler einer stabilen Sprache mit viel Praxiseinsatz“ ist
      Self-hosting ist auch nicht alles. Es ist vor allem ein symbolischer Meilenstein; wenn man ihn erreicht, ist das ein Grund zum Feiern, aber ich finde nicht, dass es bis weit später im Entwicklungszyklus als Schwäche der Sprache gelten sollte
    • Auch Swift ist noch nicht self-hosting, obwohl Release 6 bevorsteht. Ich bin kein Compiler-Entwickler, aber das Fazit der Diskussionen in der Swift-Community zu diesem Thema war bisher, dass es sich noch nicht lohnt
  • Ich hatte „mit Val herumspielen“ schon lange aufgeschoben und es heute endlich versucht, aber auch nach über 4.000 Commits ist es noch weit davon entfernt, benutzbar zu sein. Die meisten Beispiele im Sprachüberblick kompilieren nicht, und selbst scheinbar einfache Beispiele schlagen fehl
    Carbon hat noch nichts wirklich Vorzeigbares veröffentlicht, und Sean Baxter macht mit dem Circle-Compiler große Fortschritte und hat schon viele der guten Teile von Carbon umgesetzt. Wenn man noch kaum als Sprache gelten kann, ist es auch schwer, ein Nachfolger zu werden

  • Inzwischen gibt es V, Val, Vala, Vale. Gibt es noch andere Sprachen, die ich vergessen habe?

    • Es gibt auch VAL. Eine Sprache aus den 80ern, die über SISAL Einfluss auf Haskell hatte. Außerhalb der Parallelsprachen-Community dürften allerdings nicht viele dieses VAL kennen
    • Ähnliche Namen können sogar ein Vorteil sein. Wer solche Sprachen lernt, sucht wahrscheinlich nach dem „neuen heißen Scheiß“ und stößt dann vielleicht auch auf andere Sprachen mit ähnlichem Namen. Bei JavaScript war das auch so, und das Ergebnis war nicht schlecht
    • Ich dachte wirklich, das sei Vale. Der Namenskonflikt ist ziemlich bedauerlich
    • Zusätzlich wird V auch Vlang genannt, und Vale wurde früher ebenfalls Vlang genannt
  • Das kommt zwar jedes Mal zur Sprache, aber das Einzige, was mir an Val nicht gefällt, ist, dass Vale und V ebenfalls neue Systemsprachen sind. Wegen der Namen lassen sich die drei viel zu leicht verwechseln

    • Es gibt auch Vala. Ist zwar in einem etwas anderen Bereich unterwegs, aber wieder eine Sprache mit ähnlichem Namen
    • Ich musste sogar auf den Link klicken, nur um nachzusehen, ob das eine Projection-Sprache oder eine Region-Sprache ist
    • Es gibt auch VAL: Variable Assembly Language https://en.m.wikipedia.org/wiki/Variable_Assembly_Language
  • Dazu gibt es einen verwandten Beitrag. Gibt es noch mehr?
    Val, a new programing language inspired by Swift and Rust - https://news.ycombinator.com/item?id=31788527 - Juni 2022, 19 Kommentare

  • Ich habe das Paper über „mutable value semantics“ überflogen und frage mich, ob ich es richtig verstehe, dass die Autoren vorschlagen, Referenzen und Pointer durch a) verschachtelte Structs und etwas Indirektion sowie Laufzeitprüfungen über Any und b) Array-Indizes zu ersetzen
    Mir fiel die Passage auf: „Es ist berechtigt zu fragen, wie man selbstreferenzielle Datenstrukturen wie doppelt verkettete Listen oder gerichtete Graphen mit veränderlichen Werttypen ausdrücken kann. Tatsächlich lassen sich beliebige Graphen als Adjazenzlisten darstellen …“ Ich sehe nicht so recht, wie man doppelt verkettete Listen vernünftig implementieren soll, ohne innerhalb der Implementierung wieder einen Speicher-Heap und eine Art Garbage Collection nachzubauen
    Außerdem habe ich die Diskussion unter https://github.com/orgs/val-lang/discussions/736 gefunden, und es scheint, als werde es einen Fluchtweg ähnlich wie unsafe in Rust geben. Damit wären zwar alle Probleme lösbar, aber die Frage „Reicht die sichere Teilmenge von Val aus, um praktische Anwendungen zu bauen?“ dürfte noch lange Stoff für Debatten liefern

    • Wenn man Arrays verwendet und statt Pointern Array-Indizes benutzt, kann man sich den Speicher tatsächlich wieder selbst bauen
      Weniger dumm als gedacht ist das deshalb, weil diese Indizes an eine bestimmte Datenstruktur gebunden sind, etwa eine doppelt verkettete Liste oder einen Graphen, und sich daher nicht so leicht manipulieren lassen, um auf andere Teile des Programms zuzugreifen. Das gilt auch dann, wenn der Compiler das prüft, selbst bei dem Versuch, das Programm kaputtzumachen
  • Ich weiß nicht, wie ich die Erklärung des Beispiels auf der Homepage lesen soll. Dort steht: „Es gibt keine unnötigen Allokationen. Das Ergebnis von longer_of ist eine Projektion des längeren Arguments, sodass Änderungen an z durch emphasize direkt den Wert von y verändern. Der Wert wird weder kopiert noch verschoben, wird aber auch nicht als Referenz an emphasize übergeben.“
    Es ist eine Situation, in der ein String-Argument an eine Funktion übergeben und ein Zeichen angehängt wird. Der bestehende String hätte doch eine ursprüngliche Länge sowie eine bestimmte Position und Größe auf dem Stack — ich verstehe nicht, wie das ohne eine neue Kopie von y möglich sein soll. Lässt man vielleicht am Ende des Strings zusätzlichen Puffer für den Fall, dass jemand etwas anhängt? Wenn ja, wie viel Puffer, und warum ist das insgesamt nicht ineffizienter?

    • Ein Präfix von vier Leerzeichen ist nicht für Zitate gedacht, sondern für Code-/Monospace-Blöcke. Auf HN verwendet man für Zitate normalerweise die Konvention > , und das funktioniert auch gut, ohne dass der Parser es speziell behandeln muss
    • Ein unveränderlicher Wert muss nicht zwingend auf dem Stack liegen
      Ich habe allerdings eine ähnliche Frage. Was passiert, wenn man einen 1-GB-String verändert? Ist das Copy-on-Write?
      In 99 % der Fälle kann das vermutlich durch Optimierung verschwinden, aber in dem verbleibenden 1 % scheint mir das eine sehr schwer aufspürbare Performance-Verschlechterung zu sein
    • Meine eigene Antwort ein paar Tage später wäre: Es scheint möglich zu sein, wenn man den veränderten Variablennamen auf dem Stack stillschweigend mit einem neuen, längeren Wert shadowt. Vielleicht ist genau das mit „projection“ gemeint. In diesem Fall ist der Stack bereits allokiert, also findet keine neue Allokation statt. Ich bin weder Sprach- noch Compiler-Experte, daher könnte dieser Begriff dort einfach geläufig sein
    • Weiter unten gibt es noch mehr Erklärung. longer_of ist keine Funktion, sondern ein subscript, und ein subscript gibt keinen Wert zurück, sondern projiziert einen Wert und gibt dem Aufrufer temporäre Lese-/Schreibzugriffsrechte
      Ich verstehe nicht ganz, warum das nicht als Move gilt. Bei Strings könnte man sie wie in Rust auf dem Heap ablegen, um variable Größe zu erlauben