Swift vs Kotlin
Swift, pour les plateformes Apple, face à Kotlin, pour Android. Analyse détaillée des fonctionnalités de langage modernes, de la syntaxe et de l'écosystème.
Modèle basé sur les acteurs qui élimine les data races à la compilation
Modèle à fonctions suspend flexible, basé sur une bibliothèque
Ce n'est pas une question de contexte, mais un compromis conscient : Swift 6 détecte plus d'erreurs à la compilation, au prix d'un coût de migration élevé. Kotlin coroutines est plus flexible et s'adopte progressivement, en laissant l'état partagé à la discipline du runtime. Pour l'annulation, en revanche, pas de différence — les deux sont coopératifs. Sur un projet greenfield Apple uniquement, activez le mode de langage Swift 6 dès le départ. Sur une base de code existante, planifiez la migration par target, en commençant par le module le plus isolé. En KMP, considérez la couche de pont comme une phase architecturale distincte.
| Catégorie | Swift 6 Concurrency | Kotlin Coroutines |
|---|---|---|
| Performance | 8/10 | 8/10 |
| Facilité d'apprentissage | 5/10 | 7/10 |
| Écosystème | 7/10 | 9/10 |
| Communauté | 7/10 | 8/10 |
| Marché de l'emploi | 8/10 | 8/10 |
| Pérennité | 9/10 | 8/10 |
// Swift 6 — modèle Sendable + téléchargement parallèle avec actor
import Foundation
struct UserProfile: Sendable, Decodable {
let id: Int
let name: String
}
actor ProfileCache {
private var storage: [Int: UserProfile] = [:]
func value(for id: Int) -> UserProfile? {
storage[id]
}
func insert(_ profile: UserProfile) {
storage[profile.id] = profile
}
}
enum ProfileError: Error {
case invalidResponse
}
func fetchProfile(id: Int) async throws -> UserProfile {
let url = URL(string: "https://api.example.com/users/\(id)")!
let (data, response) = try await URLSession.shared.data(from: url)
guard let http = response as? HTTPURLResponse, http.statusCode == 200 else {
throw ProfileError.invalidResponse
}
return try JSONDecoder().decode(UserProfile.self, from: data)
}
func loadProfiles(ids: [Int], cache: ProfileCache) async throws -> [UserProfile] {
try await withThrowingTaskGroup(of: UserProfile.self) { group in
for id in ids {
group.addTask {
if let cached = await cache.value(for: id) {
return cached
}
let profile = try await fetchProfile(id: id)
await cache.insert(profile)
return profile
}
}
var results: [UserProfile] = []
for try await profile in group {
results.append(profile)
}
return results
}
}// Kotlin Coroutines — concurrence structurée + téléchargement parallèle avec Mutex
import kotlinx.coroutines.*
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlinx.serialization.Serializable
import io.ktor.client.*
import io.ktor.client.call.body
import io.ktor.client.request.get
@Serializable
data class UserProfile(val id: Int, val name: String)
class ProfileCache {
private val mutex = Mutex()
private val storage = mutableMapOf<Int, UserProfile>()
suspend fun get(id: Int): UserProfile? = mutex.withLock { storage[id] }
suspend fun put(profile: UserProfile) = mutex.withLock {
storage[profile.id] = profile
}
}
suspend fun fetchProfile(client: HttpClient, id: Int): UserProfile =
client.get("https://api.example.com/users/$id").body()
suspend fun loadProfiles(
client: HttpClient,
ids: List<Int>,
cache: ProfileCache
): List<UserProfile> = coroutineScope {
ids.map { id ->
async {
cache.get(id) ?: fetchProfile(client, id).also { cache.put(it) }
}
}.awaitAll()
}
// L'annulation est coopérative : un travail long doit vérifier isActive
suspend fun loadWithTimeout(client: HttpClient, ids: List<Int>, cache: ProfileCache) =
withTimeoutOrNull(5_000) { loadProfiles(client, ids, cache) } ?: emptyList()Ce n'est pas une question de contexte, mais un compromis conscient : Swift 6 détecte plus d'erreurs à la compilation, au prix d'un coût de migration élevé. Kotlin coroutines est plus flexible et s'adopte progressivement, en laissant l'état partagé à la discipline du runtime. Pour l'annulation, en revanche, pas de différence — les deux sont coopératifs. Sur un projet greenfield Apple uniquement, activez le mode de langage Swift 6 dès le départ. Sur une base de code existante, planifiez la migration par target, en commençant par le module le plus isolé. En KMP, considérez la couche de pont comme une phase architecturale distincte.
Obtenir une consultation gratuiteSwift 6 impose la détection des data races à la compilation via le protocole Sendable et l'isolation des acteurs (SE-0302, SE-0306). Kotlin coroutines, lui, est un modèle à fonctions suspend qui fonctionne via la bibliothèque kotlinx.coroutines ; la vérification des data races n'est pas assurée par le compilateur mais laissée à la discipline du développeur (Mutex, choix du dispatcher).