1 points par GN⁺ 2024-11-11 | 1 commentaires | Partager sur WhatsApp

-. F# 9, inclus dans .NET 9, réduit les problèmes de sûreté liés à l’interopérabilité avec C#/.NET grâce aux types référence nullable et à de meilleurs diagnostics du compilateur

  • Les propriétés .Is* sur les unions discriminées, les active patterns partiels renvoyant un bool et les computation expressions vides rendent la syntaxe F# du quotidien plus concise
  • FSharp.Core ajoute des fonctions aléatoires sur les collections et la prise en charge des expressions de collection C#, ce qui facilite l’usage des collections immuables F# depuis d’autres codes .NET
  • Le compilateur signale plus tôt des problèmes comme l’usage incorrect d’attributs, les méthodes IL au-delà de 65 520 éléments ou la visibilité des membres private
  • Grâce aux optimisations sur les tests d’égalité, les plages d’entiers et les compréhensions de listes et de tableaux, certaines boucles deviennent 1,25× à 8× plus rapides, et certaines compréhensions de tableaux jusqu’à 10×

F# 9 dans .NET 9

  • F# 9 inclut des changements destinés à rendre les programmes plus sûrs, plus robustes et plus performants
  • Il est disponible avec .NET 9, et le dernier SDK .NET peut être téléchargé depuis la page de téléchargement de .NET
  • Les principaux changements sont développés dans le dépôt open source du code F#

Évolutions du langage

  • Types référence nullable

    • F# a été conçu pour éviter null, mais null peut arriver lorsqu’on l’utilise avec des bibliothèques .NET écrites en C#
    • F# 9 permet d’exprimer de façon sûre au niveau du type des types référence où null est valide, comme string | null
    • Un avertissement de nullabilité est émis si l’on assigne null à un string ou si l’on accède directement à .Length sur une valeur de type string | null
    • Si le cas null est traité en premier dans un pattern matching, les liaisons suivantes sont ensuite considérées comme non nulles
    • Dans du code générique, retourner null nécessite une contrainte de type référence comme 'T : not struct
    • Plus de détails dans Nullable Reference Types in F# 9
  • Propriétés .Is* sur les unions discriminées

    • Les unions discriminées disposent de propriétés .Is* générées automatiquement pour chaque cas
    • Par exemple, si le type Contact possède les cas Email et Phone, on peut vérifier un cas précis avec person.contact.IsEmail
    • Auparavant, il fallait écrire un match du type Email _ -> true | _ -> false pour faire la même vérification
  • Retour bool pour les active patterns partiels

    • Les active patterns partiels devaient auparavant renvoyer Some () en cas de correspondance et None en cas d’échec
    • F# 9 autorise désormais aussi un retour de type bool
    • Dans un exemple de correspondance de chaînes insensible à la casse, on peut renvoyer directement le résultat de String.Equals(..., StringComparison.OrdinalIgnoreCase)
  • Priorité aux méthodes d’extension en présence d’arguments

    • Certaines bibliothèques .NET définissent des méthodes d’extension portant le même nom qu’une propriété native du type
    • F# 9 s’aligne sur ce modèle et, lorsqu’un argument est fourni, résout une méthode d’extension au lieu d’échouer à la vérification de type
    • Dans l’exemple, la propriété X de Foo et la méthode d’extension du même nom X(f: Foo, i: int) peuvent permettre un appel sous la forme f.X(1) pour combiner affectation de propriété et chaînage d’appels
  • Computation expressions vides

    • F# 9 prend en charge les computation expressions vides
    • seq { } crée une séquence vide, et des codes comme une DSL HTML peuvent exprimer un bloc vide avec p { }
    • Une computation expression vide se traduit par un appel à la méthode Zero du builder
    • La syntaxe est plus naturelle que l’ancien builder { () }

Améliorations des directives hash et de F# Interactive

  • Arguments non chaîne pour les directives hash

    • Les directives hash du compilateur n’acceptaient auparavant que des arguments de type chaîne entre guillemets
    • En F# 9, elles peuvent recevoir des arguments de type arbitraire
    • On peut ainsi écrire #nowarn 0070 au lieu de #nowarn "0070", ou #time on au lieu de #time "on"
  • #help enrichi dans F# Interactive

    • La directive #help de F# Interactive affiche dans le REPL la documentation d’un objet ou d’une fonction
    • L’argument peut être fourni sans guillemets
    • Par exemple, #help List.map;; affiche la description, les paramètres, la valeur de retour, des exemples, le nom complet et les informations d’assembly
    • Plus de détails dans le billet Enhancing #help in F# Interactive blog post
  • Préfixe FS accepté dans #nowarn

    • Auparavant, écrire #nowarn "FS0057" provoquait l’erreur Invalid warning number 'FS0057' même si le numéro d’avertissement était correct
    • F# 9 accepte désormais les numéros d’avertissement avec le préfixe FS
    • #nowarn 57, #nowarn 0057, #nowarn FS0057 ainsi que les formes chaîne "57", "0057", "FS0057" fonctionnent toutes
    • Il est préférable de conserver le même style dans un projet

Améliorations de sûreté et de diagnostic du compilateur

  • Avertissement sur les emplacements invalides de [<TailCall>]

    • F# 9 émet un avertissement lorsque l’attribut [<TailCall>] est appliqué à un emplacement inapproprié
    • Les exemples incluent une fonction non récursive, une valeur liée par let, ou une valeur liée par let récursif
    • Ces attributs n’ont pas d’effet sur le comportement du code, mais peuvent induire en erreur les lecteurs
  • Renforcement de l’application de AttributeTargets

    • Le compilateur applique désormais correctement AttributeTargets sur les valeurs let, les fonctions, les déclarations de cas d’union, les constructeurs implicites, les struct et les class
    • Cela permet d’éviter des bugs discrets, comme dans des tests Xunit lorsqu’on oublie l’argument unit
    • Auparavant, [<Fact>] let ``this test always fails`` = Assert.True(false) n’était pas une vraie fonction, donc le test runner l’ignorait, et dotnet test passait
    • Désormais, l’erreur error FS0842: This attribute is not valid for use on this language element est émise
  • Récupération du parseur

    • Les améliorations de récupération du parseur permettent aux outils comme la coloration syntaxique de continuer à fonctionner même sur du code incomplet en cours d’édition
    • Cela couvre notamment des motifs as incomplets, des object expressions, des déclarations de cas enum, des déclarations record, des patterns complexes de constructeur principal, des identifiants longs non résolus, des clauses match vides, ainsi que des champs et types de champs manquants dans des cas d’union
  • Précision des messages et emplacements de diagnostic

    • F# 9 ajoute de nouveaux messages de diagnostic et améliore la précision de leur emplacement
    • Cela concerne notamment les méthodes override ambiguës dans les object expressions, les membres abstraits dans une classe non abstraite, les propriétés ayant le même nom qu’un cas d’union discriminée, les désaccords sur le nombre d’arguments d’un active pattern, les unions avec champs dupliqués, ou l’usage combiné de use! et and! dans une computation expression
    • Une nouvelle erreur à la compilation apparaît lorsque le code IL généré comporte une classe avec plus de 65 520 méthodes
    • Une telle classe ne peut pas être chargée par le CLR et conduirait à une erreur à l’exécution
  • Option de visibilité réelle

    • F# a la particularité d’écrire les membres private en internal dans l’IL, ce qui permettait à des projets non F#, accessibles via InternalsVisibleTo, d’accéder de façon inappropriée à des membres private de projets F#
    • F# 9 introduit pour corriger ce comportement un drapeau du compilateur opt-in, --realsig+
    • Dans un .fsproj, on peut l’activer avec <RealSig>true</RealSig>
    • Cela permet de vérifier si une solution dépend du comportement précédent

Évolutions de la bibliothèque standard FSharp.Core

  • Fonctions aléatoires sur les collections

    • Les modules List, Array et Seq reçoivent des fonctions de mélange et d’échantillonnage aléatoire
    • Cela facilite l’usage de F# dans des scénarios courants nécessitant de l’aléatoire, comme la data science, le machine learning ou le développement de jeux
    • Toutes les fonctions existent en trois variantes
      • une variante utilisant une instance partagée de Random, implicite et thread-safe
      • une variante recevant une instance de Random en argument
      • une variante recevant une fonction randomizer personnalisée censée renvoyer un float supérieur ou égal à 0.0 et strictement inférieur à 1.0
    • Quatre fonctions sont proposées : Shuffle, Choice, Choices et Sample, chacune en trois variantes
    • La liste complète des fonctions et variantes est disponible dans RFC #1135
  • Comportement des fonctions aléatoires

    • Shuffle renvoie une nouvelle collection de même type et de même taille, dont les éléments sont mélangés avec une pondération uniforme sur la longueur de la collection
    • Pour les tableaux, une variante InPlace mélange directement les éléments dans le tableau existant
    • Choice renvoie un unique élément aléatoire avec une pondération uniforme sur la taille de la collection
    • Choices sélectionne N éléments de la collection d’entrée dans un ordre aléatoire, avec possibilité de sélectionner plusieurs fois le même élément
    • Sample sélectionne N éléments de la collection d’entrée dans un ordre aléatoire, sans jamais choisir deux fois le même élément
    • Dans Sample, N ne peut pas être supérieur à la longueur de la collection
  • Constructeur sans argument pour CustomOperationAttribute

    • Un constructeur sans argument a été ajouté à CustomOperationAttribute, ce qui facilite la création d’opérations personnalisées pour les computation expression builders
    • Dans la plupart des cas, le nom explicite est identique au nom de la méthode ; on peut donc écrire [<CustomOperation>] au lieu de [<CustomOperation("bar")>]
  • Prise en charge des expressions de collection C#

    • Depuis C#, les listes et ensembles F# peuvent être initialisés avec des expressions de collection
    • Par exemple, au lieu de SetModule.FromArray([1, 2, 3]), on peut écrire FSharpSet<int> mySet = [ 1, 2, 3 ];
    • Les collections immuables F# peuvent être utiles lorsqu’on a besoin d’une égalité structurelle absente des collections System.Collections.Immutable

Améliorations de performances

  • Optimisations des tests d’égalité

    • Les tests d’égalité sont plus rapides et provoquent moins d’allocations mémoire
    • Dans un exemple de recherche d’une valeur absente avec Array.contains sur un tableau de struct, 1 000 opérations de boxing étaient auparavant effectuées, ce n’est plus le cas
    • Dans un benchmark de fonctions de tableau sur une struct à 2 membres, le temps moyen de ArrayContainsNonexisting passe de 5 190.95ns à 766.005ns, et les allocations de 24 000B à 0
    • ArrayTryFindNonexisting passe de 5 139.58ns à 1 140.515ns, et les allocations de 24 024B à 24B
    • Plus de détails dans F# Developer Stories: How we’ve finally fixed a 9-year-old performance issue
  • Mutualisation des champs des unions discriminées struct

    • Lorsque plusieurs cas d’une union discriminée struct ont des champs de même nom et de même type, ils peuvent partager le même emplacement mémoire
    • Cela réduit l’empreinte mémoire de la struct
    • Dans l’exemple, une union discriminée struct partageant des champs basés sur le même int64 occupe 16 octets
    • Une version précédente utilisant des noms de champs distincts pour chaque cas occupait 60 octets
    • Comme les mêmes noms de champs n’étaient pas autorisés auparavant, cela ne pose pas de problème de compatibilité binaire
  • Optimisation des plages d’entiers

    • Le compilateur génère désormais du code optimisé dans davantage de cas pour les expressions start..finish et start..step..finish
    • Auparavant, seules les plages de type int/int32 avec un pas constant de 1 ou -1 étaient optimisées
    • Les autres types entiers et les autres valeurs de pas utilisaient une implémentation inefficace fondée sur IEnumerable
    • Tous ces cas sont désormais optimisés
    • Dans for … in start..finish do …, [start..step..finish] et [for n in start..finish -> f n], les gains vont de 1,25× à 8×
  • Optimisation des compréhensions de listes et de tableaux

    • Les compréhensions de listes et de tableaux de la forme for x in xs -> … sont optimisées
    • Les améliorations sont particulièrement marquées pour les tableaux
    • La vitesse peut être multipliée jusqu’à 10×, et les allocations réduites de moitié à un quart

Améliorations des outils Visual Studio

  • Activation par défaut des live buffers

    • La fonctionnalité live buffers de Visual Studio était auparavant optionnelle, mais elle est désormais activée par défaut après avoir été suffisamment testée
    • Le compilateur en arrière-plan qui alimente l’IDE utilise désormais les buffers de fichiers non enregistrés
    • Les modifications sont donc prises en compte sans qu’il soit nécessaire d’enregistrer le fichier sur disque
    • Auparavant, renommer un symbole présent dans un fichier modifié mais non enregistré pouvait provoquer un comportement inattendu
  • Correctif pour supprimer les parenthèses inutiles

    • Visual Studio propose désormais un correctif pour supprimer les parenthèses inutiles
    • Par exemple, let f (x) = x peut devenir let f x = x, et let _ = (2 * 2) + 3 peut devenir let _ = 2 * 2 + 3
    • L’objectif est de réduire les parenthèses qui relèvent davantage du bruit que de la clarté
  • Prise en charge des visualiseurs personnalisés dans les projets F#

    • Les visualiseurs du débogueur Visual Studio fonctionnent désormais aussi dans les projets F#
  • Info-bulle de signature au milieu d’un pipeline

    • Auparavant, l’aide sur les signatures n’était pas fournie lorsqu’une fonction au milieu d’un pipeline avait déjà reçu des paramètres curryfiés complexes
    • Désormais, une info-bulle de signature s’affiche pour le paramètre suivant

1 commentaires

 
GN⁺ 2024-11-11
Commentaires sur Hacker News
  • F# est resté mon langage préféré depuis ma première découverte à l’université
    Il était très en avance sur C# sur des fonctionnalités comme les discriminated unions, la sécurité vis-à-vis des null, le pattern matching, les records, une inférence de types plus puissante et les contraintes génériques
    C’est bien que C# ait fini par adopter ce genre de fonctionnalités avec le temps, mais c’est dommage qu’elles aient été intégrées d’une manière incompatible entre elles
    Comme les investissements dans F# sont bien plus faibles que dans C#, il a aussi pris du retard en matière de rythme d’innovation, mais cela reste un excellent langage, globalement compatible avec l’écosystème .NET, et capable d’offrir les mêmes performances que C# avec bien moins de boilerplate

    • L’essentiel des incompatibilités peut probablement se résumer aux source generators et aux autres outils fondés sur la génération de code
      On peut s’en sortir assez facilement en écrivant un projet C# auxiliaire qui contient le « code de glue » nécessaire
      Je me demande s’il y a d’autres problèmes précis que vous avez en tête
      F# 9 prend aussi en charge l’utilisation d’arguments génériques ref struct, ajoutée récemment à C#, et si j’ai bien compris il est aussi prévu d’introduire des fonctionnalités définies côté F# lui-même
      Jusqu’ici, ils ont fait un travail impressionnant pour rattraper leur retard, et ça mériterait bien plus de reconnaissance
  • Le passage disant que « les classes générées en IL avec plus de 65 520 méthodes produisent désormais une nouvelle erreur à la compilation. Ces classes ne peuvent pas être chargées par le CLR et provoqueraient sinon une erreur à l’exécution » est difficile à imaginer
    Quoi qu’il en soit, F# est un excellent langage
    C’est sans doute la deuxième meilleure chose sortie de Microsoft après Excel, et il rend .NET raisonnable comme plateforme

    • Je trouve que C# est assez sous-estimé
      C’est relativement facile à enseigner à des gens déjà familiers de JS ou TS, et c’est aussi un langage très productif
      Il est utilisé dans des contextes variés, des moteurs de jeu aux backends d’entreprise en passant par les applications desktop
      Je pense que Microsoft a ralenti sa croissance avec quelques erreurs au début, mais comme langage généraliste c’est vraiment solide et relativement simple à apprendre
    • Je serais curieux de savoir quels sont selon vous les inconvénients de F#
      Je l’avais essayé rapidement il y a quelques années via LINQPad, un IDE léger, mais je n’ai pas vraiment suivi depuis ses avantages, ses défauts ou son évolution
      https://www.linqpad.net/
  • Chez Phosphor, nous avons pris la grosse décision stratégique de miser l’entreprise et notre orientation technique sur F# pendant plusieurs années
    Après plus d’un an d’essais, nous avons finalement réécrit entièrement l’application en TypeScript et Rust
    Le produit que nous construisons est un outil de programmation pour utilisateurs finaux, donc la séparation frontend/backend traditionnelle y est floue, et l’écosystème .NET ne s’y prêtait pas très bien
    À l’origine, nous voulions utiliser Fable pour compiler le code F# vers JS, Rust, .NET, etc., afin de préserver la sûreté des types entre plusieurs technologies et assurer l’interopérabilité nécessaire
    En pratique, l’interopérabilité entre plusieurs bibliothèques s’est révélée bien plus difficile que prévu, et la gestion ainsi que la mise à jour de multiples dépendances et bindings ont été vraiment pénibles
    Je pense toujours qu’il est vrai que F# permet d’écrire un code élégant et efficace, mais, du fait de son écosystème et de sa manière d’être conçu, il me semble surtout bien adapté aux applications où la frontière frontend/backend traditionnelle reste claire
    Dans ce cas, je n’utiliserais F# que pour le backend
    Les technologies qui m’enthousiasment le plus en ce moment sont Effect et Moonbit, que nous utilisons en interne
    La bibliothèque Schema d’Effect comble beaucoup de lacunes du système de types de TS, et Moonbit ressemble à une version moderne de F# affranchie de la dépendance à MS/.NET
    Moonbit a été conçu par le créateur de ReScript, qu’on peut voir comme un Fable pour OCaml, et il est très bien pensé, avec une compilation directe vers du JS optimisé, du WASM et du natif
    Nous utilisons Effect en production mais pas encore Moonbit, néanmoins son potentiel comme langage conçu pour un monde AI-first est assez remarquable

    • Compiler du code F# pour l’exposer sous forme de modules TypeScript a été une bonne expérience
      La logique métier centrale et les validateurs étaient écrits en F#, tandis que le reste de l’application frontend était en TypeScript et le backend en C#
      Autrement dit, seule la logique cœur et la validation étaient en F#, tandis que toutes les entrées/sorties étaient gérées par TS et C#
    • Je me demande si votre entreprise a un lien avec Darklang
      C’était un produit similaire, si je me souviens bien écrit en F#, mais je n’ai pas suivi son actualité récemment
      Effect a l’air vraiment bien, et j’aimerais qu’il existe aussi pour d’autres langages que TypeScript
      MoonBit donne l’impression d’être son propre langage propriétaire, donc j’hésiterais à migrer vers ça plutôt que vers un langage plus connu ; je serais curieux de savoir comment vous voyez cet aspect
  • J’avais un cours de cryptographie où l’on pouvait choisir n’importe quel langage tournant sur .NET, et un devoir fait en F# était bien plus lisible que ceux des autres
    J’aimerais en faire plus souvent, mais pour la data science c’est presque 100 % Python

  • F# 9 bénéficie lui aussi de presque toutes les améliorations de performances de .NET 9 lui-même
    En particulier, les progrès du côté de l’object escape analysis sont importants
    https://devblogs.microsoft.com/dotnet/performance-improvemen...

  • L’époque où je travaillais en F# me manque vraiment
    C’est un langage très productif, donc même simplement suivre ses mises à jour reste agréable
    Compte tenu de la taille de la communauté et du désintérêt que Microsoft semble parfois lui porter, je trouve que le support outillage était plutôt bon
    Le plus gros point de friction pour moi, c’était la précision de la couverture de tests du code

  • J’ai récemment un peu touché à F#, et en venant de Python, j’aime vraiment le fait de pouvoir expérimenter toutes sortes de choses avec le REPL
    Je me demande si les développeurs F# expérimentés l’utilisent aussi de cette façon
    Cet hiver, j’aimerais créer un petit projet de backend web pour mieux découvrir le langage et son écosystème
    J’ai entendu dire qu’Oxpecker était bien côté HTTP, mais je me demande s’il y a des recommandations pour un client ou un driver PostgreSQL
    Je n’aime pas les ORM
    https://lanayx.github.io/Oxpecker/

    • Il y a deux possibilités
      https://monazita.gitlab.io/monazita/ a été créé en apprenant F# pour un projet personnel ; ça fonctionne globalement, mais il y a encore de la marge pour le peaufiner, et c’est spécifique à PostgreSQL
      https://github.com/jacentino/DbFun est plus abouti que le projet précédent et prend en charge plusieurs bases de données
    • Npgsql est un driver C# populaire, et il existe aussi des wrappers F#
      Ce serait probablement un bon point de départ
    • En tant que développeur utilisant plusieurs langages, il m’arrive d’avoir l’occasion d’utiliser F#, et je fais la plupart de mes preuves de concept dans le REPL
      Si une API n’est pas claire, je clique même sur « Send to F# interactive » directement dans la base de code pour exécuter et expérimenter dans le module
      Je m’en sers aussi pour tester de nouvelles bibliothèques, faire des benchmarks rapides ou remplacer des scripts PowerShell
      Avec le shebang #!/usr/bin/env -S dotnet fsi, on peut rendre des scripts F# exécutables ; je l’utilise donc souvent comme alternative à bash/Python pour des scripts autour de projets .NET où le dotnet-sdk est déjà installé
      En général, c’est plus rapide à exécuter et en gros tout aussi concis
      J’ai personnellement l’impression que la syntaxe et les idiomes de F# se prêtent mieux que ceux de C# à la programmation en REPL, où l’on assemble de petits morceaux de code
      C# demande en général davantage de structure orientée objet
  • Je me demande comment fonctionne la gestion des versions de F#
    Il y a beaucoup d’améliorations de qualité de vie qui ont l’air intéressantes, mais du point de vue du versionnement sémantique, il ne semble pas y avoir de rupture de compatibilité justifiant un changement de version majeure, et cela ne ressemble pas non plus à un saut de fonctionnalités du langage assez important pour passer de 8 à 9 dans un projet qui n’utilise pas le versionnement sémantique
    Un autre commentaire parlait de la sortie récente de .NET 9 ; je me demande si c’est pour aligner la numérotation sur celle de .NET

    • .NET et C# semblent avoir adopté depuis quelque temps un rythme de sortie annuel avec une incrémentation d’une unité, et F# semble suivre la même logique
      Je ne sais pas si le passage a été fait volontairement pour coïncider avec la version de .NET, ou si c’est une coïncidence
      Par exemple, C# a sorti C# 13 en même temps que .NET 9
    • En C# comme en F#, la version de .NET désigne la version des outils de build utilisés quand on exécute dotnet build
      Cela inclut msbuild, les compilateurs, les packages NuGet, etc.
      Par exemple, l’équipe F# aurait pu publier des changements de langage entre 8 et 9, mais même sans cela, elle aurait pu avoir besoin de changements de compilateur ou de msbuild nécessitant .NET 9 pour d’autres raisons
      En général, les développeurs peuvent simplement faire évoluer leur code vers la version la plus récente du runtime, sauf s’ils doivent attendre que le dernier .NET soit installé dans leur environnement de déploiement
      De nos jours, les changements de MSBuild permettant de créer des déploiements autonomes réduisent aussi ce besoin, mais c’est bon à savoir
    • Une nouvelle version de .NET sort chaque année, et les versions de C# et F# s’alignent sur ce cycle annuel
      Cela dit, C# a 4 versions d’avance
      De toute façon, le versionnement sémantique est à mon avis surestimé
  • Je me demande quel est l’état de F# comme alternative à C# pour créer des applications GUI sous Windows
    Je me demande aussi s’il existe des entreprises qui utilisent F# pour ce type de cas

  • Je n’ai jamais vraiment essayé F# moi-même, mais en parcourant le sujet, cette ressource m’a semblé excellente : https://fsharpforfunandprofit.com/

    • Pour quelqu’un qui découvre F#, c’est vraiment l’un des meilleurs sites
      Il convient aussi bien aux développeurs C# expérimentés qu’aux personnes qui apprennent encore relativement la programmation
      Il est peu mis à jour ces temps-ci, donc il est difficile d’y trouver une discussion sur les nouveautés de F# 9, mais les articles existants sont excellents pour comprendre des concepts comme apply et bind