Le mystérieux « some » : pourquoi des milliers de développeurs s’interrogent-ils à son sujet ?
\n\nSi vous avez déjà écrit du code en SwiftUI, vous avez sûrement vu la construction some View. Elle semble simple, mais les débutants sont souvent perdus : « Qu’est-ce que ce « some » ? Pourquoi ne peut-on pas simplement écrire View ? Et si j’enlève some, est-ce que ça casse ? ». La question « What is the "some" keyword in Swift(UI)? » a recueilli des milliers de vues sur Stack Overflow – et ce n’est pas un hasard. Derrière un mot court se cache toute une philosophie du Swift moderne.
Dans cet article, nous allons comprendre ce qu’est le mot-clé some, pourquoi il est apparu dans le langage et pourquoi il est impossible d’imaginer SwiftUI sans lui. Vous découvrirez comment il est lié aux génériques, aux protocoles et aux « types opaques » (opaque types). Et surtout, vous comprendrez comment écrire un code plus propre et plus performant.
\n\nLe problème que résout « some »
\n\nImaginez que vous écrivez une fonction qui retourne un objet conforme au protocole View. En SwiftUI, cela arrive constamment :
func makeGreeting() -> View {\n return Text("Hello!")\n}\n\nLe compilateur Swift vous dira : « Le protocole 'View' ne peut être utilisé que comme une contrainte générique (generic constraint), car il a des exigences Self ou associated type ». Cela semble effrayant, mais le principe est simple : le protocole View dans SwiftUI exige que le type soit connu à la compilation. Si nous retournons View – c’est une abstraction, alors que le compilateur a besoin de concret.
Avant, les développeurs se débrouillaient avec des génériques :
\n\nfunc makeGreeting<T: View>() -> T {\n return Text("Hello!") as! T\n}\n\nCela fonctionnait, mais ressemblait à une rustine : vous promettez au compilateur de retourner T, mais en réalité vous « faites semblant ». De plus, le code appelant devait explicitement spécifier le type. Pas joli et pas sûr.
« Some » – le sauveur du code passe-partout
\n\nLe mot-clé some en Swift est apparu dans la version 5.1 précisément pour ces cas. Il dit au compilateur : « Je vais retourner un type concret qui se conforme au protocole, mais je ne veux pas donner son nom. Tu le détermines toi-même à la compilation ». C’est ce qu’on appelle un type opaque (opaque type).
Revenons à notre exemple :
\n\nfunc makeGreeting() -> some View {\n return Text("Hello!")\n}\n\nMaintenant, le code se compile ! Le compilateur sait que c’est précisément Text qui est retourné, mais de l’extérieur, nous voyons seulement some View. Cela apporte deux choses :
- \n
- Sécurité des types – le compilateur vérifie que le type retourné est toujours le même. \n
- Encapsulation – nous cachons les détails d’implémentation au code appelant. \n
Comparaison : « some » vs génériques vs protocoles
\n\nPour mieux comprendre la magie de some, comparons les trois approches sur un exemple concret. Supposons que nous voulions écrire une fonction qui retourne une forme (cercle ou carré).
1. Retour d’un protocole (ne se compile pas)
\n\nprotocol Shape {\n func draw()\n}\n\nstruct Circle: Shape {\n func draw() { print("Dessiner un cercle") }\n}\nstruct Square: Shape {\n func draw() { print("Dessiner un carré") }\n}\n\n// Erreur : le protocole 'Shape' ne peut pas être utilisé comme type de retour\nfunc makeShape() -> Shape {\n return Circle()\n}\n\nComme nous le savons déjà – cela ne fonctionne pas si le protocole a des associated types ou des exigences Self.
\n\n2. Utilisation de génériques
\n\nfunc makeShape<T: Shape>() -> T {\n // Il faut créer T d’une manière ou d’une autre, mais nous ne connaissons pas le type concret\n fatalError("Impossible de créer un générique")\n}\n\nProblème : le code appelant doit savoir quel type attendre. La fonction ne peut pas décider elle-même quoi retourner.
\n\n3. Utilisation de « some » (fonctionne parfaitement)
\n\nfunc makeShape() -> some Shape {\n