Ce que l'équipe Swift d'Apple a dit lors du lab de la WWDC26
Apple a publié le Swift Group Lab de la WWDC26 sous la forme d’une heure de questions-réponses sans script avec quatre ingénieurs des équipes Swift, Foundation et réseau côté serveur, puis l’a diffusée sans sous-titres.1 Nous avons passé la vidéo par une transcription locale pour lire ce qu’ils ont réellement dit. Les sessions soigneusement préparées vous expliquent ce que fait une fonctionnalité. Le lab, lui, est l’endroit où Holly admet qu’elle s’était trompée sur une décision de concurrence essentielle, où Corey explique le motif de nettoyage qui échoue silencieusement dans du code annulé, et où le panel répète sans cesse un conseil que le marketing ne donnera jamais : arrêtez de collectionner les fonctionnalités du langage. La version franche se trouve ici.
Une note sur les sources : Apple n’a publié aucune transcription officielle du lab. Chaque citation ci-dessous est une paraphrase issue d’une transcription locale de la vidéo publiée, avec des horodatages approximatifs. Les intervenants sont désignés par leur prénom et leur équipe, tels que la transcription les donne : Holly (équipe du langage Swift, génériques et concurrence), Corey (équipe réseau côté serveur de Swift), Tony (Foundation et bibliothèque standard) et Doug (équipe du langage Swift).1
TL;DR
- Holly a dit que si l’équipe concevait la concurrence Swift aujourd’hui, les fonctions async nonisolated s’exécuteraient dans le contexte de l’appelant dès le premier jour. Elle a tenu la conviction inverse « pendant très longtemps » et a changé d’avis face aux preuves du terrain. Swift 6.2 a fait du contexte de l’appelant le comportement par défaut standard.1
- Le conseil répété : rendez vos types non-
Sendableà dessein.~Sendable(SE-0518, implémenté dans Swift 6.4) offre une écriture plus claire, et Foundation réannote les types qu’elle avait marqués hors limites, l’instance globale d’UserDefaults gagnant une conformité Sendable.21 - Le motif de nettoyage asynchrone de Corey : les contextes annulés sautent silencieusement le nettoyage asynchrone ; auditez donc chaque
async deferà la recherche d’appelsawaitqui suspendent, et enveloppez-les dans un bouclier d’annulation. SE-0493 (deferasync) et SE-0504 (withTaskCancellationShield) arrivent tous deux dans Swift 6.4.34 - Franchise sur la feuille de route : le type
Disconnectedest une proposition active sur les forums, les conformités de tuples sont « presque là » mais formellement revenues en révision,UniqueArrayest accepté sur le principe, Subprocess 1.0 sort, et SwiftPM s’unifie autour de Swift Build.5678 - Le thème récurrent du panel : « les fonctionnalités du langage ne sont pas des objets de collection ». Profilez d’abord, adoptez l’outil ciblé que le profileur vous désigne, et laissez le reste tranquille.1
La décision de concurrence qu’Apple prendrait autrement
La rétrospective de Holly sur la concurrence commence vers 33:42. Le lab complet n’a pas de sous-titres officiels ; la transcription ci-dessous provient d’un ASR local.
Un développeur a posé au panel une question que les sessions soignées invitent rarement : maintenant que la concurrence de Swift 6 est sur le terrain depuis assez longtemps pour en observer l’adoption, y a-t-il quelque chose que l’équipe concevrait autrement aujourd’hui ? Holly a répondu sans détour. Oui, certainement.
Le regret précis porte sur l’endroit où s’exécute une fonction async nonisolated. Deux propositions de Swift Evolution ont déplacé ce comportement dans des directions opposées. La première faisait que les fonctions async nonisolated basculaient toujours vers le pool de threads concurrent global. La seconde, dans Swift 6.2, les faisait rester dans le contexte qui les avait appelées, de sorte qu’une fonction appelée depuis le main actor reste sur le main actor.1 Holly a retracé ce revirement jusqu’aux preuves issues de personnes qui exécutaient les premiers indicateurs de vérification de concurrence dans de vraies apps et bibliothèques : elles faisaient transiter des types non-Sendable entre un contexte isolé par un acteur et ces fonctions async nonisolated, et le comportement par défaut du pool global produisait des erreurs de course aux données, car l’acteur d’origine détenait encore ces valeurs pendant que la fonction async s’exécutait ailleurs.1
Puis vient la partie qui n’apparaît dans aucun enregistrement de session. « J’ai tenu très longtemps à la conviction que l’exécution sur le pool de threads concurrent global était le bon modèle pour ses bénéfices à long terme », a dit Holly, « mais j’ai fini par être convaincue, au fil du temps, par les problèmes rencontrés dans des projets réels » (paraphrase ASR, ~35:50).1 Doug a présenté le choix initial comme un pari défendable à l’échelle du système entier : plus de concurrence disponible signifie plus de parallélisme potentiel, ce qui peut signifier de meilleures performances. Le coût n’a fait surface qu’une fois le modèle de sûreté complet utilisé, et il poussait trop de types vers Sendable, ce que Doug a qualifié de « pas la manière naturelle d’exprimer toutes ces idées ».1 Le contexte de l’appelant par défaut est plus abordable, car il se comporte comme du code non concurrent jusqu’à ce que vous optiez explicitement pour le parallélisme. Si vous avez adopté Swift 6.2 et vous êtes demandé pourquoi l’histoire de la concurrence semblait soudain plus paisible, la réponse tient au fait que les personnes qui l’ont conçue ont admis que le premier choix par défaut était le mauvais et ont livré le correctif.
Rendez vos types non-Sendable à dessein
Le conseil le plus contre-intuitif du lab va à l’encontre de deux ans d’habitudes de migration. Holly a dit qu’elle rencontre sans cesse des développeurs qui demandent comment rendre leurs types Sendable, alors que la meilleure question est souvent l’inverse : ce type devrait-il être non-Sendable ?1 Pour les types éphémères utilisés à l’intérieur d’un seul calcul, les marquer explicitement non-Sendable produit un modèle de données plus net et une frontière plus nette entre ce que vous comptez faire passer à travers les limites d’isolation et ce que vous ne comptez pas y faire passer. Cela aide aussi les performances, car le coût du passage d’un type est un coût que vous voulez éviter de payer sur des valeurs intermédiaires qui n’avaient jamais besoin de voyager.1
Swift 6.4 donne à cette intention une véritable écriture. ~Sendable (SE-0518) vous laisse supprimer directement la conformité, à la manière dont ~Copyable supprime la copiabilité, au lieu d’écrire une conformité indisponible.2 Holly a tracé la distinction avec précision : une conformité Sendable indisponible déclare que le type et chacune de ses sous-classes ne sont assurément pas sendable et propage cela à toute la hiérarchie, tandis que ~Sendable n’est que l’absence de conformité, de sorte qu’une sous-classe qui n’ajoute aucun état mutable peut tout de même ajouter sa propre conformité Sendable.21
Cette souplesse était exactement ce dont Foundation avait besoin. Tony a expliqué la troisième catégorie issue de l’audit Sendable initial de Foundation : les classes dont la superclasse est sûre mais dont une sous-classe pourrait ne pas l’être. Son exemple était NSString, qui est immuable et sendable, face à NSMutableString, qui est une sous-classe mutable et ne l’est pas.1 Plutôt que de précipiter une annotation erronée, Foundation a marqué les classes ambiguës comme non-Sendable et a attendu. À présent, a dit Tony lors du lab, l’équipe se sert de l’annotation de Swift 6.4 pour réannoter ces types avec exactitude, et il s’attend à ce que l’UserDefaults global standard gagne une conformité Sendable.1 Considérez la conformité d’UserDefaults et la réannotation plus large de Foundation comme attribuées au lab : Tony a énoncé les deux dans les questions-réponses, et ce ne sont pas des fonctionnalités que je peux confirmer de manière indépendante à partir d’une proposition publiée. L’avertissement permanent du panel s’applique aussi ici, de la part de Tony : ne recourez pas à @unchecked Sendable pour forcer le mode Swift 6, car chaque annotation unchecked jette par-dessus bord la sûreté que le compilateur aurait pu prouver pour vous.1
Le nettoyage asynchrone, fait de sorte qu’il s’exécute vraiment
Corey porte la correction la plus pratique du lab, et c’est le genre de bug qu’on livre sans le remarquer. La victoire emblématique de la concurrence structurée est la propagation automatique de l’annulation : annulez une tâche et tout ce qui a été engendré à son service est annulé aussi, ce qui est exactement ce que vous voulez quand une vue est fermée ou qu’un client se déconnecte.1 Le piège se niche dans le nettoyage. Vous pourriez avoir un fichier à moitié écrit qu’il faut vider vers un état sain connu, ou une transaction de base de données à annuler, et ce nettoyage est lui-même asynchrone. Comme Corey l’a formulé, la plupart du code Swift refuse de s’exécuter dans un contexte annulé parce qu’il suppose qu’il devrait se dérouler le plus vite possible ; ainsi, un nettoyage asynchrone qui s’exécute à l’intérieur d’une tâche annulée peut discrètement ne pas faire son travail.1
Le correctif est un bouclier d’annulation, et il s’associe directement au defer async. SE-0493 permet à un bloc defer de contenir des appels await, et arrive dans Swift 6.4.3 SE-0504 ajoute withTaskCancellationShield, lui aussi dans Swift 6.4, qui exécute un bloc comme si l’annulation n’avait pas été demandée, afin qu’un nettoyage qui suspend aille jusqu’au bout.4 La recette d’audit de Corey est concrète : examinez chaque bloc async defer et demandez-vous si l’un des await qu’il contient va effectivement suspendre. Si c’est le cas, enveloppez-le dans un bouclier d’annulation.1 Il a qualifié les deux de « formidables compagnons » et de « très bon coup d’un-deux pour nettoyer proprement vos ressources ».1 Les types non-Sendable renforcent la même discipline, a noté Corey, car une valeur qui ne peut pas franchir les domaines de concurrence oblige votre flux de contrôle asynchrone à rester linéaire et facile à raisonner.1
Le conseil plus large de Corey sur la concurrence structurée complète la section. Appuyez-vous dessus avec assurance, car ce sont les échappatoires qui causent les ennuis. Évitez les tâches non structurées (Task.detached ou un Task nu) « à presque n’importe quel prix », sauf si vous envoyez délibérément du travail ailleurs, et jamais dans le flux principal. Faites des groupes de tâches votre choix par défaut, ajustez les cycles de vie des objets à leur portée lexicale, et écrivez du code asynchrone linéaire : une recette d’étape A, puis B, puis C, en n’allant chercher le parallélisme à l’intérieur des groupes de tâches que lorsque le travail se ramifie réellement.1
Franchise sur la feuille de route
Le lab est aussi l’endroit où le panel sépare les fonctionnalités livrées des fonctionnalités optimistes, et l’écart compte lorsque vous décidez sur quoi bâtir.
La question du stockage d’une valeur non-Sendable transférée a une vraie réponse en chemin. Aujourd’hui, vous transférez avec le mot-clé sending et l’isolation par régions laisse le compilateur prouver que le propriétaire d’origine a abandonné l’accès, mais si vous avez besoin de stocker une telle valeur, seules les options de retrait non sûres fonctionnent.1 Holly a pointé Disconnected, une proposition active sur les forums pour un type qui préserve la propriété de transfert à travers le stockage, afin que vous puissiez ranger une valeur et la transmettre plus tard. Il est en cours de conception et de discussion en ce moment même, pas implémenté.51
Les conformités de tuples sont l’exemple le plus net de l’optimisme d’un ingénieur face au statut formel. Interrogée sur ce qu’il reste à faire avant que les tuples ne se conforment conditionnellement à Equatable, Hashable et Comparable, Holly a expliqué qu’il s’agit d’une évolution des packs de paramètres : le langage a besoin d’une syntaxe pour écrire une extension sur un tuple dont les types d’éléments forment un pack de paramètres, avec une clause where exigeant que chaque élément se conforme.1 Elle a dit qu’une implémentation expérimentale vit dans le dépôt du compilateur et qu’elle est « presque arrivée tout au bout ».1 Le registre formel est plus prudent. SE-0283, la proposition initiale sur les conformités de tuples, a été renvoyée en révision et son implémentation de 2020 annulée ; l’approche générale par packs de paramètres n’existe aujourd’hui que derrière un indicateur de compilateur expérimental TupleConformances.10 Lisez le « presque là » de Holly comme la lecture honnête d’un ingénieur sur l’implémentation, et non comme une fonctionnalité livrée.
Les conteneurs de performance sont plus avancés. UniqueArray, que Tony a mentionné, vient de SE-0527 (« RigidArray and UniqueArray »), désormais accepté sur le principe, qui introduit un nouveau module Containers dans la bibliothèque standard ; il est déjà livré sous une forme préliminaire dans swift-collections 1.3.7 Tony l’a présenté comme la mise à niveau d’un Array dont le trafic de retain/release lié à la copie sur écriture apparaît dans une trace Instruments.1 Subprocess, l’API de processus open source multiplateforme que Tony a citée comme sa préférée, sort en version 1.0 cette année ; le jalon 1.0 est annoncé, le dernier tag publié étant encore à 0.5, donc elle est en cours de sortie plutôt que sortie.61 Côté outillage, Holly a décrit le changement de SwiftPM que les développeurs pourraient ne pas remarquer : les builds de packages de Xcode et ceux de la chaîne d’outils open source partagent désormais une seule implémentation, Swift Build, qui devient le moteur de système de build par défaut (par défaut sur main, visant 6.4).81
Enfin, le chemin de migration que Holly a mis en avant : @diagnose, le nouvel attribut issu de SE-0522 (« Source-Level Control Over Compiler Warnings »), accepté.9 Il donne un contrôle des avertissements au niveau du code source, de sorte que vous pouvez supprimer les avertissements de dépréciation dans une région ou activer des avertissements désactivés par défaut, comme la sûreté mémoire stricte ou la concurrence stricte, dans les zones qui comptent le plus, ce qui en fait un outil plus fin pour une migration progressive vers Swift 6.1
Conseils d’ingénieurs, rassemblés
La valeur du lab tient aux conseils de praticiens accumulés qui n’entrent jamais dans la durée d’une session. Les temps forts, attribués :
- Écrivez du code asynchrone linéaire. Corey : évitez les tâches non structurées à presque n’importe quel prix, gardez chaque tâche comme une recette séquentielle, et n’introduisez le parallélisme qu’à l’intérieur des groupes de tâches quand le travail se ramifie réellement.1
- Une recette de migration vers MainActor. Holly : commencez par les types feuilles et progressez vers l’extérieur, ou activez le main-actor-by-default pour un module qui devrait être entièrement sur le main actor et annotez explicitement les parties déchargées. Marquez
nonisolatedles méthodes qui ne touchent à aucun état mutable, et convertissez enletunestatic varqui n’est en réalité jamais mutée pour qu’elle puisse rester nonisolated.1 - Les coûts de conformité sont inégaux. Doug : une conformité
EquatableouHashableinutilisée conserve son code de témoin (witness) dans le binaire, car un transtypageas?à l’exécution vers un existentiel peut le découvrir, ce qui coûte en taille de code ;Sendableest une pure étiquette de compilation sans représentation à l’exécution, de sorte qu’une conformitéSendableinutilisée est gratuite.1 - La combinaison
@inlinableplus@inline(never). L’astuce préférée de Corey :@inlinableexpose un corps de fonction au-delà des limites de module et débloque la spécialisation générique et la propagation des effets, tandis que@inline(never)empêche qu’un chemin froid et lourd en code (une copie de repli octet par octet) soit inliné, afin que le chemin chaud reste rapide. Il a utilisé ce duo « trois fois dans tout le portefeuille réseau de Swift », pour des problèmes inhabituels de performance sur chemin froid.1 - Optimisez le chemin le plus chaud, pas le projet. Corey : « Nous avons connu un grand succès en introduisant des spans et quelques unique arrays juste le long du chemin le plus chaud », ce qui apporte la quasi-totalité des gains de performance pour un changement réduit et soutenu par le compilateur. Gardez les nouveaux types de performance isolés afin que les adopter n’impose jamais un refactoring géant.1
- Arrêtez de collectionner les fonctionnalités. La phrase récurrente du panel, tirée d’un ami que Corey a cité : « les fonctionnalités du langage ne sont pas des objets de collection ». Vous ne gagnez aucun prix à toutes les utiliser. Profilez d’abord, allez chercher l’outil ciblé que le profileur vous désigne (types non copiables,
UniqueArray,Span), et consacrez le reste de vos heures aux corrections de bugs et aux fonctionnalités.1
FAQ
Apple a-t-il vraiment publié le lab Swift de la WWDC26 sans sous-titres ?
Oui. Apple a mis en ligne le Swift Group Lab (session 8001) sous forme de vidéo sans transcription ni sous-titres officiels sur le site développeur.1 Pour le citer avec exactitude, j’ai passé l’enregistrement par une transcription locale, de sorte que chaque citation de cet article est une paraphrase issue de cet ASR local, avec des horodatages approximatifs, attribuée par prénom et par équipe.1
Qu’est-ce que l’équipe Swift a dit vouloir changer concernant la concurrence ?
Holly a dit que si Apple concevait la concurrence Swift aujourd’hui, les fonctions async nonisolated s’exécuteraient dans le contexte de l’appelant dès le départ plutôt que de basculer vers le pool de threads concurrent global. Elle a tenu longtemps à la conviction du pool global et a changé d’avis face aux preuves du terrain, et Swift 6.2 a fait du comportement du contexte de l’appelant le comportement par défaut.1
Dois-je rendre mes types Swift Sendable ou non-Sendable ?
Le conseil du lab est de rendre les types de calcul éphémères non-Sendable à dessein. Swift 6.4 ajoute pour cela l’écriture ~Sendable (SE-0518), distincte d’une conformité indisponible, car les sous-classes peuvent tout de même ajouter Sendable lorsqu’elles n’ajoutent aucun état mutable.2 Tony a dit que Foundation réannote ses classes ambiguës avec la nouvelle fonctionnalité et s’attend à ce que l’UserDefaults global gagne une conformité Sendable, deux points attribués au lab.1
Comment m’assurer que le nettoyage asynchrone s’exécute lorsqu’une tâche est annulée ?
Les contextes annulés font que la plupart du code Swift saute le travail qui suspend, de sorte que le nettoyage asynchrone peut échouer silencieusement. Le motif de Corey consiste à auditer chaque async defer à la recherche d’appels await qui suspendent réellement et à les envelopper dans un bouclier d’annulation. Le defer async (SE-0493) et withTaskCancellationShield (SE-0504) arrivent tous deux dans Swift 6.4.341
Les conformités de tuples sortent-elles dans Swift ?
Pas encore. SE-0283 a été renvoyée en révision et son implémentation initiale annulée ; l’approche générale par packs de paramètres n’existe que derrière un indicateur expérimental TupleConformances. Holly a dit lors du lab qu’une implémentation expérimentale dans le compilateur est « presque arrivée tout au bout », ce qui reflète l’optimisme d’un ingénieur plutôt qu’une fonctionnalité livrée.1
Le lab est le compagnon franc des annonces : pour les fonctionnalités livrées remises en contexte, lisez les nouveautés de Swift 2026, et pour les mécaniques de migration derrière le contexte de l’appelant par défaut dont Holly a parlé, voyez la concurrence de Swift 6.2 en pratique. La philosophie du panel — « profilez d’abord, adoptez l’outil ciblé » — s’étend aux tests dans Swift Testing contre XCTest. L’intégralité de la couverture de la WWDC26 se trouve dans la série Apple Ecosystem.
Références
-
Apple, WWDC 2026 session 8001, Swift Group Lab. Apple published no official transcript or captions for this lab; all quotes attributed to it are paraphrases from a local transcription of the published video, with approximate timestamps. Source for the concurrency retrospective (Holly, ~33:42), the make-types-non-Sendable guidance, the Foundation re-annotation and UserDefaults Sendable conformance (both lab-attributed to Tony), the async-cleanup and cancellation-shield pattern (Corey), the structured-concurrency and MainActor migration advice (Corey and Holly), the conformance-cost explanation (Doug), the
@inlinableplus@inline(never)combo and hottest-path performance guidance (Corey), theDisconnected, tuple-conformance,UniqueArray, Subprocess, SwiftPM, and@diagnoseremarks, and the “language features aren’t collectibles” theme. ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩ -
Apple / Swift Evolution, SE-0518,
~Sendablefor explicitly marking non-Sendabletypes. Status: Implemented (Swift 6.4). Source for suppressing theSendableconformance and the distinction from an unavailable conformance. ↩↩↩↩ -
Apple / Swift Evolution, SE-0493, Support
asynccalls indeferbodies. Status: Implemented (Swift 6.4). Source forawaitinsidedeferblocks. ↩↩↩ -
Apple / Swift Evolution, SE-0504, Task cancellation shields. Status: Implemented (Swift 6.4). Source for
withTaskCancellationShield. ↩↩↩ -
Swift Forums, Pitch:
Disconnectedtype for modeling disconnected values. Active forums pitch for safely storing transferred non-Sendablevalues; not implemented. ↩↩ -
Apple / Swift, Subprocess — cross-platform, open-source process API announced in 2025; version 1.0 announced as releasing this year, with the latest published tag at 0.5. Status per the lab and the project’s published releases. ↩↩
-
Apple / Swift Evolution, SE-0527, RigidArray and UniqueArray. Status: Accepted in Principle; introduces a new standard-library Containers module and ships in an early form in swift-collections 1.3. ↩↩
-
Swift Forums, SwiftPM development update: default build system change. Swift Build is becoming the default SwiftPM build-system backend (default on main, targeting 6.4). ↩↩
-
Apple / Swift Evolution, SE-0522, Source-Level Control Over Compiler Warnings. Status: Accepted. Source for the
@diagnoseattribute and region-scoped warning control. ↩ -
Apple / Swift Evolution, SE-0283, Tuples Conform to
Equatable,Comparable, andHashable. Status: Returned for revision; original implementation reverted. Source for the formal status of tuple conformances against the experimentalTupleConformancesflag. ↩
