Opaque Type হলো Swift-এর একটি মেকানিজম যা একটি ফাংশনকে কলিং কোডে কংক্রিট টাইপ প্রকাশ না করেই কোনো টাইপের মান ফেরত দিতে দেয়। রিটার্ন টাইপে some কীওয়ার্ড সবচেয়ে বিখ্যাত উদাহরণ: SwiftUI-তে some View মানে “ফাংশনটি View-কে অনুসরণ করে এমন কোনো টাইপ ফেরত দেয়, কিন্তু ঠিক কোনটি — তা ইমপ্লিমেন্টেশনের বিবরণ।” Opaque type টাইপ আইডেন্টিটি সংরক্ষণ করে (একটি টাইপ হিসেবে প্রোটোকলের বিপরীতে), যা কম্পাইলারকে কোড অপ্টিমাইজ করতে এবং ফেরত দেওয়া টাইপের ধারাবাহিকতা নিশ্চিত করতে দেয়। Swift Book, 2025 অনুসারে, opaque types অ্যাসোসিয়েটেড টাইপ সহ প্রোটোকলের সমস্যা সমাধান করে, ফাংশন থেকে এই জাতীয় প্রোটোকলের মান ফেরত দেওয়ার অনুমতি দিয়ে।
মুখ্য বিষয়
Opaque Type হলো একটি রিটার্ন টাইপ যা some কীওয়ার্ড দিয়ে ঘোষণা করা হয় এবং কলিং কোড থেকে কংক্রিট ইমপ্লিমেন্টেশন লুকায়। কলার শুধু জানে যে ফেরত দেওয়া মান একটি নির্দিষ্ট প্রোটোকল অনুসরণ করে, কিন্তু জানে না some-এর পিছনে আসলে কোন টাইপ আছে। এদিকে, কম্পাইলার সঠিক টাইপ জানে এবং স্ট্যাটিক ডিসপ্যাচ ও অপ্টিমাইজেশনের জন্য এটি ব্যবহার করে।
Swift 5.1 (SE-0244)-এ opaque types চালুর আগে, বক্সিং র্যাপার ছাড়া ফাংশন থেকে অ্যাসোসিয়েটেড টাইপ সহ প্রোটোকল ফেরত দেওয়া অসম্ভব ছিল। উদাহরণস্বরূপ, Equatable প্রোটোকলের একটি অ্যাসোসিয়েটেড টাইপ আছে এবং একটি ফাংশন শুধু Equatable ফেরত দিতে পারত না — কম্পাইলার ত্রুটি দিত “প্রোটোকল শুধুমাত্র জেনেরিক কনস্ট্রেইন্ট হিসেবে ব্যবহার করা যাবে।” Opaque type এই সমস্যার সমাধান করেছে।
func makeInt() -> some Equatable {
return 42
}
func makeString() -> some Equatable {
return "Hello"
}
// কম্পাইলার জানে makeInt Int ফেরত দেয়
// makeInt() == makeString() — ❌ ত্রুটি, ভিন্ন টাইপ
উভয় ফাংশন some Equatable ফেরত দেয়, কিন্তু কংক্রিট টাইপ ভিন্ন: Int এবং String। তাদের == দিয়ে তুলনা করার চেষ্টা কম্পাইলেশন ত্রুটি সৃষ্টি করবে কারণ opaque type গ্যারান্টি দেয় যে একটি নির্দিষ্ট কল একই টাইপ ফেরত দেয়, কিন্তু ভিন্ন ফাংশনের মধ্যে নয়। এটি একটি বৈশিষ্ট্য, বাগ নয়: opaque type টাইপ আইডেন্টিটি সংরক্ষণ করে যেখানে একটি টাইপ হিসেবে প্রোটোকল (any Equatable) এটি হারায়।
Generic এবং Opaque Type একই মুদ্রার দুটি পিঠ। জেনেরিক কলিং কোডকে টাইপ বেছে নেওয়ার অনুমতি দেয়, যেখানে opaque type ফাংশনকে কলিং কোড থেকে টাইপ লুকানোর অনুমতি দেয়। পার্থক্যটি নিয়ন্ত্রণের দিকে।
| বৈশিষ্ট্য | Generic | Opaque some |
|---|---|---|
| কে টাইপ বেছে নেয় | কলিং কোড | ফাংশন/মেথড |
| টাইপ আইডেন্টিটি | সংরক্ষিত (স্থিতিশীল) | সংরক্ষিত (স্থিতিশীল) |
| রিটার্ন শাখার সংখ্যা | এক (জেনেরিকের মাধ্যমে) | সব শাখায় একই টাইপ |
| ব্যবহার | অ্যালগরিদম, ডেটা স্ট্রাকচার | SwiftUI, ফ্যাক্টরি মেথড |
একটি জেনেরিক ফাংশনে, কলার সিদ্ধান্ত নেয় কোন টাইপ ব্যবহার করবে। ফাংশনটিকে যেকোনো T-এর সাথে কাজ করতে হবে যা সীমাবদ্ধতা পূরণ করে। Opaque type-এর জন্য, কলার কংক্রিট টাইপ জানে না — ইমপ্লিমেন্টেশন সিদ্ধান্ত নেয়।
// Generic: কলার টাইপ বেছে নেয়
func identity<T>(_ value: T) -> T { value }
let x: Int = identity(42)
// Opaque: ফাংশন টাইপ লুকায়
func makeSomeEquatable() -> some Equatable { 42 }
let y = makeSomeEquatable()
জেনেরিক এবং opaque type-এর মধ্যে পছন্দ অভিপ্রায়-এর উপর নির্ভর করে। যদি কলিং কোডের টাইপ বেছে নেওয়া উচিত, তাহলে জেনেরিক ব্যবহার করুন। যদি ফাংশনের ইমপ্লিমেন্টেশন বিবরণ লুকানো উচিত, তাহলে some ব্যবহার করুন। SwiftUI some View বেছে নিয়েছে কারণ body অভ্যন্তরীণভাবে নমনীয় কিন্তু বাহ্যিকভাবে স্থিতিশীল হওয়া উচিত।
some হলো Swift 5.1 (SE-0244)-এ প্রবর্তিত একটি Swift কীওয়ার্ড। এটি রিটার্ন পজিশনে opaque type ঘোষণা করতে এবং প্যারামিটার (SE-0341) ও প্রপার্টিতেও ব্যবহৃত হয়। some গ্যারান্টি দেয় যে কংক্রিট টাইপ স্থিতিশীল এবং কম্পাইলারের জানা কিন্তু বাহ্যিক কোড থেকে লুকানো।
Swift 5.7 থেকে, some শুধু রিটার্ন পজিশনেই নয়, প্যারামিটারেও ব্যবহার করা যেতে পারে। প্যারামিটারে some Equatable মানে “এই ফাংশন যেকোনো Equatable টাইপ গ্রহণ করে, কিন্তু একটি নির্দিষ্ট বডির ভিতরে সব কল একই টাইপ দেখে।”
func areEqual(_ a: some Equatable, _ b: some Equatable) -> Bool {
// a এবং b — সম্ভাব্য ভিন্ন টাইপ, == সরাসরি কাজ করবে না
return isEqual(a, b)
}
func isEqual<T: Equatable>(_ a: T, _ b: T) -> Bool {
return a == b
}
প্যারামিটারে some ব্যবহার
any হলো Swift 5.6+-এর একটি কীওয়ার্ড যা এক্সিস্টেনশিয়াল টাইপ (একটি টাইপ হিসেবে প্রোটোকল) স্পষ্টভাবে ঘোষণা করার জন্য। some-এর বিপরীতে, any টাইপ আইডেন্টিটি মুছে ফেলে: কম্পাইলার জানে না প্রোটোকলের পিছনে কোন কংক্রিট টাইপ লুকানো আছে। এটি নমনীয়তা দেয় (আপনি একই অ্যারেতে বিভিন্ন টাইপ সংরক্ষণ করতে পারেন), কিন্তু কর্মক্ষমতার মূল্যে।
some — স্ট্যাটিক পলিমরফিজম: কম্পাইলার কংক্রিট টাইপ জানে, সরাসরি ডিসপ্যাচ ব্যবহার করে এবং কোড ইনলাইন করতে পারে। any — ডায়নামিক পলিমরফিজম: ভার্চুয়াল মেথড টেবিল (এক্সিস্টেনশিয়াল কন্টেইনার) ব্যবহার করা হয়, যা পরোক্ষতা যোগ করে।
protocol Drawable {
func draw()
}
// some: স্ট্যাটিক টাইপ পরিচিত
func makeDrawable() -> some Drawable {
return Circle() // একক রিটার্ন টাইপ
}
// any: ডায়নামিক, ভিন্ন টাইপ সংরক্ষণ করতে পারে
var shapes: [any Drawable] = [Circle(), Square()]
shapes.append(Triangle())
some এবং any-এর মধ্যে পছন্দ কর্মক্ষমতা এবং নমনীয়তার মধ্যে আপস। Some দ্রুততর কিন্তু একটি ইমপ্লিমেন্টেশনে সীমাবদ্ধ। Any অধিক নমনীয় (আপনি টাইপ মিশ্রিত করতে পারেন) কিন্তু ডায়নামিক ডিসপ্যাচের কারণে ধীর। SwiftUI-তে, body সবসময় some View ব্যবহার করে কারণ প্রতিটি View-এর body একটি কংক্রিট টাইপ।
Opaque Type Swift-এর একটি মৌলিক সমস্যা সমাধান করে: অ্যাসোসিয়েটেড টাইপ সহ প্রোটোকল (PAT) সরাসরি একটি টাইপ হিসেবে ব্যবহার করা যায় না। একটি ফাংশন শুধু Collection ফেরত দিতে পারে না — কম্পাইলার Element উল্লেখ করতে বলে। some Collection অ্যাসোসিয়েটেড টাইপ লুকিয়ে এটি সমাধান করে।
Opaque type ছাড়া, Collection ফেরত দিতে কংক্রিট টাইপ (Array
func makeReversedCollection<T>(
of array: [T]
) -> some Collection {
return array.reversed()
}
let result = makeReversedCollection(of: [1, 2, 3])
// result — ReversedCollection>, hidden from caller
for item in result {
print(item)
}
result-এ পুনরাবৃত্তি করা যেতে পারে, কিন্তু আপনি ReversedCollection-এর প্রপার্টিতে সরাসরি অ্যাক্সেস করতে পারবেন না। এটি এনক্যাপসুলেশন রক্ষা করে: যদি আপনি পরে reversed()-কে ভিন্ন ইমপ্লিমেন্টেশন সহ অন্য মেথড দিয়ে প্রতিস্থাপন করেন, কলিং কোড ভাঙবে না। Opaque type API না বদলেই ইমপ্লিমেন্টেশন পরিবর্তনের স্বাধীনতা দেয়।
some View হলো opaque type-এর সবচেয়ে বিখ্যাত ব্যবহার। SwiftUI-তে প্রতিটি View body-কে some View হিসেবে ঘোষণা করে। এর মানে body কোনো কংক্রিট টাইপের View ফেরত দেয়, কিন্তু ডেভেলপারকে ভাবতে হবে না এটি আসলে কী — TupleView, Group, ModifiedContent বা ফ্রেমওয়ার্কের অন্য কোনো টাইপ।
Opaque type ছাড়া, body-কে একটি কংক্রিট টাইপ ফেরত দিতে হতো, উদাহরণস্বরূপ, ModifiedContent<Button<Text>, Padding>, যা অবাস্তব। some View এই জটিলতা লুকায়। কম্পাইলার কম্পাইলেশনের সময় স্বয়ংক্রিয়ভাবে body-র সঠিক টাইপ অনুমান করে।
struct ContentView: View {
var body: some View {
VStack {
Text("হ্যালো")
.font(.title)
Button("আমাকে ট্যাপ করুন") {
print("ট্যাপ করা হয়েছে")
}
}
.padding()
}
}
কম্পাইলার body-কে ModifiedContent<VStack<TupleView<(Text, Button<Text>)>>, Padding> হিসেবে অনুমান করে। ডেভেলপার some View দেখে। আপনি যদি VStack থেকে HStack-এ লেআউট পরিবর্তন করেন, কম্পাইলার স্বয়ংক্রিয়ভাবে টাইপ পুনরায় অনুমান করবে — কোনো ম্যানুয়াল সম্পাদনার প্রয়োজন নেই। এটি opaque type-এর জাদু: ডেভেলপার ইন্টারফেস লজিকে মনোযোগ দেয়, কম্পোজিশন টাইপে নয়।
প্রায়শই জিজ্ঞাসিত প্রশ্ন
Opaque Type হলো একটি টাইপ যা some কীওয়ার্ড দিয়ে ঘোষণা করা হয় এবং কলিং কোড থেকে কংক্রিট ইমপ্লিমেন্টেশন লুকায়। কম্পাইলার সঠিক টাইপ জানে, কিন্তু ফাংশন ব্যবহারকারী ডেভেলপার শুধু প্রোটোকল দেখে।
some স্ট্যাটিক আইডেন্টিটি সহ opaque type: কম্পাইলার কংক্রিট টাইপ জানে। any ডায়নামিক ডিসপ্যাচ সহ এক্সিস্টেনশিয়াল টাইপ: টাইপ আইডেন্টিটি মুছে যায়। Some অধিক কার্যকর, any অধিক নমনীয়।
some View body-র জটিল কংক্রিট টাইপ লুকায়, যা কম্পাইলার স্বয়ংক্রিয়ভাবে অনুমান করে। এটি ডেভেলপারকে জেনেরিক র্যাপার (VStack, Group, ModifiedContent) দিয়ে তৈরি সঠিক টাইপ লেখার প্রয়োজন থেকে মুক্ত করে।
হ্যাঁ, Swift 5.7 থেকে। প্যারামিটারে some হলো জেনেরিক প্যারামিটারের উপর সিনট্যাকটিক সুগার। এটি ফাংশন ডিক্লেয়ারেশন সহজ করে, বিশেষ করে প্রোটোকলের সাথে কাজ করার সময় যেখানে প্রতিটি some-প্যারামিটারের জন্য আলাদা
কম্পাইলার ত্রুটি দেখাবে: opaque type আবশ্যক করে যে সব রিটার্ন শাখা একই কংক্রিট টাইপ ফেরত দেবে। এটি টাইপ আইডেন্টিটি সংরক্ষণের জন্য ইচ্ছাকৃত। যদি ভিন্ন টাইপ ফেরত দেওয়ার প্রয়োজন হয়, any ব্যবহার করুন।
সারসংক্ষেপ
আমরা একটি মোবাইল অ্যাপ্লিকেশন টার্নকি তৈরি করব
IT Sectr 2017 সাল থেকে স্টার্টআপ এবং ব্যবসার জন্য iOS এবং Android অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।
আরও পড়ুন