IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Vous êtes nouveau sur Developpez.com ? Créez votre compte ou connectez-vous afin de pouvoir participer !

Vous devez avoir un compte Developpez.com et être connecté pour pouvoir participer aux discussions.

Vous n'avez pas encore de compte Developpez.com ? Créez-en un en quelques instants, c'est entièrement gratuit !

Si vous disposez déjà d'un compte et qu'il est bien activé, connectez-vous à l'aide du formulaire ci-dessous.

Identifiez-vous
Identifiant
Mot de passe
Mot de passe oublié ?
Créer un compte

L'inscription est gratuite et ne vous prendra que quelques instants !

Je m'inscris !

Microsoft annonce que le langage de programmation F# 10 est disponible avec .NET 10 et Visual Studio 2026, apportant des améliorations axées sur la clarté, la cohérence et les performances

Le , par Alex

0PARTAGES

3  0 
F# 10 est désormais disponible avec .NET 10 et Visual Studio 2026. Cette version est une version améliorée axée sur la clarté, la cohérence et les performances, apportant des améliorations modestes mais significatives qui rendent votre code quotidien plus lisible et plus robuste. Avec F# 10, Microsoft poursuit sa démarche visant à simplifier le langage et à améliorer ses performances.

F# est un langage de programmation fonctionnel, impératif et orienté objet pour la plate-forme .NET. F# est développé par Microsoft Research et son noyau est dérivé du langage OCaml, avec lequel il est fortement compatible. Ces deux langages de programmation font partie de la même famille que les langages ML. Ce langage a été conçu spécifiquement pour la plate-forme .NET, donc fortement orienté-objet. Depuis novembre 2010, Microsoft a mis à la disposition de tous les bibliothèques core et son compilateur F#, sous la licence Apache 2.

Récemment, Microsoft a annoncé la dernière version de son framework logiciel .NET 10, apportant des améliorations au compilateur JIT, des améliorations NativeAOT, ainsi que l'optimisation du runtime. Il s'agit d'une version à support à long terme (LTS) qui devrait recevoir des mises à jour jusqu'en novembre 2028. Selon Microsoft, .NET 10 est la version la plus productive, moderne, sécurisée, intelligente et performante de .NET à ce jour.

F# 10 est désormais disponible avec .NET 10 et Visual Studio 2026. Cette version est une version améliorée axée sur la clarté, la cohérence et les performances, apportant des améliorations modestes mais significatives qui rendent votre code quotidien plus lisible et plus robuste.

Avec F# 10, Microsoft poursuit sa démarche visant à simplifier le langage et à améliorer ses performances. Les principales améliorations ergonomiques comprennent la suppression des avertissements dans un certain périmètre, une syntaxe plus cohérente pour les expressions de calcul et une meilleure prise en charge des accesseurs de propriétés automatiques. Cette version comprend également une mise à niveau de l'infrastructure afin d'accélérer la compilation et les outils interactifs sous la forme d'un nouveau cache de subsomption de types.


Améliorations du langage

1. Suppression des avertissements dans une portée donnée

La première fonctionnalité que je souhaite présenter pour F# 10 est très demandée : la possibilité de supprimer les avertissements dans des sections de code arbitraires. Le compilateur prend désormais en charge la directive #warnon, qui s'associe à #nowarn pour activer ou désactiver les avertissements dans une plage de code spécifique.

Un exemple :

Code F# : Sélectionner tout
1
2
3
// We know f is never called with a None. 
let f (Some a) =    // creates warning 25, which we want to suppress 
    // 2000 loc, where the incomplete match warning is beneficial


Il est possible d'ajouter une directive #nowarn 25 juste au-dessus de la définition de la fonction, mais sans une directive #warnon 25 correspondante, cela désactivera l'avertissement FS0025 dans le reste du fichier, risquant ainsi de supprimer des problèmes légitimes ailleurs.

Avec F# 10, vous pouvez délimiter explicitement la section, en appliquant la suppression des avertissements à une portée aussi étroite qu'une seule ligne :

Code F# : Sélectionner tout
1
2
3
4
#nowarn 25 
let f (Some x) =    // FS0025 suppressed 
#warnon 25 
    // FS0025 enabled again


À l'inverse, si un avertissement est désactivé globalement (par exemple, via un indicateur du compilateur), vous pouvez l'activer localement avec #warnon. Cette directive s'appliquera alors jusqu'à ce qu'une directive #nowarn correspondante soit rencontrée ou jusqu'à la fin du fichier.

Compatibilité :

Cette fonctionnalité s'accompagne de plusieurs modifications qui améliorent la cohérence des directives #nowarn/#warnon, ce qui se traduit par un comportement plus prévisible. Cependant, il s'agit de modifications importantes qui pourraient affecter votre base de code lorsque vous passerez à F# 10. Voici quelques exemples parmi les plus susceptibles de se produire :

- Les directives d'avertissement multilignes et vides ne sont plus autorisées.
- Les espaces entre # et nowarn ne sont plus autorisés.
- Les chaînes à triple guillemet, interpolées ou littérales ne peuvent pas être utilisées pour les numéros d'avertissement.

Le comportement des scripts est également affecté. Dans les versions précédentes, une directive #nowarn placée n'importe où dans un script s'appliquait à l'ensemble de la compilation. Désormais, son comportement dans les scripts correspond à celui des fichiers .fs, s'appliquant uniquement jusqu'à la fin du fichier ou jusqu'à une directive #warnon correspondante.

2. Modificateurs d'accès sur les accesseurs de propriétés automatiques

Un modèle fréquent dans la programmation orientée objet consiste à créer un état lisible publiquement mais modifiable en privé. Avant F# 10, pour y parvenir, il fallait utiliser une syntaxe de propriété explicite avec des champs de support, ce qui ajoutait beaucoup de code standard :

Code F# : Sélectionner tout
1
2
3
type Ledger() = 
    [<DefaultValue>] val mutable private _Balance: decimal 
    member this.Balance with public get() = this._Balance and private set v = this._Balance <- v


Avec F# 10, vous pouvez appliquer des modificateurs d'accès distincts à des accesseurs de propriétés individuels. Cela vous permet de spécifier différents niveaux d'accès pour le getter et le setter d'une propriété en ligne, ce qui permet d'utiliser des modèles courants tels que des états lisibles publiquement mais modifiables en privé sans code standard verbeux.

Vous pouvez désormais réécrire ce qui précède comme suit :

Code F# : Sélectionner tout
1
2
type Ledger() = 
    member val Balance = 0m with public get, private set


À noter :

Vous pouvez placer un modificateur d'accès soit avant le nom de la propriété (s'appliquant aux deux accesseurs), soit avant les accesseurs individuels, mais pas les deux simultanément.

De plus, cette fonctionnalité ne s'étend pas aux fichiers de signature (.fsi). La signature correcte pour l'exemple Ledger ci-dessus serait :

Code F# : Sélectionner tout
1
2
3
type Ledger() = 
    member Balance : decimal 
    member private Balance : decimal with set


3. Paramètres facultatifs ValueOption

Les paramètres facultatifs peuvent désormais utiliser une représentation ValueOption<'T> basée sur une structure. En appliquant l'attribut [<Struct>] à un paramètre facultatif, vous pouvez demander au compilateur d'utiliser ValueOption<'T> au lieu du type option basé sur une référence. Cela évite une allocation de mémoire pour le wrapper d'option, ce qui est avantageux dans le code où les performances sont critiques.

Les versions précédentes de F# utilisaient toujours le type option alloué dans le tas pour les paramètres facultatifs, même lorsque le paramètre était absent. Dans les scénarios à haut débit ou la création d'objets en boucle interne, cela imposait une pression inutile sur le GC. Les développeurs travaillant sur du code sensible aux performances n'avaient aucun moyen d'éviter ces allocations :

Code F# : Sélectionner tout
1
2
3
4
5
6
// Prior to F# 10: always uses reference option 
type X() = 
    static member M(?x : string) = 
        match x with 
        | Some v -> printfn "Some %s" v 
        | None -> printfn "None"


Vous pouvez désormais utiliser l'attribut [<Struct>] sur un paramètre facultatif pour tirer parti de ValueOption basé sur une structure et éliminer les allocations lorsque l'argument est absent :

Code F# : Sélectionner tout
1
2
3
4
5
type X() = 
    static member M([<Struct>] ?x : string) = 
        match x with 
        | ValueSome v -> printfn "ValueSome %s" v 
        | ValueNone -> printfn "ValueNone"


Choisissez cette option basée sur une structure pour les petites valeurs ou les types fréquemment construits où la pression d'allocation est importante. Utilisez option par défaut basée sur les références lorsque vous vous appuyez sur des aides de correspondance de modèles existantes, que vous avez besoin d'une sémantique de référence ou lorsque la différence de performances est négligeable. Cette fonctionnalité renforce la parité avec d'autres constructions du langage F# qui prennent déjà en charge ValueOption.

4. Prise en charge des appels en queue dans les expressions de calcul

Les constructeurs d'expressions de calcul (par exemple, les coroutines ou autres constructeurs implémentés avec des machines à états reprenables) peuvent désormais opter pour des optimisations d'appels en queue. Lors du désucrage, le compilateur reconnaît lorsqu'une expression telle que return!, yield! ou do! apparaît en position de queue et, lorsque le constructeur fournit des méthodes spéciales, achemine ces appels vers les points d'entrée optimisés.

Si un générateur implémente :

- ReturnFromFinal, le compilateur l'appellera pour un return! en queue (en revenant à ReturnFrom si la variante finale est absente).

- YieldFromFinal, le compilateur l'appellera pour un yield! en queue (en revenant à YieldFrom s'il est absent).

- Pour un do! terminal, le compilateur préférera ReturnFromFinal, puis YieldFromFinal, avant de revenir à la voie Bind normale.

Ces membres *Final sont facultatifs et existent uniquement pour permettre l'optimisation : ils permettent aux constructeurs de court-circuiter les continuations ou de renoncer prématurément aux ressources. Les constructeurs qui ne fournissent pas ces membres conservent leur sémantique existante inchangée.

Exemples :

Code F# : Sélectionner tout
1
2
3
coroutine { 
    yield! subRoutine() // tail position -> YieldFromFinal if available 
}


Code F# : Sélectionner tout
1
2
3
4
5
coroutine { 
    try 
        yield! subRoutine() // not tail -> normal YieldFrom 
    finally () 
}


Compatibilité :

Cette modification peut être préjudiciable si un constructeur définit déjà des membres avec ces noms. Dans la plupart des cas, elle est rétrocompatible : les constructeurs existants continuent de fonctionner sans modification lorsqu'ils sont compilés avec F# 10. Les anciens compilateurs ignoreront simplement les nouvelles méthodes *Final, de sorte que les constructeurs qui doivent rester compatibles avec les versions antérieures du compilateur ne doivent pas supposer que ces méthodes seront invoquées.

5. Liaisons typées dans les expressions de calcul sans parenthèses

Une incohérence de longue date dans la syntaxe des annotations de type pour les liaisons d'expressions de calcul a été résolue. Vous pouvez désormais ajouter des annotations de type aux liaisons let!, use! et and! sans mettre l'identifiant entre parenthèses.

Les versions précédentes de F# exigeaient des parenthèses pour les annotations de type dans les liaisons d'expressions de calcul. Par exemple, let! (x: int) = fetchA() était valide, mais la forme plus naturelle let! x: int = fetchA() provoquait une erreur. Cela obligeait les développeurs à utiliser des parenthèses visuellement encombrantes, même pour des annotations de type simples :

Code F# : Sélectionner tout
1
2
3
4
5
6
async { 
    let! (a: int) = fetchA() 
    and! (b: int) = fetchB() 
    use! (d: MyDisposable) = acquireAsync() 
    return a + b 
}


Vous pouvez désormais écrire des annotations de type sans parenthèses, conformément au style des liaisons let ordinaires :

Code F# : Sélectionner tout
1
2
3
4
5
6
async { 
    let! a: int = fetchA() 
    and! b: int = fetchB() 
    use! d: MyDisposable = acquireAsync() 
    return a + b 
}


6. Autoriser _ dans les liaisons use!

Les versions précédentes de F# rejetaient le modèle de suppression dans les liaisons use!, même lorsque la valeur de la ressource elle-même n'était jamais référencée. Cette incohérence avec les liaisons use ordinaires obligeait les développeurs à créer des identifiants jetables tels que __ ou _ignored uniquement pour satisfaire le compilateur.

Le modèle de suppression (_) fonctionne désormais dans les liaisons use! au sein des expressions de calcul. F# 10 vous permet d'utiliser _ directement lors de la liaison de ressources asynchrones dont les valeurs ne sont nécessaires que pour la gestion de la durée de vie, sans être obligé de fournir un identifiant nommé.

Vous pouvez désormais utiliser directement le modèle discard, ce qui clarifie votre intention et correspond au comportement de use :

Code F# : Sélectionner tout
1
2
3
4
counterDisposable { 
    use! _ = new Disposable() 
    // logic 
}


7. Rejet des modules pseudo-imbriqués dans les types

La validation structurelle a été renforcée dans cette version afin de rejeter le placement trompeur de modules dans les types. F# 10 génère désormais une erreur lorsqu'une déclaration module apparaît indentée au même niveau structurel dans une définition de type, ce qui évite une source courante de confusion concernant la portée des modules.

Les versions précédentes de F# acceptaient les déclarations module indentées dans les définitions de types, mais ces modules étaient en fait créés comme des éléments frères du type plutôt que d'être imbriqués dans celui-ci. Ce modèle d'indentation induisait souvent les développeurs en erreur en leur faisant croire qu'ils avaient créé un module imbriqué, ce qui entraînait un comportement de portée inattendu :

Code F# : Sélectionner tout
1
2
3
4
5
type U = 
    | A 
    | B 
    module M = // Silently created a sibling module, not nested 
        let f () = ()


Désormais, ce modèle génère l'erreur FS0058, vous obligeant à clarifier votre intention avec un placement correct des modules :

Code F# : Sélectionner tout
1
2
3
4
5
6
type U = 
    | A 
    | B 
  
module M = 
    let f () = ()


8. Avertissement de dépréciation pour seq omis

Un avertissement de dépréciation apparaît désormais pour les expressions de séquence nues qui omettent le constructeur seq. F# 10 vous avertit lorsque vous utilisez des accolades de plage nues telles que { 1..10 } ou des formes similaires, vous encourageant à utiliser la forme explicite seq { ... } pour plus de cohérence avec le modèle d'expression de calcul plus large.

Historiquement, F# autorisait une syntaxe spéciale « sequence comprehension lite » dans laquelle le mot-clé seq pouvait être omis. Cela divergeait du fonctionnement des autres expressions de calcul et créait une incohérence dans le langage :

Code F# : Sélectionner tout
{ 1..10 } |> List.ofSeq  // implicit sequence


Désormais, le compilateur signale ce modèle et encourage l'utilisation de la forme explicite qui clarifie la sémantique :

Code F# : Sélectionner tout
seq { 1..10 } |> List.ofSeq


Il s'agit actuellement d'un avertissement, et non d'une erreur, ce qui vous laisse le temps de mettre à jour votre base de code. La forme explicite seq améliore la clarté du code et sa cohérence avec d'autres expressions de calcul. Les versions futures de F# pourraient en faire une erreur, nous vous recommandons donc d'adopter la syntaxe explicite lors de la mise à jour du code.

9. Application des cibles d'attributs

La validation des cibles d'attributs sera appliquée dans cette version à toutes les constructions du langage. F# 10 vérifie que les attributs ne sont appliqués qu'à leurs cibles prévues en vérifiant les AttributeTargets dans les valeurs liées à let, les fonctions, les cas d'union, les constructeurs implicites, les structures et les classes.

Les versions précédentes de F# autorisaient silencieusement l'application incorrecte d'attributs à des cibles incompatibles. Cela provoquait des bogues subtils, tels que l'ignorance des attributs de test lorsque vous oubliez () pour créer une fonction ou l'inefficacité des directives d'analyseur, ce qui entraînait des divergences CI déroutantes :

Code F# : Sélectionner tout
1
2
3
[<Fact>] 
let ``this is not a function`` =  // Silently ignored, not a test! 
    Assert.True(false)


Désormais, le compilateur applique les cibles d'attributs et génère un avertissement lorsque les attributs sont mal appliqués :

Code F# : Sélectionner tout
1
2
3
4
[<Fact>] 
//^^^^ - warning FS0842: This attribute cannot be applied to property, field, return value. Valid targets are: method 
let ``works correctly`` = 
    Assert.True(true)


Compatibilité :

Il s'agit d'un changement radical qui peut révéler des problèmes auparavant silencieux dans votre base de code. Les erreurs précoces empêchent les problèmes de découverte de tests et garantissent que les attributs tels que les analyseurs et les décorateurs prennent effet comme prévu.

Amélioration de FSharp.Core – prise en charge de and! dans les expressions de tâche

Cette version apporte une seule amélioration à la bibliothèque FSharp.Core : la prise en charge de and! dans l'expression de calcul task.

L'utilisation de task est un moyen courant de travailler avec des flux de travail asynchrones dans F#, en particulier lorsque l'interopérabilité avec C# est requise. Cependant, jusqu'à récemment, il n'existait aucun moyen concis d'attendre plusieurs tâches simultanément...
La fin de cet article est réservée aux abonnés. Soutenez le Club Developpez.com en prenant un abonnement pour que nous puissions continuer à vous proposer des publications.

Une erreur dans cette actualité ? Signalez-nous-la !