Chaque langage de programmation a besoin d'un moyen de regrouper des données. La question est combien de façons, et quels compromis chacune fait.
FLIN en a trois : les tuples, les enums et les structs d'entités. Chacun sert un objectif distinct, et les frontières entre eux sont délibérées. Les tuples regroupent des données anonymes et ordonnées. Les enums définissent des alternatives nommées. Les structs d'entités définissent des enregistrements persistants avec des champs nommés.
Tuples : anonymes, ordonnés, légers
flinpoint = (10, 20)
coordinates: (int, int) = (10, 20)
// Accès par index
x = point.0 // 10
y = point.1 // 20
// Déstructuration
(q, r) = divide(17, 5)Un tuple est une collection de taille fixe de valeurs qui peuvent avoir des types différents. Le type (int, text) signifie « une paire où le premier élément est un int et le second est un text ». Contrairement à une liste, la longueur et les types d'éléments d'un tuple sont connus au moment de la compilation.
Enums : alternatives nommées
flinenum Direction { North, South, East, West }
enum Status { Pending, Active, Suspended, Deleted }Chaque variante est une valeur distincte. Direction.North n'est pas égal à Direction.South. Vous ne pouvez pas assigner une Direction à une variable Status. Le compilateur les traite comme des types complètement séparés.
Structs d'entités : nommés, persistants, relationnels
flinentity User {
name: text
email: text
age: int = 0
bio: text? = none
role: text = "user"
created: time = now
}Cette déclaration crée :
- Un type appelé User
- Une table de base de données appelée users
- Des opérations CRUD : User.all, User.find(id), User.where(...), save, delete
- Des accesseurs de champs : user.name, user.email, etc.
La comparaison à trois voies
| Fonctionnalité | Tuple | Enum | Entité |
|---|---|---|---|
| Champs nommés | Non | Non (variantes nommées) | Oui |
| Types multiples | Oui | Oui (chaque variante) | Oui |
| Persistant | Non | Non | Oui |
| Pattern matching | Par position | Par variante | Par nom de champ |
| Mutabilité | Immuable | Immuable | Mutable |
| Relations | Non | Non | Oui (un-à-plusieurs, etc.) |
| Table en base | Non | Non | Oui |
Combiner les trois
flinenum Shape {
Circle(number),
Rectangle(number, number),
Point
}
entity Drawing {
name: text
shapes: [Shape]
origin: (int, int)
created: time = now
}
fn bounding_box(shape: Shape) -> (number, number) {
match shape {
Circle(r) -> (r * 2, r * 2)
Rectangle(w, h) -> (w, h)
Point -> (0, 0)
}
}L'enum Shape définit des alternatives. L'entité Drawing définit un enregistrement persistant. La fonction bounding_box retourne un tuple. La boucle for déstructure le tuple. Les trois structures de données fonctionnent ensemble.
Principes de conception
Orthogonalité. Chaque structure de données fait une chose. Les tuples regroupent. Les enums alternent. Les entités persistent.
Composabilité. Les structures de données se composent entre elles. Une entité peut avoir un champ de type enum. Un tuple peut contenir des entités. Une variante d'enum peut porter un tuple.
Complexité progressive. Un débutant commence avec les entités -- la structure de données la plus courante et la plus utile. Les tuples et enums sont là quand nécessaire mais pas requis pour les programmes simples.
Ceci est la partie 39 de la série « Comment nous avons construit FLIN ».