रहस्यमय «some»: हजारों डेवलपर्स इसके बारे में क्यों पूछते हैं?
\n\nयदि आपने कभी SwiftUI में लिखा है, तो आपने निश्चित रूप से some View संरचना देखी होगी। यह सरल दिखती है, लेकिन शुरुआती अक्सर भ्रमित हो जाते हैं: «यह «some» क्या है? मैं सिर्फ View क्यों नहीं लिख सकता? और अगर मैं some हटा दूं तो क्या यह टूट जाएगा?» प्रश्न «What is the "some" keyword in Swift(UI)?» ने Stack Overflow पर हजारों व्यूज एकत्र किए हैं - और यह कोई संयोग नहीं है। एक छोटे से शब्द के पीछे आधुनिक Swift का एक पूरा दर्शन छिपा है।
इस लेख में, हम समझेंगे कि some कीवर्ड क्या है, यह भाषा में क्यों आया और SwiftUI के बिना इसकी कल्पना क्यों नहीं की जा सकती। आप जानेंगे कि यह जेनेरिक, प्रोटोकॉल और «अपारदर्शी प्रकारों» (opaque types) से कैसे संबंधित है। और सबसे महत्वपूर्ण बात, आप समझेंगे कि कैसे अधिक स्वच्छ और अधिक कुशल कोड लिखा जाए।
\n\nसमस्या जिसे «some» हल करता है
\n\nकल्पना करें कि आप एक फ़ंक्शन लिख रहे हैं जो प्रोटोकॉल View के अनुरूप किसी ऑब्जेक्ट को लौटाता है। SwiftUI में ऐसा लगातार होता है:
func makeGreeting() -> View {\n return Text("Hello!")\n}\n\nSwift कंपाइलर कहेगा: «प्रोटोकॉल 'View' का उपयोग केवल एक सामान्य बाधा (generic constraint) के रूप में किया जा सकता है, क्योंकि इसमें Self या associated type requirements हैं»। यह डरावना लगता है, लेकिन सार सरल है: SwiftUI में प्रोटोकॉल View के लिए आवश्यक है कि प्रकार संकलन समय पर ज्ञात हो। यदि हम View लौटाते हैं - यह एक अमूर्तता है, और कंपाइलर को विशिष्टता चाहिए।
पहले, डेवलपर्स जेनेरिक के माध्यम से काम चलाते थे:
\n\nfunc makeGreeting<T: View>() -> T {\n return Text("Hello!") as! T\n}\n\nयह काम करता था, लेकिन एक अस्थायी समाधान जैसा दिखता था: आप कंपाइलर से वादा करते हैं कि आप T लौटाएंगे, लेकिन वास्तव में «दिखावा» करते हैं। साथ ही, कॉल करने वाले कोड को स्पष्ट रूप से प्रकार निर्दिष्ट करना पड़ता था। बदसूरत और असुरक्षित।
«Some» - बॉयलरप्लेट कोड से मुक्तिदाता
\n\nSwift में some कीवर्ड संस्करण 5.1 में ऐसे ही मामलों के लिए आया था। यह कंपाइलर से कहता है: «मैं एक विशिष्ट प्रकार लौटाऊंगा जो प्रोटोकॉल के अनुरूप है, लेकिन मैं इसका नाम नहीं बताना चाहता। आप स्वयं इसे संकलन समय पर निर्धारित करें»। इसे अपारदर्शी प्रकार (opaque type) कहा जाता है।
अपने उदाहरण पर वापस आते हैं:
\n\nfunc makeGreeting() -> some View {\n return Text("Hello!")\n}\n\nअब कोड संकलित होता है! कंपाइलर जानता है कि वास्तव में Text लौटाया जा रहा है, लेकिन बाहर से हम केवल some View देखते हैं। यह दो चीजें प्रदान करता है:
- \n
- प्रकार सुरक्षा - कंपाइलर जांचता है कि लौटाया गया प्रकार हमेशा एक ही हो। \n
- एनकैप्सुलेशन - हम कॉल करने वाले कोड से कार्यान्वयन विवरण छिपाते हैं। \n
तुलना: «some» बनाम जेनेरिक बनाम प्रोटोकॉल
\n\nsome के जादू को बेहतर ढंग से समझने के लिए, आइए एक विशिष्ट उदाहरण पर तीन दृष्टिकोणों की तुलना करें। मान लीजिए, हम एक फ़ंक्शन लिखना चाहते हैं जो एक आकृति (वृत्त या वर्ग) लौटाता है।
1. प्रोटोकॉल लौटाना (संकलित नहीं होगा)
\n\nprotocol Shape {\n func draw()\n}\n\nstruct Circle: Shape {\n func draw() { print("वृत्त बनाएं") }\n}\nstruct Square: Shape {\n func draw() { print("वर्ग बनाएं") }\n}\n\n// त्रुटि: प्रोटोकॉल 'Shape' का उपयोग रिटर्न प्रकार के रूप में नहीं किया जा सकता\nfunc makeShape() -> Shape {\n return Circle()\n}\n\nजैसा कि हम पहले से जानते हैं - यह काम नहीं करता है यदि प्रोटोकॉल में associated types या Self requirements हैं।
\n\n2. जेनेरिक का उपयोग
\n\nfunc makeShape<T: Shape>() -> T {\n // किसी तरह T बनाना होगा, लेकिन हम विशिष्ट प्रकार नहीं जानते\n fatalError("जेनेरिक बनाना असंभव")\n}\n\nसमस्या: कॉल करने वाले कोड को पता होना चाहिए कि किस प्रकार की अपेक्षा करनी है। फ़ंक्शन स्वयं यह तय नहीं कर सकता कि क्या लौटाना है।
\n\n3. «some» का उपयोग (पूरी तरह से काम करता है)
\n\nfunc makeShape() -> some Shape {\n