जब Go 1.18 ने 2022 में जनरिक्स का परिचय किया, तो इसने फ़ंक्शन और स्ट्रक्चर में जनरिक टाइप पैरामीटर लाए, लेकिन विधियों को छोड़ दिया। Go 1.27 के साथ, यह सीमाएँ हटा दी गई है। अब विधियाँ अपने स्वंय के प्रकार पैरामीटर परिभाषित कर सकती हैं बिना उन्हें प्राप्त करने वाले स्ट्रक्चर में जोड़े।
इस परिवर्तन का कारण क्या था? अगर आप एक ग्राफ़ नोड बनाना चाहते हैं जो एक जनरिक मान रखता है, तो आप इसे इस तरह से लागू कर सकते हैं:
type Node[T any] struct {
value T
}
कल्पना करें कि आप एक Map विधि जोड़ते हैं जो एक T प्रकार के नोड को एक अन्य प्रकार U के नोड में बदलती है। Go 1.27 से पहले, आपको U को सीधे Node स्ट्रक्चर में जोड़ना पड़ता था:
type Node[T any, U any] struct {
value T
}
func (n *Node[T, U]) Map() Node[T, U] {
// ...
}
U को स्ट्रक्चर में जोड़ना एक खराब डिज़ाइन है क्योंकि U Map का एक विशिष्ट प्रकार पैरामीटर है। हालाँकि अन्य विधियाँ U का उपयोग नहीं करेंगी, फिर भी उन्हें अपने रिसीवर घोषणाओं में इसे रखना पड़ता था। एकमात्र समाधान यह था कि Map को पैकेज-स्तर के फ़ंक्शन के रूप में लागू करें, न कि विधि के रूप में, क्योंकि फ़ंक्शन अपने स्वंय के प्रकार पैरामीटर परिभाषित कर सकते थे। लेकिन विधियाँ नहीं कर सकती थीं, जिससे कोड API डिज़ाइन अजीब और गैर-आधुनिक हो गए। Go 1.27 से शुरू करके, U को Map विधि पर ही परिभाषित किया जा सकता है:
func (n *Node[T]) Map[U any]() Node[U] {
// ...
}
इतना लंबा समय क्यों लगा? उत्तर Go में जनरिक्स के कार्यान्वयन के तरीके में है। कंपाइलर जनरिक्स को मुख्य रूप से मोनोमॉर्फ़िकेशन के माध्यम से संभालता है, जिसका अर्थ है कि वह प्रत्येक विशिष्ट प्रकार के लिए जनरिक स्ट्रक्चर या फ़ंक्शन की एक प्रति बनाएगा। क्योंकि किसीी न किसी समय पर, जनरिक्स की अमूर्त अवधारणा को सीधे मशीन कोड में बदलना पड़ता है। हालाँकि, Go का इंटरफ़ेस सिस्टम रनटाइम में काम करता है। इंटरफ़ेस पैरामीटर में पास किए गए मान के विशिष्ट प्रकार का समाधान प्रोग्राम चलते समय किया जाता है। इस गतिशील आवंटन के साथ जनरिक्स के समय पर समाधान के बीच टकराव होता है। विचार करें कि अगर हम अपने Map विधि को इंटरफ़ेस में घोषित करना चाहते हैं तो क्या होगा:
type Mapper interface {
Map T any, U any U
}
इसे काम कराने के लिए, रनटाइम को या तो Just-In-Time कंपाइलर की आवश्यकता होगी जो विशिष्ट प्रकारों के लिए मशीन कोड उत्पन्न करे, या यह प्रत्येक संभावित प्रकार के लिए इन कॉपीज़ को पहले से बनाने की आवश्यकता होगी, जिससे बाइनरी बहुत बड़ी हो जाएगी। अंत में, Go टीम ने निर्णय लिया कि जनरिक विधियों को इंटरफ़ेस से अलग कर दें। Go 1.27 वास्तविक प्रकारों पर जनरिक विधियों की अनुमति देता है, लेकिन इंटरफ़ेस पर नहीं। यह अंतर ही यह है कि ऊपर दिए गए उदाहरण को नहीं चलाया जा सकता और इसके चारों ओर चर्चा करने में कितना समय लगा।
स्रोत: Hacker News · HeadlinesBriefing द्वारा सारांशित