expect/actual হল একটি Kotlin Multiplatform প্রক্রিয়া যা সাধারণ কোডে প্ল্যাটফর্ম-নির্ভর API ঘোষণা করার অনুমতি দেয়। expect কীওয়র্ডটি commonMain-এ একটি ফাংশন, ক্লাস বা প্রাপার্টির একটি চুক্তি তৈরি করে, যখন actual কীওয়র্ডটি প্রতিটি প্ল্যাটফর্মের জন্য একটি নির্দিষ্ট বাস্তবায়ন প্রদান করে। কম্পাইলার যাচাই করে যে সকল টার্গেট প্ল্যাটফর্মে প্রতিটি expect ঘোষণার জন্য একটি actual বাস্তবায়ন থাকে। JetBrains, 2025 অনুসারে, এই প্রক্রিয়াটি 80% KMM প্রকল্পে প্ল্যাটফর্ম ব্যবসায়িক যুক্তি বাস্তবায়নে ব্যবহৃত হয়।
মূখ্য বিষয়
expect/actual হল প্ল্যাটফর্ম-ওয়ান্মুখী প্রোগ্রামিং বাস্তবায়নের জন্য Kotlin Multiplatform এর একটি ঘোষণামূলক প্রক্রিয়া। এটি সাধারণ মডিউলে (expect) একবার API বর্ণনা করার এবং প্রতিটি প্ল্যাটফর্মের (actual) জন্য আলাদা করে বাস্তবায়ন করার অনুমতি দেয়। ইন্টারফেসের বিপরীতে, expect/actual ভার্চুয়াল কল তৈরি করে না — কম্পাইলার কম্পাইল টাইমে expect এবং actual ঘোষণাগুলিকে সংযুক্ত করে, যা ডায়নামিক ডিস্প্যাচের ওভারহেড দূর করে।
expect/actual এর ইতিহাস 2017 সালে Kotlin Multiplatform এর আবির্ভাবের সাথে শুরু হয়েছিল। প্রথমে, প্রক্রিয়াটিকে expect/actual declarations বলা হত এবং এটি পরীক্ষামূলক ছিল। Kotlin 1.2-এ expect অ্যানোটেশন যুক্ত করা হয়েছিল, এবং Kotlin 1.3-এ expect/actual ক্লাস এবং ফাংশনের জন্য স্থির হয়েছিল। সময়ের সাথে প্রক্রিয়াটি বিস্তৃত হয়েছে: Kotlin 1.6 কম্প্যানিয়ন অবজেক্টের জন্য expect/actual সমর্থন যুক্ত করেছে, Kotlin 1.7 এনাম ক্লাসের জন্য, এবং Kotlin 2.0 typealias এর জন্য।
expect/actual এর চাবিকাঠামো হল কম্পাইল-টাইম নিরাপত্তা। যদি কোনো ডেভেলপার commonMain-এ একটি expect ঘোষণা যুক্ত করে কিন্তু iOS এর জন্য একটি actual বাস্তবায়ন প্রদান করতে ভুলে যায়, তবে কম্পাইলার একটি ত্রুটি তৈরি করবে। এটি রিফলেক্শন বা প্ল্যাটফর্ম কোডের ডায়নামিক লোডিং ব্যবহারকারী পদ্ধতিতে সাধারণ রনটাইম ব্যর্থতা প্রতিরোধ করে।
expect/actual এর প্রক্রিয়া source set স্তরে কাজ করে — Kotlin Multiplatform এর মডিউল ব্যবস্থা। সকল প্ল্যাটফর্মের জন্য উপলব্ধ সাধারণ কোডটি commonMain source set-এ অবস্থিত। প্ল্যাটফর্ম-নির্ভর কোডটি iosMain, androidMain, macosMain ইত্যাদিতে অবস্থিত। commonMain-এ expect কীওয়র্ডটি একটি API ঘোষণা করে, যখন একটি প্ল্যাটফর্ম source set-এ actual কীওয়র্ডটি বাস্তবায়ন প্রদান করে। কম্পাইলার কোড জেনারেশন পর্যায়ে তাদের সংযুক্ত করে, টার্গেট প্ল্যাটফর্মের জন্য expect ফাংশন কলকে সংশ্লিষ্ট actual বাস্তবায়ন দিয়ে প্রতিস্থাপন করে।
একটি সাধারণ KMM প্রকল্পে source set পদানুক্রম নিম্নরূপ: commonMain-এ expect ঘোষণা থাকে, iosMain এবং androidMain-এ actual বাস্তবায়ন থাকে। iOS এর জন্য কম্পাইল করার সময় iosMain থেকে actual ব্যবহৃত হয়, Android এর জন্য কম্পাইল করার সময় androidMain থেকে। Source set গুলি মধ্যবর্তী হতে পারে (যেমন, একটি নির্দিষ্ট আর্কিটেকচারের জন্য iosArm64Main), যা বিভিন্ন ডিভাইসের জন্য বাস্তবায়ন পরিশোধনের অনুমতি দেয়।
// commonMain — expect declaration
expect fun getPlatformName(): String
// androidMain — actual for Android
actual fun getPlatformName(): String = "Android"
// iosMain — actual for iOS
actual fun getPlatformName(): String = "iOS"
Kotlin কম্পাইলার expect/actual এর সাথে কাজ করার সময় বেশ কয়েকটি শর্ত যাচাই করে। প্রতিটি সক্রিয় প্ল্যাটফর্মের জন্য প্রতিটি expect ঘোষণার একটি actual বাস্তবায়ন থাকতে হবে। actual ঘোষণার স্বাক্ষর expect স্বাক্ষরের সাথে মেলানো উচিত (@OptionalExpectation অ্যানোটেশন এই প্রয়োজনীয়তা শিথিল করতে পারে)। অ্যাক্সেস মডিফায়ার, রিটার্ন টাইপ এবং প্যারামিটার অবিশ্য অনুরূপ হতে হবে। কম্পাইলার expect এবং actual ঘোষণার মধ্যে চাক্রিয়ক নির্ভরতার অনুপস্থিতিও যাচাই করে।
expect/actual বেশ কয়েকটি ধরনের ঘোষণা সমর্থন করে। সবচেয়ে বেশি ব্যবহৃত হল প্ল্যাটফর্ম কাজের জন্য expect/actual ফাংশন, নেটিভ বাস্তবায়ন প্রয়োজন বস্তুগুলির জন্য expect/actual ক্লাস, এবং স্থিরাংক এবং সেটিংয়ের জন্য expect/actual প্রাপার্টি। প্রতিটি ধরনের নিজস্ব ব্যবহারের নিয়ম এবং সীমাবদ্ধি রয়েছে।
Expect/actual ফাংশন হল সবচেয়ে সহজ এবং সাধারণ ধরন। এগুলি সময় প্রাপ্তি, ফাইল পড়া বা HTTP অনুরোধ প্রেরণের মতো প্ল্যাটফর্ম API কল করার জন্য ব্যবহৃত হয়। Expect/actual ক্লাস ব্যবহৃত হয় বস্তু তৈরির জন্য যা সরাসরি নেটিভ কোডের সাথে যোগাযোগ করে (যেমন, ক্যামেরা, জিয়োলকেশন বা কী স্টোরেজ অ্যাক্সেসের জন্য)। Expect/actual প্রাপার্টি (val) প্ল্যাটফর্ম স্থিরাংকের জন্য উপযুক্ত — OS নাম, SDK সংস্করণ বা সিস্টম ডিরেক্টরি পাথ।
| ঘোষণার ধরন | কীওয়র্ড | ব্যবহারের উদাহরণ |
|---|---|---|
| ফাংশন | expect fun / actual fun | একটি অনন্য ডিভাইস শনাক্তকারী প্রাপ্ত করা |
| ক্লাস | expect class / actual class | SecureStorage-এ অ্যাক্সেস (Keychain / EncryptedSharedPreferences) |
| প্রাপার্টি | expect val / actual val | বর্তমান প্ল্যাটফর্ম (iOS / Android) |
| এনাম ক্লাস | expect enum / actual enum | উপলব্ধ অ্যাপ অনুমতির তালিকা |
| Typealias | expect typealias / actual typealias | প্ল্যাটফর্ম-নির্দিষ্ট নেটওয়ার্ক প্রতিক্রিয়ার ধরন |
Kotlin এর সকল গঠন expect/actual এর সাথে ব্যবহৃত হতে পারে না। একটি expect ঘোষণা একটি বোডি ধারণ করতে পারে না — শুধু স্বাক্ষর। একটি expect ক্লাসে প্যারামিটার সহ কনস্ট্রাক্টার থাকতে পারে না (একটি খালি প্রাইমারি কনস্ট্রাক্টার থাকতে হবে)। enum expect/actual এর জন্য, expect এবং actual উভয়ের সকল স্থিরাংক অবিশ্য অনুরূপ হতে হবে। Expect প্রাপার্টি val (বার নয়) হতে হবে, কারণ প্ল্যাটফর্ম প্রাপার্টির জন্য সাধারণ মডিউলে অবস্থা সংরক্ষণ করা অর্থহীন।
আসুন সহজ ফাংশন থেকে পূর্ণাঙ্গ ক্লাস পর্যন্ত expect/actual এর ব্যাবহারিক উদাহরণ অনুসন্ধান করি। মৌলিক ক্ষেত্রটি হল UI-তে ব্যবহারের জন্য প্ল্যাটফর্মের নাম প্রাপ্ত করা। আরও জটিল উদাহরণে নেটিভ স্টোরেজ অ্যাক্সেস এবং প্ল্যাটফর্ম থ্রেড নিয়ে কাজ অন্তর্ভুক্ত রয়েছে।
// commonMain — expect class for secure storage
expect class PlatformStorage {
fun save(key: String, value: String)
fun get(key: String): String?
fun remove(key: String)
}
// androidMain — actual on Android
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() }
}
এই উদাহরণে, expect ক্লাস PlatformStorage একটি সহজ কী-ভ্যালু স্টোরেজের চুক্তি সংজ্যায়িত করে। Android-এ বাস্তবায়ন SharedPreferences ব্যবহার করে, যখন iOS-এ Keychain বা NSUserDefaults ব্যবহার করে। expect/actual এর কারণে, commonMain-এ ব্যবসায়িক যুক্তি প্ল্যাটফর্ম বাস্তবায়ন সম্পর্কে না জেনেই save/get/remove কল করে।
// iosMain — actual on iOS with Keychain
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 ডিজাইন করার সময়, বেশ কয়েকটি নীতি অনুসরণ করা উচিত। expect ঘোষণার সংখ্যা সর্বনিম্ন করুন — যত বেশি সাধারণ কোড, রক্ষণাবেক্ষণ তত সহজ। expect/actual শুধু সেই সব API এর জন্য ব্যবহার করুন যা প্ল্যাটফর্মের মধ্যে প্রকৃতই পার্থক্য করে। বাকি কোডের জন্য, ফ্যাক্টরি বা ডিপেন্ডেন্সি ইনজেক্শন সহ ইন্টারফেস ব্যবহার করুন, যা পরীক্ষাকে সরল করে।
expect ঘোষণাগুলিকে বিষয়ভিত্তিক মডিউলএ সমূহীভূত করার পরামর্শ করা হয়, একটি ফাইলে মিশানোর পরিবর্তে। উদাহরণস্বরূপ, Storage.kt স্টোরেজ সম্পর্কিত expect ঘোষণার জন্য, Platform.kt OS এর সাথে কাজ করা expect ফাংশনের জন্য, এবং Analytics.kt বিশ্লেষণ expect ক্লাসের জন্য। এটি একটি KMM প্রকল্পের প্ল্যাটফর্ম পৃষ্ঠ নেভিগেট এবং বুঝতে সহজ করে। প্রতিটি actual ফাইল সংশ্লিষ্ট source setএ থাকা উচিত: androidMain, iosMain, desktopMain ইত্যাদি।
expect fun এর সাথে actual fun যেখানে actual সাধারণ কোড ব্যবহার করে সেটি একটি সাধারণ অ্যান্টিপ্যাটার্ন। যদি প্ল্যাটফর্ম বাস্তবায়ন ডিফল্ট হতে পার্থক্য না করে, তবে expect/actual প্রয়োজন নেই। এমন ক্ষেত্রে, commonMain-এ একটি সহজ ফাংশন ব্যবহার করুন। একই সাথে, তুচ্ছ getters এর জন্য expect/actual এড়িয়ে চলুন — স্থিরাংকের সাথে expect val ব্যবহার করুন।
expect/actual কোডের উপযুক্ত গঠন প্রকল্পের পঠনীয়তার জন্য অত্যন্ত গুরুত্বপূর্ণ। প্রতিটি expect/actual মডিউলের একটি একক প্রবেশ বিন্দু থাকা উচিত। উদাহরণ সংগঠন: commonMain/kotlin/com/project/platform expect ঘোষণা ধারণ করে, androidMain/kotlin/com/project/platform Android এর জন্য actual ধারণ করে, iosMain/kotlin/com/project/platform iOS এর জন্য actual ধারণ করে। ফাইল এবং প্যাকেজের নাম expect এবং actual উভয়ের জন্য অনুরূপ হতে হবে, যাতে একজন ডেভেলপার সহজে সংশ্লিষ্ট বাস্তবায়ন আবিষ্কার করতে পারে।
প্ল্যাটফর্ম ফ্যাক্টরি সহ ইন্টারফেস expect/actual এর মূল বিকল্প। একটি expect ক্লাসের পরিবর্তে, আপনি commonMain-এ একটি ইন্টারফেস ঘোষণা করতে পারেন এবং প্ল্যাটফর্ম মডিউলে কাঙ্ক্রিট ক্লাস তৈরি করতে পারেন। একটি ফ্যাক্টরি বা DI কন্টেনার রনটাইমে সঠিক বাস্তবায়ন প্রদান করে। এই পদ্ধতি পরীক্ষার জন্য উপযুক্ত, কারণ ইন্টারফেসটি মক করা যায়।
ডিপেন্ডেন্সি ইনজেক্শন (Koin, Kodein) একটি আরও নমনীয় কিন্তু কম দক্ষ পদ্ধতি। একটি DI কন্টেনার প্রতিটি প্ল্যাটফর্মের জন্য দল ভাবে কনফিগার করা হয় এবং সাধারণ কোডকে প্ল্যাটফর্ম নির্ভরতা প্রদান করে। expect/actual এর বিপরীতে, ইনজেক্শন রনটাইমে সংঘটিত হয়, যা পরীক্ষার জন্য বাস্তবায়ন স্যাপ করার অনুমতি দেয়। অপর দিকে, DI কনফিগারেশন ত্রুটি কেবল রনটাইমে শনাক্ত করা যায়, কম্পাইল টাইমে নয়।
| পদ্ধতি | কম্পাইল টাইম যাচাই | পরীক্ষার নমনীয়তা | রনটাইম ওভারহেড |
|---|---|---|---|
| expect/actual | পূর্ণ | কম (actual মজক করা যায় না) | শূন্য (কম্পাইল-টাইম বাংধন) |
| ইন্টারফেস + ফ্যাক্টরি | আংশিক | উচ্চ (মজক করা যায়) | সর্বনিম্ন (ভার্চুয়াল কল) |
| ডিপেন্ডেন্সি ইনজেক্শন | না (রনটাইম) | উচ্চ | মধ্যম (DI প্রঅক্সি) |
expect/actual এবং বিকল্পগুলির মধ্যে পছন্দ প্রসঙ্গের ঊপর নির্ভর করে। কার্যদক্ষতা-সমালোচনামূলক কোডের জন্য (গেম ইঞ্জিন, রিয়াল-টাইম প্রক্রিয়াকরণ), শূন্য ওভারহেডের কারণে expect/actual পছন্দনীয়। ব্যবসায়িক যুক্তি (রিপজিটরি, যুজ কেস) এর জন্য, পরীক্ষা সরল করতে DI সহ ইন্টারফেস ব্যবহার করা ভালো। একটি সংমিশ্র পদ্ধতি — নিম্ন-স্তরীয় প্ল্যাটফর্ম কাজের জন্য expect/actual এবং ব্যবসায়িক যুক্তি স্তরের জন্য ইন্টারফেস — অধিকাংশ প্রোডাক্শন KMM প্রকল্পে ব্যবহৃত হয়।
সামান্য জিজ্ঞাসা
expect/actual ভার্চুয়াল কল ছাড়া কম্পাইল টাইমে বাস্তবায়ন বাঁধে, যখন ইন্টারফেস রনটাইমে বাঁধে। expect/actual সকল প্ল্যাটফর্মের জন্য বাস্তবায়নের গারংটি দেয়, ইন্টারফেসের রনটাইম যাচাই প্রয়োজন।
হ্যাঁ, expect enum Kotlin 1.7 থেকে সমর্থিত। expect এবং actual enum উভয়ের সকল স্থিরাংক অবিশ্য মেলানো উচিত। বিভিন্ন প্ল্যাটফর্মে ভিন্ন স্থিরাংক মান একটি কম্পাইলেশন ভুল।
কম্পাইলার প্রতিটি প্ল্যাটফর্মের জন্য একটি ত্রুটি তৈরি করবে যেখানে actual বাস্তবায়ন প্রাপ্ত্যাহীন। সকল expect ঘোষণার জন্য সংশ্লিষ্ট actual বাস্তবায়ন যুক্ত না হয়া পর্যন্ত প্রকল্পটি তৈরি হবে না।
না, expect এবং actual আলাদা source setএ থাকা উচিত। expect commonMain বা একটি মধ্যবর্তী source setএ, actual একটি প্ল্যাটফর্ম source setএ। expect এবং actual একই source setএ রাখা একটি কম্পাইলেশন ত্রুটি।
expect/actual পরীক্ষার জন্য, প্ল্যাটফর্ম পরীক্ষা source set সহ commonTest ব্যবহার করুন। commonTest-এ expect পরীক্ষা এবং প্রতিটি প্ল্যাটফর্মের জন্য actual পরীক্ষা লিখুন। ইন্টিগ্রেশন পরীক্ষা প্রতিটি টার্গেট প্ল্যাটফর্মে পৃথক ভাবে চালানো হয়।
সারাংশ
আমরা একটি মোবাইল অ্যাপ্লিকেশন টার্নকি তৈরি করব
IT Sectr 2017 সাল থেকে স্টার্টআপ এবং ব্যবসার জন্য iOS এবং Android অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।
আরও পড়ুন