प्रकार का हवाला देकर स्वचालित डाउनकास्टिंग


11

जावा में, आपको एक चर को कम करने के लिए स्पष्ट रूप से डालना चाहिए

public class Fruit{}  // parent class
public class Apple extends Fruit{}  // child class

public static void main(String args[]) {
    // An implicit upcast
    Fruit parent = new Apple();
    // An explicit downcast to Apple
    Apple child = (Apple)parent;
}

क्या इस आवश्यकता का कोई कारण है, इस तथ्य से अलग कि जावा किसी भी प्रकार का अनुमान नहीं करता है?

क्या किसी नई भाषा में स्वचालित डाउनकास्टिंग को लागू करने के साथ कोई "गोच" है?

उदाहरण के लिए:

Apple child = parent; // no cast required 

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

जवाबों:


24

Upcasts हमेशा सफल।

डाउनकास्ट के परिणामस्वरूप रनटाइम त्रुटि हो सकती है, जब ऑब्जेक्ट रनटाइम प्रकार कास्ट में उपयोग किए जाने वाले प्रकार का उपप्रकार नहीं है।

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

जब टाइप सिस्टम का संबंध होता है, तो upcasts ने कंपाइलर (जो इसे स्टेटिकली चेक करना होता है) पर प्रूफ का बोझ डाल दिया है, डाउनकास्ट्स ने प्रूफ का भार प्रोग्रामर पर डाल दिया है (जिसे इसके बारे में कठिन सोचना है)।

कोई यह तर्क दे सकता है कि एक ठीक से डिज़ाइन की गई प्रोग्रामिंग भाषा पूरी तरह से डाउनकास्ट से मना कर देगी, या सुरक्षित रूप से सुरक्षित विकल्प प्रदान करेगी, जैसे कि वैकल्पिक प्रकार Option<T>। हालांकि, कई व्यापक भाषाओं ने सरलता और अधिक व्यावहारिक दृष्टिकोण का चयन किया, बस Tअन्यथा वापस आना और अन्यथा एक त्रुटि उठाना।

आपके विशिष्ट उदाहरण में, कंपाइलर को यह कटौती करने के लिए डिज़ाइन किया जा सकता है कि parentवास्तव में Appleएक साधारण स्थैतिक विश्लेषण के माध्यम से, और निहित कलाकारों की अनुमति है। हालाँकि, सामान्य तौर पर समस्या अनिर्णायक है, इसलिए हम कंपाइलर से बहुत अधिक जादू करने की उम्मीद नहीं कर सकते हैं।


1
केवल संदर्भ के लिए, वैकल्पिक करने के लिए डाउनकास्ट करने वाली भाषा का एक उदाहरण रस्ट है, लेकिन ऐसा इसलिए है क्योंकि इसमें वास्तविक विरासत नहीं है, केवल एक "किसी भी प्रकार"
क्रोल्टन

3

आमतौर पर डाउनकास्टिंग आप ऐसा करते हैं जब संकलित ज्ञान संकलक के बारे में कुछ ऐसा होता है जो आप जानते हैं (या कम से कम उम्मीद) की तुलना में कम विशिष्ट है।

आपके उदाहरण जैसी स्थितियों में, ऑब्जेक्ट को एक के रूप में बनाया गया था Appleऔर फिर उस ज्ञान को रेफरेंस को प्रकार के एक चर में संग्रहीत करके फेंक दिया गया था Fruit। फिर आप फिर से उसी रेफ़रेंस का उपयोग करना चाहते हैं Apple

चूंकि जानकारी केवल "स्थानीय रूप से" फेंक दी गई थी, यकीन है, संकलक उस ज्ञान को बनाए रख सकता है parentजो वास्तव में एक है Apple, भले ही इसका घोषित प्रकार है Fruit

लेकिन आमतौर पर ऐसा कोई नहीं करता। यदि आप एक बनाना चाहते हैं Appleऔर इसे एक के रूप में उपयोग करना चाहते हैं Apple, तो आप इसे एक Appleनहीं बल्कि एक चर में संग्रहित करते हैं Fruit

जब आपके पास है Fruitऔर इसका उपयोग करना चाहते हैं, तो Appleइसका मतलब यह है कि आमतौर पर आपको Fruitकुछ साधनों के माध्यम से प्राप्त होता है जो आम तौर पर किसी भी प्रकार की वापसी कर सकता है Fruit, लेकिन इस मामले में आप जानते हैं कि यह एक था Apple। लगभग हमेशा आपने इसका निर्माण नहीं किया है, आपको इसे किसी अन्य कोड से पारित कर दिया गया है।

एक स्पष्ट उदाहरण है अगर मेरे पास एक parseFruitफ़ंक्शन है जो "सेब", "नारंगी", "नींबू", आदि जैसे तारों को उपयुक्त उपवर्ग में बदल सकता है; आम तौर पर हम सभी (और संकलक) इस फ़ंक्शन के बारे में जान सकते हैं कि यह किसी प्रकार का रिटर्न देता है Fruit, लेकिन अगर मैं फोन करता हूं, parseFruit("apple")तो मुझे पता है कि कॉल करने जा रहा है Appleऔर Appleविधियों का उपयोग करना चाह सकता है , इसलिए मैं डाउनकास्ट कर सकता हूं।

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

यथार्थवादी कोड डाउनकास्ट में आमतौर पर जहां कंपाइलर सत्यापित नहीं कर सकता है कि डाउनकास्ट जेनेरिक विधियों का उपयोग करके सुरक्षित है, और इस तरह के सरल मामलों में नहीं है क्योंकि तुरंत एक ही प्रकार की सूचना को फेंकने के बाद उसी प्रकार की जानकारी जिसे हम डाउनकास्टिंग द्वारा वापस पाने की कोशिश कर रहे हैं।


3

यह एक बात है कि आप कहां रेखा खींचना चाहते हैं। आप एक भाषा डिज़ाइन कर सकते हैं जो निहित डाउनकास्ट की वैधता का पता लगाएगी:

public static void main(String args[]) { 
    // An implicit upcast 
    Fruit parent = new Apple();
    // An implicit downcast to Apple 
    Apple child = parent; 
}

अब, आइए एक विधि निकालें:

public static void main(String args[]) { 
    // An implicit upcast 
    Fruit parent = new Apple();
    eat(parent);
}
public static void eat(Fruit parent) { 
    // An implicit downcast to Apple 
    Apple child = parent; 
}

हम अभी भी अच्छे हैं। स्थैतिक विश्लेषण बहुत कठिन है लेकिन अभी भी संभव है।

लेकिन समस्या यह है कि कोई व्यक्ति किसी दूसरे को जोड़ता है:

public static void causeTrouble() { 
    // An implicit upcast 
    Fruit trouble = new Orange();
    eat(trouble);
}

अब, आप त्रुटि कहां से उठाना चाहते हैं? यह एक दुविधा पैदा करता है, कोई कह सकता है कि समस्या अंदर है Apple child = parent;, लेकिन यह "लेकिन इससे पहले काम किया" द्वारा पुन: प्रस्तुत किया जा सकता है। दूसरे हाथ से, eat(trouble);इस समस्या का कारण है ", लेकिन बहुरूपता के पूरे बिंदु को वास्तव में अनुमति देना है।

इस मामले में, आप प्रोग्रामर के कुछ काम कर सकते हैं, लेकिन आप इसे पूरे तरीके से नहीं कर सकते। जितना अधिक आप इसे देने से पहले लेते हैं, उतना ही कठिन यह बताना होगा कि क्या गलत हुआ। इसलिए, त्रुटियों को जल्द रिपोर्ट करने के सिद्धांत के अनुसार, जितनी जल्दी हो सके रोकना बेहतर है।

BTW, जावा में आपके द्वारा वर्णित डाउनकास्ट वास्तव में डाउनकास्ट नहीं है। यह एक सामान्य कास्ट है, जो सेब को संतरे के रूप में अच्छी तरह से डाल सकता है। तो, तकनीकी रूप से @ चाई का विचार यहाँ पहले से ही है, जावा में कोई डाउनकास्ट नहीं हैं, केवल "एवरीकास्ट" हैं। यह एक विशेष डाउनकास्ट ऑपरेटर को डिजाइन करने के लिए समझ में आता है जो संकलन त्रुटि को फेंक देगा जब यह परिणाम प्रकार है यह तर्क प्रकार से डाउनस्ट्रीम नहीं पाया जा सकता है। प्रोग्रामर को हतोत्साहित करने के लिए बहुत ही अच्छे कारण के बिना उसे हतोत्साहित करने के लिए "एरोकास्ट" का उपयोग करना अधिक अच्छा होगा। C ++ का XXXXX_cast<type>(argument)सिंटैक्स दिमाग में आता है।

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