extension function — একটি Kotlin প্রক্রিয়া যা বিদ্যমান ক্লাসে ইনহেরিটেন্স ছাড়া এবং সোর্স কোড পরিবর্তন না করে নতুন মেথড যোগ করার অনুমতি দেয়। ফাংশনটি একটি রিসিভার টাইপের উপসর্গ সহ ঘোষণা করা হয় এবং সেই টাইপের সাধারণ মেথডের মতো কল করা হয়। Kotlin Documentation, 2025 অনুযায়ী, extension functions প্রথম প্যারামিটার হিসেবে রিসিভার সহ স্ট্যাটিক মেথডে কম্পাইল হয়, যা সাধারণ কলের তুলনায় রানটাইমে শূন্য overhead নিশ্চিত করে।
মূল বিষয়
Extension function হল একটি ফাংশন যা ক্লাসের বাইরে ঘোষণা করা হয় কিন্তু তার মেথড হিসেবে কল করা হয়। এটি একটি রিসিভার টাইপ নেয় যাতে নতুন মেথড যোগ করা হয়। ফাংশনের ভিতরে, কীওয়ার্ড this রিসিভার টাইপের ইনস্ট্যান্সকে নির্দেশ করে। এই পদ্ধতি ফাইনাল ক্লাস, থার্ড-পার্টি লাইব্রেরি ক্লাস এবং এমনকি প্রিমিটিভ টাইপকেও র্যাপার তৈরি না করে এক্সটেন্ড করার অনুমতি দেয়।
Java-এর বিপরীতে, যেখানে বিদ্যমান ক্লাসে মেথড যোগ করার জন্য ইনহেরিটেন্স বা স্ট্যাটিক ইউটিলিটি ক্লাস প্রয়োজন, Kotlin boilerplate ছাড়া একটি মার্জিত সমাধান প্রদান করে। Kotlin Foundation গবেষণা (2024) অনুযায়ী, extension functions ভাষার পাঁচটি সবচেয়ে বেশি ব্যবহৃত বৈশিষ্ট্যের মধ্যে রয়েছে — 78% Kotlin ডেভেলপার তাদের দৈনন্দিন কাজে এগুলি ব্যবহার করেন।
Kotlin কম্পাইলার extension function-কে একটি স্ট্যাটিক মেথডে অনুবাদ করে যেখানে রিসিভার ইনস্ট্যান্স প্রথম আর্গুমেন্ট হিসেবে পাস করা হয়। এর অর্থ হল extension functions টার্গেট ক্লাসের বাইটকোড পরিবর্তন করে না এবং এনক্যাপসুলেশন ভঙ্গ করে না — শুধুমাত্র রিসিভারের পাবলিক ফিল্ড এবং মেথড অ্যাক্সেসযোগ্য।
পরিষ্কার ইউটিলিটি ফাংশন লিখতে extension functions ব্যবহার করুন যা যৌক্তিকভাবে একটি নির্দিষ্ট টাইপের সাথে আবদ্ধ কিন্তু তার সোর্স কোডে যোগ করা যায় না।
Extension function-এর মৌলিক সিনট্যাক্স: রিসিভার টাইপের নাম, একটি ডট, ফাংশনের নাম, তারপর প্যারামিটার এবং রিটার্ন টাইপ। ফাংশনের ভিতরে, রিসিভার this-এর মাধ্যমে অ্যাক্সেসযোগ্য।
// Extension function for String
fun String.isEmail(): Boolean {
return this.contains("@") && this.contains(".")
}
// Called as regular String method
val result = "user@example.com".isEmail() // true
এই উদাহরণে, isEmail() সব স্ট্রিং-এর জন্য উপলব্ধ হয়। ফাংশনের ভিতরে, this সেই স্ট্রিং-কে নির্দেশ করে যার উপর মেথড কল করা হয়। Kotlin অধিকাংশ ক্ষেত্রে this বাদ দেওয়ার অনুমতি দেয় — আপনি this.contains("@")-এর পরিবর্তে শুধু contains("@") লিখতে পারেন।
Extension functions অতিরিক্ত প্যারামিটার গ্রহণ করতে পারে এবং যেকোনো টাইপের মান ফেরত দিতে পারে। এটি এগুলিকে পূর্ণাঙ্গ ফাংশন করে তোলে, শুধু সিনট্যাকটিক সুগার নয়।
fun List<Int>.defaultIfEmpty(default: Int): List<Int> {
if (this.isEmpty()) return listOf(default)
return this
}
val populated = listOf(1, 2).defaultIfEmpty(0)
val empty = listOf<Int>().defaultIfEmpty(0)
default প্যারামিটার একটি খালি তালিকার জন্য ফেরত দেওয়া মান নির্ধারণ করে। Extension function জেনেরিক হতে পারে — List
Kotlin-এ extension functions স্ট্যাটিক ডিসপ্যাচ ব্যবহার করে, ভার্চুয়াল ডিসপ্যাচ নয়। এটি সাধারণ ক্লাস মেথড থেকে একটি মূল পার্থক্য। কোন extension function কল করা হবে তা কম্পাইল টাইমে ভেরিয়েবলের স্ট্যাটিক টাইপ দ্বারা নির্ধারিত হয়, তার প্রকৃত রানটাইম টাইপ দ্বারা নয়।
open class Animal
class Dog : Animal()
fun Animal.speak() = "Animal sound"
fun Dog.speak() = "Woof"
fun test() {
val animal: Animal = Dog()
println(animal.speak()) // "Animal sound" — static type Animal
val dog: Dog = Dog()
println(dog.speak()) // "Woof" — static type Dog
}
যদিও animal ভেরিয়েবল Dog-এর একটি ইনস্ট্যান্স নির্দেশ করে, Animal-এর জন্য extension function কল করা হয় কারণ ভেরিয়েবলের স্ট্যাটিক টাইপ Animal। যদি speak() একটি ভার্চুয়াল ক্লাস মেথড হতো, তাহলে Dog.speak() কল করা হতো। এই আচরণ extension functions দিয়ে API ডিজাইন করার সময় বিবেচনা করা গুরুত্বপূর্ণ।
Extension functions ক্লাসের সদস্য নয় — এগুলি সাধারণ ফাংশন যা অন্য ফাইলে ব্যবহারের জন্য ইম্পোর্ট প্রয়োজন। Kotlin ইম্পোর্টের দুটি বিকল্প প্রদান করে: ফাংশনের নাম অনুসারে বা নাম পরিবর্তন করে।
// Import by name
import com.example.extensions.isEmail
// Import with alias (to resolve conflicts)
import com.example.extensions.isEmail as isValidEmail
// Call after import
val valid = "test@test.com".isEmail()
as-এর মাধ্যমে নাম পরিবর্তন নামের দ্বন্দ্বের ক্ষেত্রে উপযোগী — উদাহরণস্বরূপ, যদি দুটি লাইব্রেরি একই টাইপের জন্য একই নামে extension function প্রদান করে। এই ক্ষেত্রে, আপনি তাদের একটিকে ভিন্ন নামে ইম্পোর্ট করতে পারেন এবং নতুন নাম ব্যবহার করে কল করতে পারেন।
Extension functions বিভিন্ন স্তরে ঘোষণা করা যেতে পারে:
| স্তর | দৃশ্যমানতা | উদাহরণ |
|---|---|---|
| Top-level | ইম্পোর্টের পরে পুরো প্রকল্প | fun String.isEmail() |
| Member extension | মালিক ক্লাসের ভিতরে | class A { fun B.ext() } |
| Local | একটি ফাংশনের ভিতরে | fun test() { fun String.ext() } |
Member extension functions একটি বিশেষ ক্ষেত্রে যেখানে extension function অন্য একটি ক্লাসের ভিতরে ঘোষণা করা হয়। এই ক্ষেত্রে, extension function-এর ভিতরে রিসিভার (ফাংশনের this) এবং বাইরের ক্লাসের সদস্য উভয়ই অ্যাক্সেসযোগ্য।
যদি একটি ক্লাসে extension function-এর মতো একই সিগনেচর সহ একটি মেথড থাকে, তবে ক্লাস সদস্যটি সর্বদা কল করা হয়। Extension function কখনই ক্লাস মেথড ওভাররাইড করে না — এটি আকস্মিক ওভাররাইড প্রতিরোধের জন্য একটি আর্কিটেকচারাল সিদ্ধান্ত।
class User {
fun greet() = "Hello from class"
}
fun User.greet() = "Hello from extension"
fun main() {
val user = User()
println(user.greet()) // "Hello from class"
}
এমনকি যদি extension function পরে সংজ্ঞায়িত করা হয় এবং একই সিগনেচর থাকে, কম্পাইলার ক্লাস মেথড বেছে নেবে। Kotlin কম্পাইলার এই ধরনের পরিস্থিতি শনাক্ত করলে একটি সতর্কতা জারি করে। ক্লাস মেথড থাকা অবস্থায় extension function কল করার একমাত্র উপায় হল এটিকে সাধারণ ফাংশন হিসেবে কল করা: greet(user)।
Android ডেভেলপমেন্টে, extension functions View, Context এবং fragments-এর সাথে কাজ করার জন্য একটি মানক টুল হয়ে উঠেছে। Android KTX লাইব্রেরি extension functions-এর উপর নির্মিত, যা Android API-এর উপর সুবিধাজনক র্যাপার প্রদান করে।
// Extension function for working with View
fun View.show() {
visibility = View.VISIBLE
}
fun View.hide() {
visibility = View.GONE
}
// Extension function for Context — toast
fun Context.toast(message: String) {
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
}
// Extension function as DSL builder
fun String.colorFormat(color: String): String =
"$color$this\u001b[0m"
toast() extension function Context-নির্ভর কলগুলিকে সংক্ষিপ্ত করে: Toast.makeText(context, message, length).show() লেখার পরিবর্তে, শুধু context.toast("টেক্সট") লেখা যথেষ্ট। এটি boilerplate হ্রাস করে এবং কোডকে আরও পাঠযোগ্য করে তোলে।
সচরাচর জিজ্ঞাসা
না, extension functions স্ট্যাটিক ডিসপ্যাচ ব্যবহার করে। আপনি যদি বেস ক্লাসের জন্য এবং সাবক্লাসের জন্য একই extension function ঘোষণা করেন, কোনটি কল হবে তা কম্পাইল টাইমে ভেরিয়েবলের স্ট্যাটিক টাইপ দ্বারা নির্ধারিত হয়, প্রকৃত রানটাইম টাইপ দ্বারা নয়।
আপনি nullable রিসিভার টাইপের জন্য extension functions ঘোষণা করতে পারেন: fun String?.isNullOrEmail()। এই জাতীয় ফাংশনের ভিতরে, this null হতে পারে, তাই আপনার নিরাপদ কল অপারেটর বা স্পষ্ট null পরীক্ষা ব্যবহার করা উচিত।
না, extension functions স্ট্যাটিক মেথডে কম্পাইল হয়। বাইটকোড স্তরে, extension function কল করা প্রথম প্যারামিটার হিসেবে রিসিভার সহ স্ট্যাটিক মেথড কল করার সমান। কোনো রিফ্লেকশন বা ডায়নামিক ডিসপ্যাচ জড়িত নয়।
হ্যাঁ, extension properties extension functions-এর মতো কাজ করে কিন্তু অবস্থা সংরক্ষণ করতে পারে না — শুধু getter এবং setter। উদাহরণস্বরূপ: val List
Java-তে আপনি StringUtils.isEmail(str) লেখেন, যেখানে Kotlin-এ আপনি str.isEmail() লেখেন। পার্থক্য শুধু সিনট্যাক্সের নয়: extension functions IDE-তে অটোকমপ্লিট সমর্থন করে, কল চেইনের পঠনযোগ্যতা উন্নত করে এবং IDE-কে একটি নির্দিষ্ট টাইপের জন্য প্রাসঙ্গিক ফাংশন suggest করার অনুমতি দেয়। Java-তে এই ক্ষমতাগুলি নেই।
সারসংক্ষেপ
আমরা একটি মোবাইল অ্যাপ্লিকেশন টার্নকি তৈরি করব
IT Sectr 2017 সাল থেকে স্টার্টআপ এবং ব্যবসার জন্য iOS এবং Android অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।
আরও পড়ুন