2010-11-20 10 views
33

मेरी समझ यह है कि सी # में जेनेरिक के लिए भिन्नता निर्दिष्ट करना प्रकार घोषणा घोषणा स्तर पर होता है: जब आप अपना सामान्य प्रकार बनाते हैं, तो आप प्रकार तर्कों के लिए भिन्नता निर्दिष्ट करते हैं। जावा में, दूसरी तरफ, भिन्नता निर्दिष्ट होती है जहां एक सामान्य का उपयोग किया जाता है: जब आप कुछ सामान्य प्रकार का चर बनाते हैं, तो आप निर्दिष्ट करते हैं कि इसके प्रकार के तर्क अलग-अलग कैसे हो सकते हैं।जावा की उपयोग-साइट भिन्नता सी # की घोषणा साइट भिन्नता से तुलना कैसे करती है?

पेशेवरों और प्रत्येक विकल्प के विपक्ष क्या हैं?

+3

इस प्रश्न को छूने वाला एक पेपर: http://cgi.di.uoa.gr/~smaragd/varj-ecoop12.pdf – Aivar

उत्तर

36

मैं घोषणा-साइट और उपयोग-साइट भिन्नता के बीच मतभेदों का उत्तर देने जा रहा हूं, क्योंकि सी # और जावा जेनरिक कई अन्य तरीकों से भिन्न होते हैं, लेकिन अंतर भिन्नता के लिए अधिकतर ऑर्थोगोनल होते हैं।

सबसे पहले, अगर मुझे सही ढंग से उपयोग-साइट भिन्नता याद है तो घोषणा-साइट भिन्नता (हालांकि संयोजन की लागत पर) से कम शक्तिशाली है, या कम से कम जावा के वाइल्डकार्ड (जो वास्तव में उपयोग-साइट भिन्नता से अधिक शक्तिशाली हैं))। यह बढ़ी हुई शक्ति विशेष रूप से उन भाषाओं के लिए उपयोगी होती है जिनमें राज्यिक संरचनाओं का उपयोग भारी रूप से किया जाता है, जैसे कि सी # और जावा (लेकिन स्कैला बहुत कम है, खासकर जब से इसकी मानक सूचियां अपरिवर्तनीय हैं)। List<E> पर विचार करें (या IList<E>)। चूंकि इसमें ई को जोड़ने और ई प्राप्त करने के तरीकों के तरीके हैं, इसलिए यह ई के संबंध में परिवर्तनीय है, और इसलिए घोषणा-साइट भिन्नता का उपयोग नहीं किया जा सकता है। हालांकि, उपयोग-साइट भिन्नता के साथ आप List के contravariant सबसेट प्राप्त करने के लिए List और List<-Number> के कॉन्वर्सट सबसेट प्राप्त करने के लिए केवल List<+Number> कह सकते हैं। एक घोषणा-साइट भाषा में लाइब्रेरी के डिजाइनर को प्रत्येक सबसेट के लिए अलग-अलग इंटरफेस (या कक्षाएं यदि आप कक्षाओं के एकाधिक विरासत की अनुमति देते हैं) बनाना होगा और List उन इंटरफेस का विस्तार करें। यदि लाइब्रेरी डिज़ाइनर ऐसा नहीं करता है (ध्यान दें कि सी # IEnumerable केवल IList के कॉन्विएन्ट भाग का एक छोटा सबसेट करता है), तो आप भाग्य से बाहर हैं और आपको बिना किसी परेशानी के एक भाषा में करना होगा किसी प्रकार का भिन्नता।

तो घोषणा-साइट विरासत पर उपयोग-साइट विरासत के फायदे हैं। उपयोग-साइट विरासत पर घोषणा-स्थल विरासत का लाभ मूल रूप से उपयोगकर्ता के लिए संक्षिप्त है (बशर्ते डिजाइनर प्रत्येक वर्ग/इंटरफ़ेस को अपने कॉन्वर्सेंट और contravariant भागों में अलग करने के प्रयास के माध्यम से चला गया)। IEnumerable या Iterator जैसे कुछ के लिए, इंटरफ़ेस का उपयोग करने पर हर बार कॉन्वर्सिस निर्दिष्ट करना अच्छा नहीं है। जावा ने इसे एक लंबे वाक्यविन्यास का उपयोग करके विशेष रूप से परेशान कर दिया (बिविरिएंस को छोड़कर जिसके लिए जावा का समाधान मूल रूप से आदर्श है)।

बेशक, ये दो भाषा विशेषताएं सह-अस्तित्व में रह सकती हैं। टाइप पैरामीटर के लिए जो स्वाभाविक रूप से कॉन्वर्सेंट या contravariant (जैसे IEnumerable/Iterator में) हैं, घोषणा में ऐसा घोषित करें। स्वाभाविक रूप से इनवेरिएंट (जैसे कि (I)List) के प्रकार पैरामीटर के लिए, यह घोषणा करें कि प्रत्येक बार जब आप इसका उपयोग करते हैं तो आप किस तरह का भिन्नता चाहते हैं। घोषणा-साइट भिन्नता के साथ तर्कों के लिए बस उपयोग-साइट भिन्नता निर्दिष्ट न करें क्योंकि इससे चीजों को भ्रमित कर दिया जाता है।

ऐसे कई और विस्तृत मुद्दे हैं जिनमें मैं नहीं गया हूं (जैसे वाइल्डकार्ड वास्तव में उपयोग-साइट भिन्नता से अधिक शक्तिशाली हैं), लेकिन मुझे उम्मीद है कि यह आपकी सामग्री को आपके प्रश्न का उत्तर देगा। मैं मानता हूं कि मैं उपयोग-साइट भिन्नता की ओर पक्षपातपूर्ण हूं, लेकिन मैंने प्रोग्रामर और भाषा शोधकर्ताओं के साथ मेरी चर्चाओं में दोनों के प्रमुख फायदे चित्रित करने की कोशिश की।

+1

शानदार जवाब, धन्यवाद! उपयोग-साइट भिन्नता का उपयोग करके स्वचालित रूप से एक प्रकार को सह-और कॉन्ट्रैक्ट-वेरिएंट भागों में विभाजित करना कुछ ऐसा नहीं था जिसे मैंने सोचा था। – munificent

+7

@ शानदार ग्लेड आपको पसंद आया। वास्तव में इस वर्ष पीएलडीआई में एक पेपर आ रहा है, जिसमें पता चलता है कि जावा के घोषणा-साइट भिन्नता के 3 9% उपयोग-साइट भिन्नताएं (वाइल्डकार्ड में) को अनावश्यक बनाया जा सकता है, लेकिन इसका मतलब यह भी है कि 61% मामले अभिव्यक्ति के साथ अप्रचलित उपयोग करते हैं सह/अनुबंध/द्वि-संस्करण घटकों में कक्षाओं और इंटरफेस को तोड़ने के बिना -साइट भिन्नता। सोचा था कि आप उन आंकड़ों को दिलचस्प लग सकते हैं; मैंने निश्चित रूप से किया। –

+2

वाह, यह आश्चर्यजनक है। मुझे कम संख्या की उम्मीद होगी लेकिन तब जावा के पास उत्परिवर्तन को अलग करने की कोई विरासत नहीं है (यहां तक ​​कि 'इटरेटर ' के बाद 'हटाएं)) है, जो शायद समझ में आता है। असल में, मुझे आश्चर्य है कि उनमें से कितने मामले विशेष रूप से 'इटरेटर ' के कारण हैं। – munificent

14

अधिकांश लोगों घोषणा साइट विचरण पसंद करते हैं क्योंकि यह बनाता है यह उपयोगकर्ताओं पुस्तकालय की के लिए आसान (जबकि यह थोड़ा मुश्किल पुस्तकालय डेवलपर के लिए कर रही है, हालांकि मैं तर्क है पुस्तकालय डेवलपर के बारे में सोचना है कि लगता है जहां विचरण वास्तव में लिखा है की परवाह किए बिना विचरण।)

लेकिन ध्यान रखें, कि न तो जावा और न ही सी # अच्छा भाषा डिजाइन के उदाहरण हैं।

जबकि जावा विचरण सही और क्योंकि जावा 5 में संगत वीएम सुधार और टाइप-विलोपन की JVM की स्वतंत्र रूप से काम मिल गया, उपयोग साइट विचरण उपयोग थोड़ा बोझिल और के प्रकार-विलोपन विशेष कार्यान्वयन बनाता आकर्षित किया है अच्छी तरह से योग्य आलोचना।

सी # की घोषणा साइट विचरण के मॉडल बोझ पुस्तकालय के उपयोगकर्ता से दूर ले जाता है, लेकिन reified जेनरिक के अपने परिचय के दौरान वे मूल रूप से बनाया विचरण उनके वीएम में नियम। आज भी वे इस गलती के कारण सह-/ contravariance का पूरी तरह से समर्थन नहीं कर सकते हैं (और संशोधित संग्रह कक्षाओं के गैर पिछड़े-संगत परिचय ने प्रोग्रामर को दो शिविरों में विभाजित कर दिया है)।

यह सीएलआर को लक्षित करने वाली सभी भाषाओं पर एक कठिन प्रतिबंध है और यह एक कारण है कि वैकल्पिक प्रोग्रामिंग भाषाएं जेवीएम पर अधिक जीवंत हैं, हालांकि ऐसा लगता है कि सीएलआर में "बहुत अच्छी विशेषताएं हैं"।

चलो स्कैला देखें: स्कैला JVM पर चलने वाला एक पूर्ण ऑब्जेक्ट उन्मुख, कार्यात्मक संकर है। वे, जावा की तरह प्रकार विलोपन उपयोग करें, लेकिन समझने के लिए जावा के (या सी # के) की तुलना में, और अधिक सरल और शक्तिशाली दोनों जेनेरिक्स के कार्यान्वयन और (घोषणा-साइट) विचरण आसान होता है क्योंकि वीएम कैसे विचरण है पर नियमों को लागू नहीं काम करने के लिए। स्काला संकलक विचरण अंकन जाँच करता है और, कार्यावधि में अपवाद फेंक जिसके परिणामस्वरूप .class फ़ाइलें मूल जावा से इस्तेमाल किया जा सकता है, जबकि के बजाय संकलन समय पर अस्वस्थ स्रोत कोड अस्वीकार कर सकते हैं। घोषणा साइट विचरण के

एक नुकसान यह है कि यह कुछ मामलों में प्रकार निष्कर्ष कठिन बनाने के लिए लगता है।

एक ही समय में स्काला उन्हें @specialized एनोटेशन जो स्काला संकलक कक्षा या अनुरोध किया आदिम प्रकार के लिए विशेष विधि से एक या एक से अधिक अतिरिक्त कार्यान्वयन उत्पन्न करने के लिए कहता है का उपयोग करके सी # में तरह संग्रह में मुक्केबाजी के बिना आदिम प्रकार उपयोग कर सकते हैं।

स्काला भी "लगभग" जेनरिक प्रकट होता है जो उन्हें सी # में तरह कार्यावधि में सामान्य प्रकार पुनः प्राप्त करने के लिए अनुमति देता है का उपयोग करके वस्तु के बारे में जैसे सोचना कर सकते हैं। जावा शैली जेनरिक की

+0

यह सीएलआर को लक्षित करने वाली सभी भाषाओं पर एक कठिन प्रतिबंध है और वैकल्पिक कारण प्रोग्रामिंग भाषाएं हैं जेवीएम पर बहुत अधिक जीवंत है हालांकि ऐसा लगता है कि सीएलआर में "बहुत अच्छी विशेषताएं" हैं <- मुझे बकवास की तरह लगता है। .NET पर जावा स्टाइल जेनेरिक लागू करना मुश्किल नहीं होना चाहिए। बस उन्हें .NET समझ में गैर सामान्य बनाएं और उन्हें इस तरह से चिह्नित करें कि आपका कंपाइलर समझता है। – CodesInChaos

+0

और कह रहा है कि वैकल्पिक भाषाएं जेवीएम पर अधिक जीवंत हैं, शायद यह भी गलत है। दोनों प्लेटफॉर्म पर कई वैकल्पिक भाषाएं हैं। http://en.wikipedia.org/wiki/List_of_CLI_languages ​​ http://en.wikipedia.org/wiki/List_of_JVM_languages ​​ – CodesInChaos

+0

फिर आप बाइटकोड के साथ सभी इंटरऑपरेबिलिटी को खो देते हैं जो जेनेरिक का उपयोग करता है। हाल ही में सी # पर कितने जेनेरिक का उपयोग किया जाता है, यह तब तक कोई विकल्प नहीं है जब तक कि आप बिना किसी अंतःक्रियाशीलता वाली भाषा रखने की योजना बनाते हैं। और भाषाएं हैं और JVM में और भाषा विकास है। देखें कि माइक्रोसॉफ्ट ने हाल ही में आयरन रूबी और आयरनपीथन के लिए समर्थन कैसे छोड़ा। – soc

1

नुकसान

एक परिणाम यह है कि जावा संस्करण केवल संदर्भ प्रकार (या बॉक्सिंग मूल्य-प्रकार) और नहीं मूल्य-प्रकार के साथ काम करता है।आईएमओ यह सबसे बड़ा नुकसान है क्योंकि यह कई परिदृश्यों में उच्च प्रदर्शन जेनरिक को रोकता है और विशेष प्रकार के मैन्युअल लेखन की आवश्यकता होती है।

यह इस सूची की तरह गारंटी नहीं देता है कि "इस सूची में केवल प्रकार x की वस्तुएं हैं" और प्रत्येक गेटर पर रनटाइम चेक की आवश्यकता है। सामान्य प्रकार वास्तव में मौजूद है।

प्रतिबिंब का उपयोग करते समय आप एक जेनेरिक ऑब्जेक्ट का उदाहरण नहीं पूछ सकते जो सामान्य पैरामीटर है। जावा शैली जेनरिक की

लाभ

आप विचरण/विभिन्न सामान्य मापदंडों के बीच डाली कर सकते हैं।

+0

सी # में टाइप पैरामीटर के लिए भी भिन्नता है। मेरा प्रश्न इस बात के बारे में अधिक था कि साइट-वेरिएंस (जावा) कैसे घोषणा-साइट (सी #) की तुलना करता है और उन प्लेटफार्मों पर जेनेरिकों की समग्र तुलना नहीं करता है। – munificent

0

जावा: जावा 5 के बाद साइट-साइट भिन्नता जेनरिक।1.0 के बाद से एक अलग वाक्यविन्यास के साथ टूटा covariant सरणी। जेनेरिक की कोई रनटाइम प्रकार की जानकारी नहीं।

सी #: सी # 2.0 के बाद साइट-साइट भिन्नता जेनरिक। सी # 4.0 में घोषणा साइट भिन्नता जोड़ा गया। 1.0 के बाद से एक अलग वाक्यविन्यास के साथ टूटा covariant सरणी (जावा के लिए एक ही मुद्दा)। "संशोधित" जेनेरिक का अर्थ है कि संकलन समय पर टाइप जानकारी खो नहीं जाती है।

स्कैला: भाषा के शुरुआती संस्करणों (कम से कम 2008 के बाद से) दोनों साइट/घोषणा-साइट भिन्नता। Arrays एक अलग भाषा सुविधा नहीं हैं, इसलिए आप एक ही जेनेरिक वाक्यविन्यास का उपयोग करते हैं और भिन्नता नियम टाइप करते हैं। कुछ संग्रह VM स्तर पर JVM arrays के साथ कार्यान्वित किए जाते हैं ताकि आप जावा कोड की तुलना में बराबर या बेहतर रनटाइम प्रदर्शन प्राप्त कर सकें।

सी #/जावा सरणी प्रकार सुरक्षा समस्या पर विस्तृत करने के लिए: आप एक कुत्ते [] को पालतू जानवर [] में डाल सकते हैं और एक बिल्ली जोड़ सकते हैं और एक रनटाइम त्रुटि ट्रिगर कर सकते हैं जो संकलन समय पर पकड़ा नहीं जाता है। स्कैला ने इसे सही ढंग से कार्यान्वित किया।

संबंधित मुद्दे