एक अच्छा सामान्य प्रकार की प्रणाली


29

यह आमतौर पर स्वीकार किया जाता है कि जावा जेनरिक कुछ महत्वपूर्ण तरीकों से विफल रहा। वाइल्डकार्ड और सीमा के संयोजन ने कुछ गंभीर रूप से अपठनीय कोड का नेतृत्व किया।

हालाँकि, जब मैं अन्य भाषाओं को देखता हूं, तो मुझे वास्तव में एक सामान्य प्रकार की प्रणाली नहीं मिल सकती है जिससे प्रोग्रामर खुश होते हैं।

यदि हम इस प्रकार के सिस्टम के डिजाइन लक्ष्य के रूप में निम्नलिखित लेते हैं:

  • हमेशा आसानी से पढ़े जाने वाले प्रकार की घोषणाएँ करता है
  • सीखने में आसान (कोविरेंस, कंट्रोवर्सी, इत्यादि पर ब्रश करने की आवश्यकता नहीं)
  • संकलन-समय त्रुटियों की संख्या को अधिकतम करता है

क्या कोई भाषा है जो इसे सही मिली? अगर मैं गूगल करता हूं, तो मुझे केवल एक ही चीज दिखाई देती है, वह यह है कि भाषा में टाइप सिस्टम कैसे चूसता है। क्या जेनेरिक टाइपिंग में इस तरह की जटिलता निहित है? क्या हमें संकलन समय पर 100% सुरक्षा को सत्यापित करने का प्रयास करना चाहिए?

मेरा मुख्य प्रश्न यह है कि इन तीन लक्ष्यों के संबंध में भाषा "सही है" सबसे अच्छी है। मुझे पता है कि यह व्यक्तिपरक है, लेकिन अभी तक मुझे एक भाषा भी नहीं मिल रही है, जहां सभी प्रोग्रामर इस बात से सहमत नहीं हैं कि सामान्य प्रकार की प्रणाली एक गड़बड़ है।

परिशिष्ट: जैसा कि उल्लेख किया गया है, उपप्रकार / विरासत और जेनरिक के संयोजन से जटिलता पैदा होती है, इसलिए मैं वास्तव में एक ऐसी भाषा की तलाश कर रहा हूं जो दोनों को जोड़ती है और जटिलता के विस्फोट से बचाती है।


2
आपका क्या मतलब है easy-to-read type declarations? तीसरा मानदंड भी अस्पष्ट है: उदाहरण के लिए, मैं सरणी अनुक्रमणिका को सीमा अपवादों से संकलित समय त्रुटियों में बदल सकता हूं, जब तक कि मैं संकलित समय पर सूचकांक की गणना नहीं कर सकता हूं, तब तक आपको अनुक्रमणिका सरणियों को न दें। इसके अलावा, दूसरा मानदंड सबटाइपिंग का नियम है। यह जरूरी नहीं कि एक बुरी चीज है लेकिन आपको इस बात की जानकारी होनी चाहिए कि आप क्या पूछ रहे हैं।
डोभाल


9
@gnat, यह निश्चित रूप से जावा के खिलाफ एक शेख़ी नहीं है। मैं जावा में लगभग विशेष रूप से कार्यक्रम करता हूं। मेरा कहना है कि यह आम तौर पर जावा समुदाय के भीतर स्वीकार किया जाता है कि जेनरिक त्रुटिपूर्ण हैं (कुल विफलता नहीं, लेकिन शायद एक आंशिक), इसलिए यह पूछना एक तार्किक प्रश्न है कि उन्हें कैसे लागू किया जाना चाहिए था। वे गलत क्यों हैं और क्या दूसरों ने उन्हें सही पाया है? या क्या वास्तव में जेनेरिक को पूरी तरह से प्राप्त करना असंभव है?
पीटर

1
क्या हर कोई C # से चोरी कर रहा था, कम शिकायतें होती। विशेष रूप से जावा नकल करके पकड़ने की स्थिति में है। इसके बजाय वे हीन समाधानों पर निर्णय लेते हैं। जावा डिजाइन समितियों में अभी भी चर्चा के कई सवाल पहले ही तय हो चुके हैं और C # में लागू किए गए हैं। वे दिखते भी नहीं हैं।
usr

2
@emodendroket: मुझे लगता है कि C # जेनरिक के बारे में मेरी दो सबसे बड़ी शिकायतें यह हैं कि "सुपरटाइप" बाधा (जैसे Foo<T> where SiameseCat:T) को लागू करने का कोई तरीका नहीं है और जेनेरिक प्रकार होने की कोई संभावना नहीं है जो परिवर्तनीय नहीं है Object। IMHO, .NET कुलीन प्रकारों से लाभान्वित होगा जो संरचनाओं के समान थे, लेकिन और भी नंगे-बंधुआ। यदि KeyValuePair<TKey,TValue>इस प्रकार के होते हैं, तो IEnumerable<KeyValuePair<SiameseCat,FordFocus>>कास्ट किया जा सकता है IEnumerable<KeyValuePair<Animal,Vehicle>>, लेकिन केवल तभी टाइप किया जा सकता है जब बॉक्सिंग नहीं किया जा सकता है।
सुपरकैट

जवाबों:


24

जबकि जेनरिक दशकों से कार्यात्मक प्रोग्रामिंग समुदाय में मुख्य धारा रहे हैं, ऑब्जेक्ट ओरिएंटेड प्रोग्रामिंग भाषाओं में जेनेरिक को जोड़ने से कुछ अनूठी चुनौतियां मिलती हैं, विशेष रूप से उपप्रकार और जेनरिक की बातचीत।

हालाँकि, भले ही हम ऑब्जेक्ट ओरिएंटेड प्रोग्रामिंग लैंग्वेज और विशेष रूप से जावा पर ध्यान केंद्रित करते हों, एक बेहतर जेनेरिक सिस्टम डिजाइन किया जा सकता था:

  1. जहाँ भी अन्य प्रकार हैं, सामान्य प्रकार स्वीकार्य होने चाहिए। विशेष रूप से, यदि Tएक प्रकार का पैरामीटर है, तो निम्नलिखित अभिव्यक्तियों को चेतावनी के बिना संकलित करना चाहिए:

    object instanceof T; 
    T t = (T) object;
    T[] array = new T[1];
    

    हां, इसके लिए भाषा में हर दूसरे प्रकार की तरह ही जेनेरिकों को भी शामिल करने की आवश्यकता होती है।

  2. जेनेरिक प्रकार के सहसंयोजक और विरोधाभासी को इसकी घोषणा में निर्दिष्ट किया जाना चाहिए (या इससे प्राप्त), हर बार सामान्य प्रकार का उपयोग करने के बजाय, इसलिए हम लिख सकते हैं

    Future<Provider<Integer>> s;
    Future<Provider<Number>> o = s; 
    

    बजाय

    Future<? extends Provider<Integer>> s;
    Future<? extends Provider<? extends Number>> o = s;
    
  3. जैसा कि सामान्य प्रकार लंबे समय तक प्राप्त कर सकते हैं, हमें उन्हें अनावश्यक रूप से निर्दिष्ट करने की आवश्यकता नहीं होनी चाहिए। यानी हमें लिखने में सक्षम होना चाहिए

    Map<String, Map<String, List<LanguageDesigner>>> map;
    for (var e : map.values()) {
        for (var list : e.values()) {
            for (var person : list) {
                greet(person);
            }
        }
    }
    

    बजाय

    Map<String, Map<String, List<LanguageDesigner>>> map;
    for (Map<String, List<LanguageDesigner>> e : map.values()) {
        for (List<LanguageDesigner> list : e.values()) {
            for (LanguageDesigner person : list) {
                greet(person);
            }
        }
    }
    
  4. किसी भी प्रकार को केवल संदर्भ प्रकार नहीं, बल्कि एक प्रकार के पैरामीटर के रूप में स्वीकार्य होना चाहिए। (अगर हमारे पास एक है int[], तो हम क्यों नहीं कर सकते हैं List<int>)?

यह सब C # में संभव है।


1
क्या इससे सेल्फ रेफरेंसियल जेनरिक से भी छुटकारा मिल जाएगा? क्या होगा अगर मैं कहना चाहता हूं कि एक तुलनीय वस्तु खुद की तुलना किसी भी प्रकार या उपवर्ग से कर सकती है? क्या ऐसा किया जा सकता है? या अगर मैं एक प्रकार की विधि लिखता हूं जो तुलनीय वस्तुओं के साथ सूचियों को स्वीकार करता है, तो सभी को एक दूसरे के साथ तुलना करने की आवश्यकता होती है। Enum एक और अच्छा उदाहरण है: Enum <E का विस्तार Enum <E >> है। मैं यह नहीं कह रहा हूं कि एक प्रकार की प्रणाली को ऐसा करने में सक्षम होना चाहिए, मैं बस उत्सुक हूं कि C # इन स्थितियों को कैसे संभालता है।
पीटर

1
जावा 7 के सामान्य प्रकार के अनुमान और C ++ के ऑटो इन चिंताओं में से कुछ के साथ मदद करते हैं, लेकिन सिंटैक्टिक चीनी हैं और अंतर्निहित तंत्र को नहीं बदलते हैं।

@Snowman जावा के प्रकार के निष्कर्ष में कुछ वास्तव में अप्रिय कोने के मामले हैं, जैसे कि अनाम कक्षाओं के साथ काम नहीं करना और वाइल्डकार्ड के लिए सही सीमा नहीं खोजना, जब आप किसी अन्य सामान्य विधि के तर्क के रूप में एक सामान्य विधि का मूल्यांकन करते हैं।
डोभाल

@ डोवल यही कारण है कि मैंने कहा कि यह कुछ चिंताओं के साथ मदद करता है: यह कुछ भी नहीं ठीक करता है, और सब कुछ संबोधित नहीं करता है। जावा जेनरिक में बहुत सारी समस्याएं हैं: जबकि कच्चे प्रकारों से बेहतर, वे निश्चित रूप से कई सिरदर्द पैदा करते हैं।

34

जेनेरिक प्रोग्रामिंग करते समय उपप्रकारों का उपयोग बहुत सारी जटिलताएं पैदा करता है। यदि आप उप-भाषाओं के साथ एक भाषा का उपयोग करने पर जोर देते हैं, तो आपको यह स्वीकार करना होगा कि जेनेरिक प्रोग्रामिंग में एक निश्चित अंतर्निहित जटिलता है जो इसके साथ आती है। कुछ भाषाएं इसे दूसरों की तुलना में बेहतर करती हैं, लेकिन आप इसे अभी तक ले सकते हैं।

उदाहरण के लिए हास्केल की जेनरिक के साथ विरोधाभास। वे काफी सरल हैं कि यदि आप प्रकार के अनुमान का उपयोग करते हैं, तो आप दुर्घटना से एक सही सामान्य कार्य लिख सकते हैं । वास्तव में, यदि आप किसी एकल प्रकार को निर्दिष्ट करते हैं, तो संकलक अक्सर खुद से कहता है, "ठीक है, मैं यह सामान्य बनाने जा रहा था , लेकिन आपने मुझे इसे केवल किलों के लिए बनाने के लिए कहा है, इसलिए जो भी हो।"

बेशक, लोग कुछ चौंकाने वाले जटिल तरीकों से हास्केल के प्रकार की प्रणाली का उपयोग करते हैं, जिससे यह हर नौसिखिया का बैन हो जाता है, लेकिन अंतर्निहित प्रकार की प्रणाली ही सुरुचिपूर्ण और बहुत प्रशंसनीय है।


1
इस उत्तर के लिए धन्यवाद। यह लेख जोशुआ बलोच के कुछ उदाहरणों से शुरू होता है, जहां जेनेरिक बहुत जटिल हो जाते हैं: artima.com/weblogs/viewpost.jsp?thread=222021 । क्या जावा और हास्केल के बीच की संस्कृति में यह अंतर है, जहां इस तरह के निर्माण को हास्केल में ठीक माना जाएगा, या क्या हास्केल के प्रकार प्रणाली में वास्तविक अंतर है जो ऐसी स्थितियों से बचा जाता है?
पीटर

10
@ पेटर हास्केल में सबटाइटलिंग नहीं है, और कार्ल ने कहा कि कंपाइलर प्रकारों को स्वचालित रूप से कम कर सकता है, जैसे कि बाधाएं जैसे "प्रकार aकुछ पूर्णांक होना चाहिए"।
डोभाल

दूसरे शब्दों में , कोवेरियन , स्कैला जैसी भाषाओं में।
पॉल ड्रेपर

14

लगभग 20 साल पहले होने वाले सबटाइपिंग के साथ जेनेरिक के संयोजन में काफी शोध हुआ था। एमआईटी में बारबरा लिस्कॉव के अनुसंधान समूह द्वारा विकसित थोर प्रोग्रामिंग भाषा में "जहां" क्लॉज़ की धारणा थी जो आपको उस प्रकार की आवश्यकताओं को निर्दिष्ट करने देती है जिस पर आप पैरामीटर बना रहे हैं। (यह सी + + के समान है जो अवधारणाओं के साथ करने की कोशिश कर रहा है ।)

थोर की जेनरिक का वर्णन करने वाला पेपर और वे थोर के उपप्रकारों के साथ कैसे बातचीत करते हैं: डे, एम; ग्रुबर, आर; लिस्कोव, बी; मायर्स, एसी: उप प्रकार बनाम जहां खंड: पैरामीट्रिक पोलिमोर्फ़िज्मके बाधित , Obj उन्मुख प्रोग्राम, Sys, लैंग और Apps पर एसीएम सम्मेलन , (OOPSLA-10): 156-158, 1995।

मेरा मानना ​​है कि वे बदले में, 1980 के दशक के दौरान एमराल्ड पर किए गए काम पर बने थे। (मैंने वह काम नहीं पढ़ा है, लेकिन संदर्भ है: ब्लैक, ए; हचिन्सन, एन; जूल , ई; लेवी, एच; कार्टर, एल: एमराल्ड में वितरण और सार प्रकार , _IEEE टी। सॉफ्टवेयर Eng।, 13 ( 1): 65-76, 1987।

थोर और एमराल्ड दोनों "अकादमिक भाषाएं" थीं, इसलिए उन्हें लोगों को वास्तव में यह समझने के लिए पर्याप्त उपयोग नहीं मिला कि जहां क्लॉज़ (अवधारणाएं) वास्तव में किसी भी वास्तविक समस्याओं को हल करती हैं। यह दिलचस्प है कि बज़्ने स्ट्रॉस्ट्रुप के लेख को पढ़ना क्यों कि C ++ में कॉन्सेप्ट्स में पहली कोशिश विफल रही: स्ट्रॉस्ट्रुप, बी: सी ++ 0x "कॉन्सेप्ट्स को हटाएं" निर्णय , डॉ। डॉब्स , 22 जुलाई, 2009। ( स्ट्रॉस्ट्रप के होम पेज पर आगे की जानकारी । )

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

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.