expect/actual — Kotlin Multiplatform mexanizmi boʻlib, platformaga bogʻliq API-larni umumiy kodda eʻlon qilish imkonini beradi. expect kalit soʻzi commonMain da funksiya, sinf yoki xususiyatning kontraktini yaratadi, actual kalit soʻzi esa har bir platforma uchun aniq implementatsiyani taqdim etadi. Kompilyator har bir expect deklaratsiyasiga barcha maqsadli platformalarda actual implementatsiya mos kelishini tekshiradi. JetBrains, 2025 maʻlumotlariga koʻra, mexanizm KMM loyihalarining 80 foizida platforma biznes mantiqini amalga oshirish uchun qoʻlaniladi.
Asosiy maqsadlar
expect/actual — platformaga yoʻnaltirilgan dasturlashni amalga oshirish uchun Kotlin Multiplatformning deklarativ mexanizmi. Bu API-ni bir marta umumiy modulda (expect) tavsiflash va uni har bir platforma uchun alohida (actual) amalga oshirish imkonini beradi. Interfeyslardan farqli oʻlaroq, expect/actual virtual chaqiruvlarni yaratmaydi — kompilyator expect va actual deklaratsiyalarini kompilyatsiya bosqichida bogʻlaydi va bu dinamik dispetcherizatsiya uchun qoʻshimcha yukni yoʻq qiladi.
expect/actual tarixi 2017 yilda Kotlin Multiplatform paydo boʻlishi bilan boshlandi. Dastlab mexanizm expect/actual declarations deb nomlangan va eksperimental edi. Kotlin 1.2 da expect annotatsiyalari qoʻshildi, Kotlin 1.3 da esa expect/actual sinflar va funksiyalar uchun barqaror boʻldi. Asta-sekin mexanizm kengaytirildi: Kotlin 1.6 da companion obʻektlari uchun, Kotlin 1.7 da — enum sinflari uchun, Kotlin 2.0 da — typealias uchun qoʻllab-quvvatlandi.
expect/actual ning asosiy xususiyati — kompilyatsiya darajasida xavfsizlik. Agar dasturchi commonMain ga expect deklaratsiyasini qoʻshgan boʻlsa, lekin iOS uchun actual implementatsiyani unutgan boʻlsa, kompilyator xatolik beradi. Bu refleksiya yoki platforma kodini dinamik yuklash yondashuvlariga xos runtime xatolarining oldini oladi.
Mexanizm expect/actual source set — Kotlin Multiplatform modul tizimi darajasida ishlaydi. Barcha platformalar uchun mavjud umumiy kod commonMain source setida joylashgan. Platformaga bogʻliq kod — iosMain, androidMain, macosMain va hokazo. commonMain dagi expect kalit soʻzi API-ni eʻlon qiladi, platforma source setidagi actual kalit soʻzi esa implementatsiyani taqdim etadi. Kompilyator ularni kod generatsiyasi bosqichida bogʻlaydi va expect funksiyasini maqsadli platforma uchun mos actual implementatsiya bilan almashtiradi.
Oddiy KMM loyihasida source set ierarxiyasi quyidagicha: commonMain expect deklaratsiyalarini oʻz ichiga oladi, iosMain va androidMain actual implementatsiyalarni oʻz ichiga oladi. iOS uchun kompilyatsiyada iosMain dan actual, Android uchun kompilyatsiyada androidMain dan actual ishlatiladi. Source setʻlar oraliq boʻlishi mumkin (masalan, maʻlum arxitektura uchun iosArm64Main), bu turli qurilmalar uchun implementatsiyalarni aniqlashtirish imkonini beradi.
// commonMain — expect deklaratsiyasi
expect fun getPlatformName(): String
// androidMain — Android uchun actual
actual fun getPlatformName(): String = "Android"
// iosMain — iOS uchun actual
actual fun getPlatformName(): String = "iOS"
Kotlin kompilyatori expect/actual bilan ishlashda bir nechta shartlarni tekshiradi. Har bir expect deklaratsiyasi har bir faol platforma uchun actual implementatsiyaga ega boʻlishi kerak. actual deklaratsiyasining imzosi expect imzosi bilan mos kelishi kerak (@OptionalExpectation annotatsiyasi bu talabni yumshatishi mumkin). Kirish modifikatorlari, qaytish turi va parametrlar bir xil boʻlishi kerak. Kompilyator expect va actual deklaratsiyalari oʻrtasida siklik bogʻliqliklar yoʻqligini ham tekshiradi.
expect/actual bir nechta deklaratsiya turlarini qoʻllab-quvvatlaydi. Eng koʻp ishlatiladiganlari platforma operatsiyalari uchun expect/actual funksiyalari, mahalliy implementatsiyani talab qiladigan obʻektlar uchun expect/actual sinflari va konstantalar va sozlamalar uchun expect/actual xususiyatlaridir. Har bir turning oʻziga xos foydalanish qoidalari va cheklovlari mavjud.
Expect/actual funksiyalari — eng sodda va keng tarqalgan tur. Ular vaqtni olish, fayllarni oʻqish yoki HTTP soʻrovlarini yuborish kabi platforma API-larini chaqirish uchun ishlatiladi. Expect/actual sinflari mahalliy kod bilan bevosita aloqada boʻladigan obʻektlarni yaratish uchun qoʻllaniladi (masalan, kameraga, geolokatsiyaga yoki kalit saqlovchiga kirish uchun). Expect/actual xususiyatlari (val) platforma konstantalari — OT nomi, SDK versiyasi yoki tizim katalogiga yoʻl uchun mos keladi.
| Deklaratsiya turi | Kalit soʻzlar | Foydalanish misoli |
|---|---|---|
| Funksiya | expect fun / actual fun | Qurilmaning noyob identifikatorini olish |
| Sinf | expect class / actual class | SecureStorage ga kirish (Keychain / EncryptedSharedPreferences) |
| Xususiyat | expect val / actual val | Joriy platforma (iOS / Android) |
| Enum sinf | expect enum / actual enum | Mavjud ilova ruxsatnomalari roʻyxati |
| Typealias | expect typealias / actual typealias | Platformaga xos tarmoq javob turi |
Kotlinning barcha konstruksiyalari expect/actual bilan ishlatilmaydi. Expect deklaratsiyasi tanaga ega boʻla olmaydi — faqat imzo. Expect sinfi parametrli konstruktorga ega boʻla olmaydi (boʻsh asosiy konstruktor boʻlishi kerak). Enum expect/actual uchun barcha konstantalar expect va actual da bir xil boʻlishi kerak. Expect xususiyatlari val (var emas) boʻlishi kerak, chunki platforma xususiyatlari uchun umumiy modulda holatni saqlash maʻnoga ega emas.
Keling, expect/actual ning oddiy funksiyalardan toʻliq sinflargacha boʻlgan amaliy misollarini koʻrib chiqamiz. Asosiy holat — interfeysda foydalanish uchun platforma nomini olish. Murakkabroq misollar mahalliy xotiraga kirish va platforma oqimlari bilan ishlashni oʻz ichiga oladi.
// commonMain — xavfsiz saqlash uchun expect sinfi
expect class PlatformStorage {
fun save(key: String, value: String)
fun get(key: String): String?
fun remove(key: String)
}
// androidMain — Android da actual
actual class PlatformStorage {
private val prefs = AppContext.getSharedPreferences("secure", 0)
actual fun save(key: String, value: String) { prefs.edit().putString(key, value).apply() }
actual fun get(key: String): String? = prefs.getString(key, null)
actual fun remove(key: String) { prefs.edit().remove(key).apply() }
}
Ushbu misolda PlatformStorage expect sinfi oddiy kalit-qiymat xotirasining kontraktini belgilaydi. Android da implementatsiya SharedPreferences dan, iOS da esa Keychain yoki NSUserDefaults dan foydalanadi. expect/actual tufayli commonMain dagi biznes mantigʻi platforma implementatsiyasini bilmagan holda save/get/remove ni chaqiradi.
// iosMain — iOS da Keychain bilan actual
actual class PlatformStorage {
actual fun save(key: String, value: String) {
val query = mapOf<String, Any>(
kSecClass to kSecClassGenericPassword,
kSecAttrAccount to key,
kSecValueData to value.encodeToByteArray()
)
SecItemAdd(query, null)
}
actual fun get(key: String): String? {
val query = mapOf<String, Any>(
kSecClass to kSecClassGenericPassword,
kSecAttrAccount to key,
kSecReturnData to true
)
val result = mutableMapOf<String, Any>()
return if (SecItemCopyMatching(query, result) == errSecSuccess)
result[kSecValueData]?.toString()
else null
}
actual fun remove(key: String) {
val query = mapOf<String, Any>(
kSecClass to kSecClassGenericPassword,
kSecAttrAccount to key
)
SecItemDelete(query)
}
}
expect/actual API-ni loyihalashda bir nechta tamoyillarga rioya qilish kerak. expect deklaratsiyalari sonini minimallashtiring — umumiy kod qancha koʻp boʻsa, texnik xizmat koʻrsatish shuncha oson. expect/actual ni faqat platformalarda haqiqatan farq qiladigan API-lar uchun ishlating. Qolgan kod uchun interfeyslarni fabrikalar yoki dependency injection bilan qoʻllang, bu testlashni soddalashtiradi.
expect deklaratsiyalarini mavzuli modullar boʻyicha guruhlash tavsiya etiladi, ularni bitta faylda aralashtirmang. Masalan, xotira uchun Storage.kt, OT bilan ishlash uchun Platform.kt va analitika uchun Analytics.kt expect deklaratsiyalari. Bu KMM loyihasining platforma yuzasida navigatsiya va tushunishni soddalashtiradi. Har bir actual fayl tegishli source setda boʻlishi kerak: androidMain, iosMain, desktopMain va hokazo.
Standart implementatsiyalar actual fun umumiy koddan foydalanadigan expect fun orqali — keng tarqalgan anti-naʻmunadir. Agar platforma implementatsiyasi standartdan farq qilmasa, expect/actual kerak emas. Bunday hollarda commonMain da oddiy funksiyadan foydalaning. Shuningdek, oddiy getterlar uchun expect/actual dan saqlaning — konstantalar bilan expect val dan foydalaning.
expect/actual kodining toʻgʻri tuzilishi loyihaning oʻqiluvchanligi uchun juda muhimdir. Har bir expect/actual moduli yagona kirish nuqtasiga ega boʻlishi kerak. Tashkilot namunasi: commonMain/kotlin/com/project/platform expect deklaratsiyalarini oʻz ichiga oladi, androidMain/kotlin/com/project/platform — Android uchun actual, iosMain/kotlin/com/project/platform — iOS uchun actual. Fayl va paket nomlari expect va actual uchun mos boʻlishi kerak, shunda dasturchi tegishli implementatsiyani tez topa oladi.
Interfeyslar platforma fabrikasi bilan — expect/actual ning asosiy alternativi. expect sinfi oʻrniga commonMain da interfeys eʻlon qilinishi va platforma modullarida aniq sinflar yaratilishi mumkin. Fabrika yoki dependency injection konteyneri runtime da toʻgʻri implementatsiyani taqdim etadi. Bu yondashuv testlash uchun qulayroq, chunki interfeysni mock qilish mumkin.
Dependency Injection (Koin, Kodein) — yanada moslashuvchan, ammo kam samarali yondashuv. DI konteyneri har bir platforma uchun alohida konfiguratsiya qilinadi va platforma bogʻliqliklarini umumiy kodga taqdim etadi. expect/actual dan farqli oʻlaroq, inyeksiya runtime da sodir boʻladi, bu implementatsiyalarni testlash uchun almashtirish imkonini beradi. Boshqa tomondan, DI konfiguratsiya xatolari faqat ishga tushirishda aniqlanadi, kompilyatsiya bosqichida emas.
| Yondashuv | Kompilyatsiya bosqichida tekshirish | Testlash moslashuvchanligi | Runtime qoʻshimcha yuki |
|---|---|---|---|
| expect/actual | Toʻliq | Past (actual mock qilinmaydi) | Nol (kompilyatsiya bogʻlanishi) |
| Interfeyslar + fabrika | Qisman | Yuqori (mock qilinishi mumkin) | Minimal (virtual chaqiruv) |
| Dependency Injection | Yoʻq (runtime) | Yuqori | Oʻrta (DI proksi) |
expect/actual va alternativlar oʻrtasidagi tanlov kontekstga bogʻliq. Kritik samaradorlik uchun (oʺbyin dvigatellari, real-time qayta ishlash) nol runtime yuki tufayli expect/actual afzal. Biznes mantigʻi uchun (repositoryʻlar, use-caseʻlar) testlashni soddalashtirish uchun DI bilan interfeyslardan foydalanish yaxshiroq. Kombinatsiyalangan yondashuv — past darajadagi platforma operatsiyalari uchun expect/actual va biznes mantigʻi qatlami uchun interfeyslar — aksariyat ishlab chiqarish KMM loyihalarida qoʻlaniladi.
Koʻp beriladigan savollar
expect/actual implementatsiyani virtual chaqiruvlarsiz kompilyatsiya bosqichida bogʻlaydi, interfeyslar esa runtime da. expect/actual barcha platformalar uchun implementatsiya mavjudligini kafolatlaydi, interfeyslar runtime tekshiruvlarini talab qiladi.
Ha, expect enum Kotlin 1.7 dan boshlab qoʻllab-quvvatlanadi. expect va actual enumdagi barcha konstantalar mos kelishi kerak. Turli platformalarda konstantalarning turli qiymatlari — kompilyatsiya xatosi.
Kompilyator actual implementatsiyasi boʻlmagan har bir platforma uchun xatolik beradi. Barcha expect deklaratsiyalari uchun tegishli actual implementatsiyalar qoʻshilguncha loyiha yigʻilmaydi.
Yoʻq, expect va actual turli source setʻlarda boʻlishi kerak. expect — commonMain yoki oraliq source setda, actual — platforma source setida. expect va actual ni bir source setga joylashtirish kompilyatsiya xatosidir.
expect/actual ni testlash uchun platforma test source setʻlari bilan commonTest dan foydalaning. commonTest da expect testlari va har bir platforma uchun actual testlar yozing. Integratsiya testlari har bir maqsadli platformada alohida ishga tushiriladi.
Xulosa
Biz kalit topshirig'i bilan mobil ilovani ishlab chiqamiz
IT Sectr 2017-yildan beri startaplar va korxonalar uchun iOS va Android ilovalarini yaratadi. Biz sizga maslahat beramiz va eng yaxshi yechimni taklif qilamiz.