-.NET 9 enthaltene F# 9 reduziert mit Nullable Reference Types und verbesserten Compiler-Diagnosen Sicherheitsprobleme bei der C#/.NET-Interoperabilität
- Mit
.Is*-Eigenschaften für Discriminated Unions, partiellen aktiven Mustern mitbool-Rückgabe und leeren Computation Expressions wird die alltägliche F#-Syntax kompakter - FSharp.Core ergänzt zufallsbasierte Funktionen für Collections und Unterstützung für C#-Collection-Expressions, sodass sich immutable F#-Collections auch in anderem .NET-Code leichter verwenden lassen
- Der Compiler macht Probleme wie falsche Attributverwendung, IL-Methoden mit mehr als 65.520 Einträgen und die Sichtbarkeit von private members früher sichtbar
- Durch Optimierungen bei Gleichheitsprüfungen, Integer-Bereichen und List-/Array-Comprehensions werden einige Schleifen um 1,25× bis 8×, manche Array-Comprehensions um bis zu 10× schneller
F# 9 in .NET 9
- F# 9 enthält Änderungen, die Programme sicherer, robuster und leistungsfähiger machen sollen
- Es ist mit .NET 9 verfügbar, und das aktuelle .NET SDK kann auf der .NET-Downloadseite heruntergeladen werden
- Die wichtigsten Änderungen wurden im F# open source code repository entwickelt
Änderungen bei den Sprachfunktionen
-
Nullable Reference Types
- F# wurde so entworfen, dass
nullvermieden wird, aber bei der Nutzung mit in C# geschriebenen .NET-Bibliotheken kannnullhereinkommen - F# 9 stellt Referenztypen, für die
nullzulässig ist, typsicher dar, etwastring | null - Wenn
nullin einenstringeingefügt wird oder bei einem Wert vom Typstring | nulldirekt auf.Lengthzugegriffen wird, erscheint eine Warnung zur möglichen Nullbarkeit - Wird im Pattern Matching zuerst der
null-Fall behandelt, werden spätere Bindungen als Nicht-Null-Werte behandelt - Um in generischem Code
nullzurückzugeben, ist eine Referenztyp-Einschränkung wie'T : not structnötig - Mehr dazu steht in Nullable Reference Types in F# 9
- F# wurde so entworfen, dass
-
.Is*-Eigenschaften für Discriminated Unions- Discriminated Unions erhalten für jeden Fall automatisch generierte
.Is*-Eigenschaften - Hat der Typ
Contactzum Beispiel die FälleEmailundPhone, kann mitperson.contact.IsEmailgeprüft werden, ob ein bestimmter Fall vorliegt - Bisher musste man dafür Code wie
match-Ausdrücke mitEmail _ -> true | _ -> falseschreiben
- Discriminated Unions erhalten für jeden Fall automatisch generierte
-
bool-Rückgabe bei partiellen aktiven Mustern- Partielle aktive Muster mussten bisher bei erfolgreichem Match
Some ()und bei MisserfolgNonezurückgeben - In F# 9 ist auch eine
bool-Rückgabe erlaubt - Im Beispiel für case-insensitive String-Matches kann das Ergebnis von
String.Equals(..., StringComparison.OrdinalIgnoreCase)direkt zurückgegeben werden
- Partielle aktive Muster mussten bisher bei erfolgreichem Match
-
Erweiterungsmethoden mit Argumenten werden bevorzugt
- Einige .NET-Bibliotheken definieren Erweiterungsmethoden mit demselben Namen wie eingebaute Eigenschaften eines Typs
- F# 9 folgt diesem Muster und wertet bei übergebenen Argumenten statt eines fehlgeschlagenen Typtests die Erweiterungsmethode aus
- Im Beispiel kann die Erweiterungsmethode
X(f: Foo, i: int)mit demselben Namen wie die EigenschaftXvonFooin der Formf.X(1)aufgerufen werden, um Eigenschaftssetzung und Call Chaining zu kombinieren
-
Leere Computation Expressions
- F# 9 unterstützt leere computation expressions
seq { }erzeugt eine leere Sequenz, und in Code wie HTML-DSLs lassen sich leere Blöcke wiep { }ausdrücken- Eine leere Computation Expression führt zu einem Aufruf der
Zero-Methode des Builders - Das ist natürlicher als die bisherige Syntax
builder { () }
Verbesserungen bei Hash-Direktiven und F# Interactive
-
Nicht-String-Argumente für Hash-Direktiven
- Compiler-Hash-Direktiven erlaubten bisher nur String-Argumente in Anführungszeichen
- In F# 9 können Argumente beliebigen Typs übergeben werden
- So lässt sich etwa
#nowarn "0070"statt#nowarn 0070und#time "on"statt#time onschreiben
-
Erweitertes
#helpin F# Interactive- Die Direktive
#helpin F# Interactive zeigt im REPL Dokumentation für Objekte oder Funktionen an - Argumente können ohne Anführungszeichen übergeben werden
- Zum Beispiel zeigt
#help List.map;;Beschreibung, Parameter, Rückgabewert, Beispiele, den vollständigen Namen und Assembly-Informationen an - Mehr dazu steht im Blogbeitrag Enhancing #help in F# Interactive blog post
- Die Direktive
-
FS-Präfix bei#nowarnerlaubt- Bisher führte
#nowarn "FS0057"trotz korrekter Warnungsnummer zum FehlerInvalid warning number 'FS0057' - In F# 9 wird die Warnungsnummer auch mit
FS-Präfix akzeptiert #nowarn 57,#nowarn 0057,#nowarn FS0057sowie die String-Formen"57","0057","FS0057"funktionieren alle- Innerhalb eines Projekts ist es sinnvoll, denselben Stil beizubehalten
- Bisher führte
Verbesserungen bei Compiler-Sicherheit und Diagnosen
-
Warnung bei falscher Position von
[<TailCall>]- F# 9 gibt eine Warnung aus, wenn das Attribut
[<TailCall>]an einer ungeeigneten Stelle verwendet wird - Beispiele sind nichtrekursive Funktionen,
let-gebundene Werte und rekursivelet-gebundene Werte - Solche Attribute beeinflussen das Laufzeitverhalten zwar nicht, können Leser aber verwirren
- F# 9 gibt eine Warnung aus, wenn das Attribut
-
Strengere Anwendung von
AttributeTargets- Der Compiler erzwingt
AttributeTargetsnun korrekt fürlet-Werte, Funktionen, Union-Case-Deklarationen, implizite Konstruktoren,structundclass - Damit lassen sich unauffällige Bugs verhindern, etwa wenn in Xunit-Tests ein
unit-Argument vergessen wird - Bisher wurde
[<Fact>] let ``this test always fails`` = Assert.True(false)vom Test-Runner ignoriert, weil es keine echte Funktion war, unddotnet testlief dadurch erfolgreich durch - Jetzt erscheint der Fehler
error FS0842: This attribute is not valid for use on this language element
- Der Compiler erzwingt
-
Parser-Recovery
- Durch Verbesserungen bei der Parser-Recovery funktionieren Werkzeuge wie Syntax Highlighting auch bei syntaktisch noch unvollständigem Code während der Bearbeitung weiter
- Betroffen sind unter anderem unvollständige
as-Muster, Object Expressions, Enum-Case-Deklarationen, Record-Deklarationen, komplexe Primary-Constructor-Muster, unresolved long identifier, leerematch-Zweige sowie fehlende Union-Case-Felder und Feldtypen
-
Genauere Diagnosemeldungen und Positionen
- F# 9 ergänzt neue Diagnosemeldungen und präzisere Diagnosepositionen
- Dazu gehören mehrdeutige Override-Methoden in Object Expressions, abstract members in nicht-abstrakten Klassen, Eigenschaften mit demselben Namen wie Cases einer Discriminated Union, falsche Argumentanzahl bei aktiven Mustern, Unions mit doppelten Feldern sowie die gemeinsame Verwendung von
use!undand!in Computation Expressions - Für Klassen mit mehr als 65.520 Methoden im erzeugten IL gibt es jetzt einen neuen Compile-Time-Fehler
- Solche Klassen können von der CLR nicht geladen werden und würden sonst zu Laufzeitfehlern führen
-
Option für echte Sichtbarkeit
- F# schreibt private members im IL traditionell als internal, sodass Nicht-F#-Projekte mit
InternalsVisibleTounangemessen auf private members in F#-Projekten zugreifen konnten - F# 9 bietet zur Korrektur dieses Verhaltens das Opt-in-Compiler-Flag
--realsig+ - In
.fsprojkann dafür<RealSig>true</RealSig>ergänzt werden - So lässt sich prüfen, ob eine Lösung vom bisherigen Verhalten abhängt
- F# schreibt private members im IL traditionell als internal, sodass Nicht-F#-Projekte mit
Änderungen in der Standardbibliothek FSharp.Core
-
Zufallsfunktionen für Collections
- Zu den Modulen
List,ArrayundSeqkommen Funktionen für zufälliges Sampling und Mischen hinzu - Das erleichtert die Nutzung von F# in typischen Szenarien mit Zufälligkeit wie Data Science, Machine Learning oder Game Development
- Alle Funktionen gibt es in drei Varianten
- eine Variante mit einer impliziten, threadsicheren gemeinsamen
Random-Instanz - eine Variante, die eine
Random-Instanz als Argument annimmt - eine Variante, die eine benutzerdefinierte
randomizer-Funktion annimmt, diefloat-Werte ab 0.0 und kleiner als 1.0 zurückgeben muss
- eine Variante mit einer impliziten, threadsicheren gemeinsamen
- Verfügbar sind die vier Funktionen
Shuffle,Choice,ChoicesundSample, jeweils in drei Varianten - Die vollständige Liste der Funktionen und Varianten steht in RFC #1135
- Zu den Modulen
-
Verhalten der einzelnen Zufallsfunktionen
Shufflegibt eine neue Collection mit demselben Typ und derselben Größe zurück, deren Elemente gleichmäßig über die Länge der Collection verteilt gemischt werden- Für Arrays gibt es zusätzlich eine
InPlace-Variante, die Elemente innerhalb des bestehenden Arrays mischt Choicegibt ein einzelnes zufälliges Element mit gleichmäßiger Gewichtung über die Größe der Collection zurückChoiceswählt N Elemente in zufälliger Reihenfolge aus der Eingabe-Collection, wobei dasselbe Element mehrfach ausgewählt werden kannSamplewählt N Elemente in zufälliger Reihenfolge aus der Eingabe-Collection aus, ohne dass dasselbe Element zweimal gewählt wird- Bei
Sampledarf N nicht größer als die Länge der Collection sein
-
Parameterloser Konstruktor für
CustomOperationAttributeCustomOperationAttributeerhält einen parameterlosen Konstruktor, wodurch sich benutzerdefinierte Operationen für Computation-Expression-Builder leichter erstellen lassen- Da der explizite Name meist ohnehin dem Methodennamen entspricht, kann statt
[<CustomOperation("bar")>]nun[<CustomOperation>]verwendet werden
-
Unterstützung für C#-Collection-Expressions
- F#-Listen und -Sets lassen sich in C# mit Collection Expressions initialisieren
- Statt
SetModule.FromArray([1, 2, 3])kann zum BeispielFSharpSet<int> mySet = [ 1, 2, 3 ];geschrieben werden - Immutable F#-Collections sind nützlich, wenn strukturelle Gleichheit benötigt wird, die
System.Collections.Immutable-Collections nicht bieten
Performance-Verbesserungen
-
Optimierung von Gleichheitsprüfungen
- Gleichheitsprüfungen sind schneller geworden und verursachen weniger Speicherallokationen
- Im Beispiel für die Suche eines nicht vorhandenen Werts mit
Array.containsin einem Array vonstruct-Typen kam es bisher zu 1.000 Boxings, jetzt zu keinem mehr - In Benchmarks für Array-Funktionen mit einem
structmit 2 Members sank die durchschnittliche Zeit fürArrayContainsNonexistingvon 5.190,95 ns auf 766,005 ns, und die Allokationen gingen von 24.000 B auf 0 zurück ArrayTryFindNonexistingsank von 5.139,58 ns auf 1.140,515 ns, die Allokationen von 24.024 B auf 24 B- Mehr dazu steht in F# Developer Stories: How we’ve finally fixed a 9-year-old performance issue
-
Gemeinsame Feldnutzung bei
struct-Discriminated-Unions- Wenn mehrere Cases einer
struct-Discriminated Union denselben Feldnamen und denselben Typ haben, können sie denselben Speicherbereich teilen - Dadurch sinkt der Speicherverbrauch des
struct - Im Beispiel ist eine
struct-Discriminated Union mit gemeinsam genutztenint64-basierten Feldern 16 Byte groß - Eine Version im bisherigen Stil, bei der jeder Case einen eigenen Feldnamen haben musste, war 60 Byte groß
- Da gleiche Feldnamen früher nicht erlaubt waren, gibt es keine Probleme bei der Binärkompatibilität
- Wenn mehrere Cases einer
-
Optimierung von Integer-Bereichen
- Der Compiler erzeugt nun in mehr Fällen optimierten Code für Ausdrücke der Form
start..finishundstart..step..finish - Bisher wurde nur optimiert, wenn der Typ
int/int32war und der Schritt den konstanten Wert1oder-1hatte - Andere Integer-Typen und andere Schrittwerte verwendeten eine ineffiziente
IEnumerable-basierte Implementierung - Jetzt werden all diese Fälle optimiert
- In
for … in start..finish do …,[start..step..finish]und[for n in start..finish -> f n]ergeben sich Geschwindigkeitsgewinne von 1,25× bis 8×
- Der Compiler erzeugt nun in mehr Fällen optimierten Code für Ausdrücke der Form
-
Optimierung von List- und Array-Comprehensions
- In List- und Array-Comprehensions wird die Form
for x in xs -> …optimiert - Besonders deutlich fällt die Verbesserung bei Arrays aus
- Die Geschwindigkeit steigt um bis zu 10×, und die Allokationsgröße sinkt auf die Hälfte bis ein Viertel
- In List- und Array-Comprehensions wird die Form
Verbesserungen der Visual-Studio-Tools
-
Live Buffers standardmäßig aktiviert
- Die Funktion Live Buffers in Visual Studio war zuvor optional, ist nach ausreichenden Tests nun aber standardmäßig aktiviert
- Der Hintergrund-Compiler, der die IDE antreibt, verwendet nicht gespeicherte Dateipuffer
- Änderungen werden damit übernommen, auch wenn die Datei noch nicht auf die Festplatte gespeichert wurde
- Zuvor konnte es zu unerwartetem Verhalten kommen, wenn Symbole in bearbeiteten, aber noch nicht gespeicherten Dateien umbenannt wurden
-
Code Fix zum Entfernen unnötiger Klammern
- Für unnötige Klammern bietet Visual Studio nun einen Code Fix zum Entfernen an
- So kann etwa
let f (x) = xzulet f x = xundlet _ = (2 * 2) + 3zulet _ = 2 * 2 + 3geändert werden - Ziel ist es, Klammern zu reduzieren, die eher Rauschen als Klarheit erzeugen
-
Unterstützung für benutzerdefinierte Visualisierungen in F#-Projekten
- Visual-Studio-Debugger-Visualisierungen funktionieren jetzt auch in F#-Projekten
-
Signature-Tooltip in der Mitte von Pipelines
- Bisher wurde keine Signature Help angeboten, wenn bei einer Funktion mitten in einer Pipeline bereits komplexe curried Parameter angewendet worden waren
- Jetzt wird ein Signature-Tooltip für den nächsten Parameter angezeigt
1 Kommentare
Hacker-News-Kommentare
F# war seit meiner ersten Begegnung damit an der Universität immer meine Lieblingssprache
Bei Funktionen wie Unions, Null-Sicherheit, Pattern Matching, Records, stärkerer Typinferenz und generischen Constraints war sie C# weit voraus
Es ist gut, dass C# diese Funktionen im Lauf der Zeit ebenfalls eingeführt hat, aber schade, dass sie auf zueinander inkompatible Weise hineingekommen sind
Da die Investitionen in F# viel kleiner sind als in C#, ist es beim Innovationstempo zwar etwas zurückgefallen, aber es ist immer noch eine großartige Sprache, weitgehend mit dem .NET-Ökosystem kompatibel und kann dieselbe Performance wie C# mit deutlich weniger Boilerplate liefern
Wenn man ein zusätzliches C#-Projekt mit dem nötigen „Glue Code“ schreibt, lässt sich das ziemlich einfach handhaben
Ich frage mich, ob es darüber hinaus konkrete Probleme gibt, die du im Sinn hast
F# 9 unterstützt auch die Verwendung von
ref structals generische Argumente, die kürzlich zu C# hinzugefügt wurde, und soweit ich weiß, ist auch geplant, entsprechende Funktionen einzuführen, die in F# selbst definiert werdenBisher hat F# beim Aufholen beeindruckend gute Arbeit geleistet und verdient deutlich mehr Anerkennung
Die Passage „Klassen mit mehr als 65.520 Methoden im erzeugten IL führen jetzt zu einem neuen Compile-Time-Fehler. Solche Klassen können vom CLR nicht geladen werden und verursachen daher einen Runtime-Fehler“ ist kaum vorstellbar
Wie auch immer: F# ist eine großartige Sprache
Nach Excel scheint es mir das Zweitbeste zu sein, was Microsoft hervorgebracht hat, und es macht .NET zu einer vernünftigen Plattform
Es ist relativ leicht Menschen beizubringen, die bereits mit JS oder TS vertraut sind, und ist eine sehr produktive Sprache
Sie wird in vielen Kontexten eingesetzt, von Game-Engines über Enterprise-Backends bis zu Desktop-Apps
Ich denke, Microsoft hat sich anfangs ein paar Fehltritte geleistet und dadurch das Wachstum gebremst, aber als Allzwecksprache ist sie wirklich gut und vergleichsweise leicht zu lernen
Ich habe vor einigen Jahren kurz mit einer leichtgewichtigen IDE namens LINQPad damit herumgespielt, aber seitdem die Vor- und Nachteile oder die Weiterentwicklung nicht weiter verfolgt
https://www.linqpad.net/
Bei Phosphor haben wir über mehrere Jahre hinweg eine große Entscheidung getroffen, die Firma und die technische Richtung auf F# aufzubauen
Nach mehr als einem Jahr des Ausprobierens haben wir die Anwendung vollständig in TypeScript und Rust neu geschrieben
Das Produkt, das wir bauen, ist ein End-User-Programming-Tool, wodurch die traditionellen Frontend-/Backend-Grenzen verschwimmen, und das .NET-Ökosystem passte dafür nicht gut
Ursprünglich wollten wir mit Fable F#-Code nach JS, Rust, .NET usw. kompilieren, um Typsicherheit über mehrere Technologien hinweg zu erhalten und die nötige Interoperabilität zu ermöglichen
In der Praxis war die Interoperabilität zwischen verschiedenen Libraries viel schwieriger als erwartet, und das Verwalten und Aktualisieren der vielen Abhängigkeiten und Bindings war wirklich schmerzhaft
Ich denke weiterhin, dass die Prämisse stimmt, dass F# schönen und effizienten Code erzeugt, aber aufgrund seines Ökosystems und Designs passt es meiner Ansicht nach nur gut zu Anwendungen mit klaren traditionellen Frontend-/Backend-Grenzen
In so einem Fall würde man F# nur im Backend einsetzen
Die Technologien, auf die ich mich derzeit am meisten freue, sind Effect und Moonbit, die wir intern verwenden
Effects Schema-Library schließt viele Lücken im TS-Typsystem, und Moonbit wirkt wie ein modernes F#, das von der MS/.NET-Abhängigkeit befreit ist
Moonbit wurde vom Erfinder von ReScript entworfen, das man als Fable für OCaml bezeichnen kann, ist sehr gut designt und kompiliert direkt zu optimiertem JS, WASM und nativer Ausgabe
Effect nutzen wir in Produktionsumgebungen, Moonbit noch nicht, aber sein Potenzial als Sprache, die für eine AI-first-Welt entwickelt wurde, ist ziemlich beeindruckend
Die zentrale Geschäftslogik und die Validatoren haben wir in F# geschrieben, den Rest der Frontend-App in TypeScript und das Backend in C#
Mit anderen Worten: Nur Kernlogik und Validierung lagen in F#, sämtliche Ein- und Ausgabe übernahmen TS und C#
Ich erinnere mich, dass es ein ähnliches Produkt war und in F# geschrieben wurde, habe die jüngste Entwicklung aber nicht verfolgt
Effect ist ziemlich gut, und ich wünschte, es gäbe so etwas auch für andere Sprachen als TypeScript
MoonBit sieht wie eine eigene proprietäre Programmiersprache aus, daher zögere ich, statt einer bekannten Sprache dorthin zu wechseln; mich würde interessieren, wie du diesen Punkt siehst
Ich hatte einen Kryptografie-Kurs, in dem man jede Sprache wählen konnte, die .NET nutzt, und die Aufgabe, die ich in F# gelöst habe, war viel lesbarer als die der anderen
Ich würde es gern häufiger verwenden, aber Data-Science-Arbeit ist fast zu 100 % Python
Auch F# 9 profitiert von fast allen Performance-Verbesserungen von .NET 9 selbst
Besonders groß sind die Verbesserungen bei der Objekt-Escape-Analyse (object escape analysis)
https://devblogs.microsoft.com/dotnet/performance-improvemen...
Ich vermisse die Zeit, in der ich mit F# gearbeitet habe, wirklich
Es ist eine produktive Sprache, daher macht es schon Spaß, einfach die Updates weiterzuverfolgen
Angesichts der Größe der Community und der gelegentlichen Gleichgültigkeit von Microsoft fand ich die Tool-Unterstützung ziemlich gut
Das größte Ärgernis war die Genauigkeit der Code-Test-Coverage
Ich habe kürzlich ein wenig mit F# herumgespielt, und aus der Perspektive von jemandem, der von Python kommt, gefällt mir wirklich sehr, dass man im REPL alles Mögliche ausprobieren kann.
Ich frage mich, ob erfahrene F#-Entwickler das auch so nutzen.
Diesen Winter möchte ich ein kleines Web-Backend-Projekt bauen, um die Sprache und das Ökosystem besser kennenzulernen.
Für HTTP habe ich gehört, dass Oxpecker gut sein soll; ich frage mich, ob es Empfehlungen für PostgreSQL-Clients oder -Treiber gibt.
ORMs mag ich nicht.
https://lanayx.github.io/Oxpecker/
https://monazita.gitlab.io/monazita/ wurde beim Lernen von F# für persönliche Projekte erstellt; es funktioniert grundsätzlich, hat aber noch Raum für Feinschliff und ist ausschließlich für PostgreSQL gedacht.
https://github.com/jacentino/DbFun ist ausgereifter als das erstgenannte Projekt und unterstützt mehrere Datenbanken.
Dort anzufangen wäre wohl sinnvoll.
Wenn mir eine API nicht klar ist, drücke ich auch innerhalb der eigentlichen Codebasis „Send to F# interactive“, um sie im Modul auszuführen und damit zu experimentieren.
Ich nutze es auch, um neue Libraries auszuprobieren, schnelle Benchmarks zu machen oder als Ersatz für PowerShell-Skripte.
Mit dem Shebang
#!/usr/bin/env -S dotnet fsikann man F#-Skripte ausführbar machen; daher nutze ich es häufig als Alternative zu bash/Python für Skripte rund um .NET-Projekte, in denen das dotnet-sdk ohnehin schon installiert ist.Meist läuft es schneller und ist im Allgemeinen ebenso knapp.
Mein persönlicher Eindruck ist, dass Syntax und Idiome von F# besser als C# zu REPL-Programmierung passen, bei der man kleine Code-Stücke zusammensetzt.
C# braucht normalerweise mehr objektorientierte Struktur.
Ich frage mich, wie die Versionierung von F# gehandhabt wird.
Es gibt viele Verbesserungen der Lebensqualität, die gut aussehen, aber aus Sicht von Semantic Versioning gibt es keine Breaking Changes, sodass ein Major-Version-Sprung nicht gerechtfertigt wirkt; und für ein Projekt, das kein Semantic Versioning nutzt, scheint es auch kein so großer Sprung bei den Sprachfeatures zu sein, dass man von 8 auf 9 gehen müsste.
In einem anderen Kommentar wurde das kürzlich erschienene .NET 9 erwähnt; ich frage mich, ob es darum geht, mit den .NET-Versionsnummern Schritt zu halten.
Ob der Wechsel absichtlich zu dem Zeitpunkt erfolgte, an dem es mit der .NET-Version zusammenpasste, oder ob das Zufall war, weiß ich nicht.
Zum Beispiel wurde passend zu .NET 9 C# 13 veröffentlicht.
dotnet buildverwendet werden.Dazu gehören msbuild, Compiler, NuGet-Pakete usw.
Das F#-Team hätte zum Beispiel zwischen 8 und 9 Sprachänderungen veröffentlichen können; selbst wenn es das nicht getan hätte, hätte es aus irgendeinem Grund Compiler-Änderungen oder msbuild-Änderungen veröffentlichen können, die .NET 9 erfordern.
Entwickler können ihren Code normalerweise einfach auf die neueste Runtime-Version anheben, sofern sie nicht darauf warten müssen, dass in der Deployment-Umgebung das neueste .NET installiert ist.
Heutzutage ist das dank MSBuild-Änderungen zur Erstellung von self-contained Deployments seltener nötig, aber es ist gut, das zu wissen.
C# liegt allerdings um 4 voraus.
Ich halte Semantic Versioning ohnehin für überbewertet.
Ich frage mich, wie der Stand von F# als Alternative zu C# für die Entwicklung von GUI-Apps unter Windows ist.
Außerdem interessiert mich, ob es Unternehmen gibt, die F# für solche Zwecke einsetzen.
https://github.com/fsprojects/Avalonia.FuncUI
https://fabulous.dev/ zielt auf Avalonia/MAUI/Xamarin ab.
https://github.com/kekyo/epoxy unterstützt Avalonia und WPF.
Wenn dich interessiert, ob Unternehmen das für solche Zwecke nutzen, kann ich mich umhören.
Ich habe F# selbst noch nie ausprobiert, aber beim Stöbern wirkte diese Ressource hervorragend: https://fsharpforfunandprofit.com/
Sie ist sowohl für erfahrene C#-Entwickler als auch für Leute gut, die Programmieren noch relativ neu lernen.
Heutzutage wird sie kaum noch aktualisiert, daher findet man dort nur schwer Diskussionen zu den neuen Features von F# 9, aber die bestehenden Artikel sind ausgezeichnet, um Konzepte wie
applyundbindzu verstehen.