Module
Syntaxe
accessibility-modifier
: restreint l'accessibilité → public
(défaut), internal
(assembly), private
(parent)
Le nom complet ([namespace.]module-name
) doit être unique → 2 fichiers ne peuvent pas déclarer des modules de même nom
Module top-level
Doit être déclaré en 1er dans un fichier ❗
Contient tout le reste du fichier
Contenu non indenté
Ne peut pas contenir de namespace
Peut être qualifié = inclus dans un namespace parent (existant ou non)
Module top-level implicite
Si fichier sans module/namespace top-level
Nom du module = nom du fichier
Sans l'extension
Avec 1ère lettre en majuscule
Ex :
program.fs
→module Program
Module local
Syntaxe similaire au let
mais ne pas oublier :
Le signe
=
après le nom du module local ❗D'indenter tout le contenu du module local
Non indenté = ne fait pas partie du module local
Contenu d'un module
Un module, local comme top-level, peut contenir :
Types et sous modules locaux
Valeurs, fonctions
Différence : l'indentation du contenu
Module top-level : contenu non indenté
Module local : contenu indenté
Équivalence module / classe statique
Ce module F♯ est équivalent à la classe statique suivante :
Module imbriqué
Comme en C♯ et les classes, les modules F♯ peuvent être imbriqués
☝ Notes :
Intéressant avec module imbriqué privé pour isoler/regrouper
Sinon, préférer une vue aplanie
Module top-level vs local
Qualifiable
✅
❌
Signe =
+ Contenu indenté
❌
✅ ❗
Module top-level → 1er élément déclaré dans un fichier
Sinon (après un module/namespace top-level) → module local
Module récursif
Même principe que namespace récursif → Pratique pour qu'un type et un module associé se voient mutuellement
☝ Recommandation : limiter au maximum la taille des zones récursives
Annotation d'un module
2 attributs influencent l'usage d'un module
[<RequireQualifiedAccess>]
[<RequireQualifiedAccess>]
→ Force l'usage qualifié des éléments d'un module → Empêche l'import du module
💡 Pratique pour éviter le shadowing pour des noms communs :
add
,parse
...☝️ Il n'y a pas d'attribut équivalent pour les méthodes statiques d'un type :
Par défaut, on utilise l'accès qualifié, y compris à l'intérieur du type, alors qu'à l'intérieur d'un module on n'accède directement aux autres fonctions, la qualification n'étant pas possible (sauf peut-être en rendant le module récursif 🤷)
L'accès direct est possible en important le type à l'aide du mot clé
open type
.
[<AutoOpen>]
[<AutoOpen>]
Import du module en même temps que le module/namespace parent
💡 Pratique pour "monter" valeurs/fonctions au niveau d'un namespace (un namespace ne pouvant pas en contenir normalement)
💡On emploie couramment AutoOpen
pour mieux organiser un module, en regroupant des éléments dans des modules enfants
→ à condition qu'ils restent de taille raisonnable, sinon il vaudrait mieux considérer de les répartir dans différents fichiers
→ on peut combiner cela avec le fait de rendre certains modules private
pour cacher l'ensemble de son contenu au code appelant tout en gardant ce contenu accessible directement au reste du module courant.
👉 Avoir un module AutoOpen
à l'intérieur d'un module RequireQualifiedAccess
ne fait sens que si le module est private
.
AutoOpen
, RequireQualifiedAccess
ou rien ?
AutoOpen
, RequireQualifiedAccess
ou rien ?Soit un type Cart
avec son module compagnon Cart
→ Comment appeler la fonction qui ajoute un élément au panier ?
addItem item cart
→[<RequireQualifiedAccess>]
intéressant pour forcer à avoirCart.addItem
dans le code appelant et lever toute ambiguïté sur le containeur (Cart
) dans lequel on ajoute l'élémentaddItemToCart item cart
→addItemToCart
est self-explicit,Cart.addItemToCart
pléonastique. →[<AutoOpen>]
intéressant pour éviter de devoir importer le module
Si le module Cart
contient d'autres fonctions de ce type, mieux vaudrait leur appliquer toute la même convention de nommage.
Module et Type
Un module sert typiquement à regrouper des fonctions agissant sur un type de donnée bien spécifique.
2 styles, selon localisation type / module :
Type défini avant le module → module compagnon
Type défini dans le module
Module compagnon d'un type
Style par défaut - cf.
List
,Option
,Result
...Bonne interop autres langages .NET
Module peut porter le même nom que le type
Module wrappant un type
Type défini à l'intérieur du module
On peut nommer le type
T
ou comme le module
Recommandé pour améliorer encapsulation
Constructeur du type
private
Module contient un smart constructor
Top-level module ou namespace
Préférer un namespace pour :
1 ou plusieurs types, avec quelques modules compagnons
Dans les autres cas, préférer un top-level module, pour gagner un niveau d'indentation.
Dernière mise à jour
Cet article vous a-t-il été utile ?