C = और Java '==' के लिए डिफ़ॉल्ट के रूप में संदर्भ समानता का उपयोग क्यों करते हैं?


32

मैं थोड़ी देर के लिए विचार कर रहा हूं कि जावा और सी # (और मुझे यकीन है कि अन्य भाषाएं) डिफ़ॉल्ट रूप से संदर्भ समानता के लिए ==

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

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

मैं तार्किक तुलना को लागू करने की कोशिश के साथ मुद्दों से अनभिज्ञ प्रतीत नहीं होना चाहता, और यह कि इसे हर वर्ग में लागू किया जाना चाहिए। मुझे यह भी पता है कि इन भाषाओं को बहुत समय पहले डिजाइन किया गया था, लेकिन सामान्य प्रश्न खड़ा है।

क्या इसे चूकने का कुछ बड़ा लाभ यह है कि मैं बस गायब हूँ, या यह उचित प्रतीत नहीं होता है कि डिफ़ॉल्ट व्यवहार तार्किक समानता होना चाहिए, और समानता को संदर्भित करने के लिए वापस डिफ़ॉल्ट करना यह तार्किक समानता वर्ग के लिए मौजूद नहीं है?


3
क्योंकि चर संदर्भ हैं? चूँकि चर
बिंदुओं

C # स्ट्रक् स जैसे मूल्य प्रकारों के लिए तार्किक समानता का उपयोग करता है। लेकिन विभिन्न संदर्भ प्रकारों की दो वस्तुओं के लिए "डिफ़ॉल्ट तार्किक समानता" क्या होनी चाहिए? या दो वस्तुओं के लिए जहां एक बी से विरासत में मिली A प्रकार की है? हमेशा "झूठे" जैसे स्ट्रक्चर्स के लिए? यहां तक ​​कि जब आपके पास एक ही वस्तु को दो बार संदर्भित किया जाता है, तो पहले ए, फिर बी के रूप में? मुझे कुछ बहुत ज्यादा समझ में नहीं आया।
डॉक्टर ब्राउन

3
दूसरे शब्दों में, क्या आप पूछ रहे हैं कि C # में क्यों, यदि आप ओवरराइड करते हैं Equals(), तो यह स्वतः के व्यवहार को नहीं बदलता है ==?
svick

जवाबों:


29

C # करता है क्योंकि Java ने किया है। जावा ने किया क्योंकि जावा ऑपरेटर ओवरलोडिंग का समर्थन नहीं करता है। चूंकि प्रत्येक वर्ग के लिए मूल्य समानता को फिर से परिभाषित किया जाना चाहिए, यह एक ऑपरेटर नहीं हो सकता है, बल्कि इसके लिए एक तरीका होना चाहिए। IMO यह एक खराब निर्णय था। यह लिखने और पढ़ने दोनों की a == bतुलना में बहुत आसान है a.equals(b), और सी या सी ++ अनुभव वाले प्रोग्रामर के लिए बहुत अधिक प्राकृतिक है, लेकिन a == bलगभग हमेशा गलत है। ==जहाँ .equalsआवश्यक थे , वहाँ के उपयोग से कीड़े ने प्रोग्रामर के अनगिनत हजारों घंटे बर्बाद कर दिए।


7
मुझे लगता है कि ऑपरेटर के उतने ही समर्थक हैं, जितने कि वहां से हटाने वाले हैं, इसलिए मैं यह नहीं कहूंगा कि "यह एक खराब निर्णय था" एक निरपेक्ष कथन है। उदाहरण: C ++ प्रोजेक्ट में हम काम करते हैं, हमने ==कई कक्षाओं के लिए ओवरलोड किया है और कुछ महीने पहले मुझे पता चला कि कुछ डेवलपर्स को पता नहीं ==था कि वास्तव में क्या कर रहा था। यह जोखिम हमेशा होता है जब कुछ निर्माण के शब्दार्थ स्पष्ट नहीं होते हैं। equals()अंकन मुझसे कहता है कि मैं एक कस्टम विधि का उपयोग कर रहा हूँ और मैं कहीं उसे ढूंढने की है। नीचे पंक्ति: मुझे लगता है कि ऑपरेटर ओवरलोडिंग सामान्य रूप से एक खुला मुद्दा है।
जियोर्जियो

9
मैं कहूंगा कि जावा में कोई उपयोगकर्ता-निर्धारित ऑपरेटर ओवरलोडिंग नहीं है। बहुत सारे ऑपरेटरों के जावा में दोहरे (ओवरलोडेड) अर्थ हैं। को देखो +उदाहरण के लिए, जो एक ही समय में और तार के संयोजन (अंकीय मान के) इसके अतिरिक्त है।
जोकिम सॉर

14
a == bC अनुभव वाले प्रोग्रामर के लिए अधिक स्वाभाविक कैसे हो सकता है, क्योंकि C उपयोगकर्ता-परिभाषित ऑपरेटर ओवरलोडिंग का समर्थन नहीं करता है? (उदाहरण के लिए, तार की तुलना करने का C तरीका है strcmp(a, b) == 0, नहीं a == b।)
svick

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

4
@ शविक: सी में, कोई स्ट्रिंग प्रकार नहीं है, न ही कोई संदर्भ प्रकार। स्ट्रिंग संचालन के माध्यम से किया जाता है char *। यह मुझे स्पष्ट प्रतीत होता है कि समानता के लिए दो बिंदुओं की तुलना करना एक स्ट्रिंग तुलना के समान नहीं है।
केविन क्लाइन

15

संक्षिप्त उत्तर: संगति

हालांकि, आपके सवाल का ठीक से जवाब देने के लिए, मेरा सुझाव है कि हम एक कदम पीछे ले जाएं और इस मुद्दे पर गौर करें कि प्रोग्रामिंग भाषा में समानता का क्या मतलब है। कम से कम तीन अलग-अलग संभावनाएं हैं, जो विभिन्न भाषाओं में उपयोग की जाती हैं:

  • संदर्भ समानता : इसका अर्थ है कि a और b एक ही वस्तु के संदर्भ में है तो a = b सत्य है। यह सही नहीं होगा यदि a और b को अलग-अलग वस्तुओं के लिए संदर्भित किया जाए, भले ही a और b के सभी गुण समान हों।
  • उथला समानता : इसका मतलब है कि a = b सत्य है यदि वस्तुओं के सभी गुण जिनके लिए a और b संदर्भ समान हैं। उथले समानता को आसानी से मेमोरी स्पेस की एक बिटवाइज़ तुलना द्वारा लागू किया जा सकता है जो दो वस्तुओं का प्रतिनिधित्व करता है। कृपया ध्यान दें कि संदर्भ समानता उथले समानता का अर्थ है
  • गहरी समानता : इसका अर्थ है कि a = b सत्य है यदि a और b में प्रत्येक गुण समान या गहरा समान है। कृपया ध्यान दें कि गहरी समानता संदर्भ समानता और उथले समानता दोनों से निहित है। इस अर्थ में, गहरी समानता समानता का सबसे कमजोर रूप है और संदर्भ समानता सबसे मजबूत है।

इन तीन प्रकार की समानता का उपयोग अक्सर किया जाता है क्योंकि वे लागू करने के लिए सुविधाजनक होते हैं: सभी तीन समानता की जांच आसानी से एक कंपाइलर द्वारा उत्पन्न की जा सकती है (गहरी समानता के मामले में, कंपाइलर को अनन्त छोरों को रोकने के लिए टैग बिट्स का उपयोग करने की आवश्यकता हो सकती है यदि कोई संरचना है तुलना किया जाना परिपत्र संदर्भ है)। लेकिन एक और समस्या है: इनमें से कोई भी उपयुक्त नहीं हो सकता है।

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

इसलिए हम आपके प्रश्न पर वापस आ सकते हैं:

क्या इसे चूकने का कुछ बड़ा लाभ यह है कि मैं बस गायब हूँ, या यह उचित प्रतीत नहीं होता है कि डिफ़ॉल्ट व्यवहार तार्किक समानता होना चाहिए, और यदि समानता तार्किक वर्ग के लिए मौजूद नहीं है तो संदर्भ समानता को वापस करना है?

किसी भी भाषा में 'a == b' लिखने पर हमें क्या मतलब है? आदर्श रूप से, यह हमेशा समान होना चाहिए: शब्दार्थ समानता। लेकिन यह संभव नहीं है।

मुख्य विचारों में से एक यह है कि, कम से कम सरल प्रकार की संख्याओं के लिए, हम उम्मीद करते हैं कि समान मूल्य के असाइनमेंट के बाद दो चर समान हैं। निचे देखो:

var a = 1;
var b = a;
if (a == b){
    ...
}
a = 3;
b = 3;
if (a == b) {
    ...
}

इस मामले में, हम उम्मीद करते हैं कि दोनों बयानों में 'एक बराबरी बी'। और कुछ भी पागल होगा। भाषाओं के अधिकांश (यदि सभी नहीं) इस सम्मेलन का अनुसरण करते हैं। इसलिए, सरल प्रकार (उर्फ मूल्यों) के साथ हम जानते हैं कि कैसे अर्थ समानता को प्राप्त करना है। वस्तुओं के साथ, यह पूरी तरह से अलग कुछ हो सकता है। निचे देखो:

var a = new Something(1);
var b = a;
if (a == b){
    ...
}
b = new Something(1);
a.DoSomething();
b.DoSomething();
if (a == b) {
    ...
}

हम उम्मीद करते हैं कि पहला 'अगर' हमेशा सच होगा। लेकिन दूसरे 'अगर ’पर आप क्या उम्मीद करते हैं? यह वास्तव में निर्भर करता है। क्या 'DoSomething' a और b की समानता (अर्थ) को बदल सकता है?

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

ऑपरेटरों के साथ, हालांकि, हम समान व्यवहार की उम्मीद करते हैं। जब आप 'a == b' देखते हैं, तो आपको सभी स्थितियों में एक ही प्रकार की समानता (4 से ऊपर) की अपेक्षा करनी चाहिए। तो, के लिए लक्ष्य स्थिरता भाषाओं सभी प्रकार के लिए इस्तेमाल किया संदर्भ समानता डिजाइनरों। यह इस बात पर निर्भर नहीं होना चाहिए कि एक प्रोग्रामर ने एक विधि को ओवरराइड किया है या नहीं।

पुनश्च: भाषा डी जावा और सी # से थोड़ी अलग है: बराबर ऑपरेटर का अर्थ है उपयोगकर्ता-परिभाषित वर्गों के लिए सरल प्रकार और अर्थ समानता के लिए उथले समानता (उपयोगकर्ता के साथ झूठ बोलने वाले = ऑपरेशन को लागू करने की जिम्मेदारी के लिए - कोई डिफ़ॉल्ट प्रदान नहीं किया जाता है)। के रूप में, सरल प्रकार के लिए, उथले समानता हमेशा शब्दार्थ समानता है, भाषा सुसंगत है। हालांकि, इसकी कीमत का भुगतान उपयोगकर्ता के परिभाषित प्रकारों के लिए डिफ़ॉल्ट ऑपरेटर द्वारा अपरिभाषित है। आपको इसे लागू करना होगा। और, कभी-कभी, यह सिर्फ उबाऊ है।


2
When you see ‘a == b’ you should expect the same type of equality (from the 4 above) in all situations.जावा के भाषा डिजाइनरों ने वस्तुओं के लिए संदर्भ समानता और आदिम के लिए शब्दार्थ समानता का उपयोग किया। मेरे लिए यह स्पष्ट नहीं है कि यह सही निर्णय था, या यह निर्णय ==वस्तुओं की शब्दार्थ समानता के लिए अतिभारित होने की अनुमति से अधिक "सुसंगत" है ।
चार्ल्स साल्विया

उन्होंने आदिम लोगों के लिए भी "संदर्भ समानता के समकक्ष" का इस्तेमाल किया। जब आप "int i = 3" का उपयोग करते हैं तो संख्या के लिए कोई संकेत नहीं होते हैं, इसलिए आप संदर्भ का उपयोग नहीं कर सकते। स्ट्रिंग्स के साथ, "एक प्रकार का" आदिम प्रकार, यह अधिक स्पष्ट है: आपको ".intern ()" या एक सीधा असाइनमेंट (स्ट्रिंग s = "abc") का उपयोग == (संदर्भ समानता) का उपयोग करना होगा।
होबस

1
पुनश्च: सी #, दूसरी ओर, यह तार के अनुरूप नहीं था। और IMHO, इस मामले में, यह बहुत बेहतर है।
होबस

@CharlesSalvia: में जावा, अगर aऔर bएक ही प्रकार, अभिव्यक्ति कर रहे हैं a==bकि क्या परीक्षण aऔर bएक ही बात पकड़ो। यदि उनमें से कोई एक वस्तु # 291 का संदर्भ रखता है, और दूसरा वस्तु # 572 का संदर्भ रखता है, तो वे एक ही बात नहीं रखते हैं। ऑब्जेक्ट की सामग्री # 291 और # 572 समतुल्य हो सकती है, लेकिन चर स्वयं अलग-अलग चीजों को धारण करते हैं।
१at

2
@CharlesSalvia इसे इस तरह से डिज़ाइन किया गया है कि आप इसे देख a == bऔर जान सकते हैं कि यह क्या करता है। इसी तरह, आप देख सकते हैं a.equals(b)और मानते हैं कि एक अधिभार है equals। यदि a == bकॉल a.equals(b)(यदि लागू हो), तो क्या यह संदर्भ या सामग्री द्वारा तुलना कर रहा है? याद नहीं है? आपको कक्षा ए की जांच करनी होगी। कोड अब पढ़ने के लिए उतने जल्दी नहीं है अगर आपको यह भी निश्चित नहीं है कि क्या कहा जा रहा है। यह वैसा ही होगा जैसे कि एक ही हस्ताक्षर वाले तरीकों की अनुमति दी गई थी, और कहा जा रहा तरीका वर्तमान गुंजाइश क्या है पर निर्भर करता है। ऐसे कार्यक्रमों को पढ़ना असंभव होगा।
नील

0

मैं यह सोचने की कोशिश कर रहा था कि इन दोनों भाषाओं ने इसे निष्क्रिय करने और == तार्किक समानता और उपयोग करने के बजाय इस मार्ग को क्यों चुना। संदर्भ संदर्भ के लिए। संदर्भ ()।

क्योंकि उत्तरार्द्ध दृष्टिकोण भ्रामक होगा। विचार करें:

if (null.ReferenceEquals(null)) System.out.println("ok");

क्या यह कोड प्रिंट "ok"होना चाहिए, या इसे फेंक देना चाहिए NullPointerException?


-2

जावा और C # के लिए लाभ उनके वस्तु उन्मुख होने में निहित है।

एक से देखने का प्रदर्शन बिंदु - लिखने कोड के लिए आसान भी तेज किया जाना चाहिए: के बाद से OOP तार्किक विशिष्ट तत्वों के लिए इरादा रखता विभिन्न वस्तुओं द्वारा प्रतिनिधित्व किए जाने, संदर्भ समानता जाँच तेज हो सकता है, को ध्यान में ले जा रहा है कि वस्तुओं काफी बड़ी बन सकता है।

एक से देखने का तार्किक बिंदु - दूसरे को कोई चीज की समानता समानता के लिए ऑब्जेक्ट के गुणों की तुलना के रूप में स्पष्ट रूप में होना करने के लिए (पूर्व कैसे अशक्त == बातिल तार्किक व्याख्या की है इस मामले को मामले से अलग कर सकते हैं।?) नहीं है।

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


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

@ JörgWMittag: ऑब्जेक्ट-ओरिएंटेड प्रोग्राम को ठीक से करने के लिए यह आवश्यक है कि ऑब्जेक्ट X से पूछने का एक साधन हो, चाहे उसका राज्य Y [एक संभावित क्षणिक स्थिति] के बराबर हो, और ऑब्जेक्ट X से पूछने का एक साधन भी हो, चाहे वह Y के बराबर हो। [X, Y के समतुल्य है यदि उसके राज्य को Y के समान अनंत काल की गारंटी दी जाती है]। समतुल्यता और राज्य-समानता के लिए अलग-अलग आभासी तरीके होना अच्छा होगा, लेकिन कई प्रकारों के लिए, संदर्भ असमानता गैर-तुल्यता होगी, और इसे साबित करने के लिए वर्चुअल विधि प्रेषण पर समय बिताने का कोई कारण नहीं है।
सुपरकैट

-3

.equals()उनकी सामग्री से चर की तुलना करता है। इसके बजाय ==उनकी सामग्री द्वारा वस्तुओं की तुलना ...

वस्तुओं का उपयोग करना अधिक सटीक तु का उपयोग है .equals()


3
आप धारणा गलत है। । असमान () जो कुछ भी करता है। असमान () को करने के लिए कोडित किया गया था। यह सामान्य रूप से सामग्री द्वारा होता है, लेकिन यह होना जरूरी नहीं है। इसके अलावा .equals () का उपयोग करना अधिक सटीक नहीं है। यह सिर्फ इस बात पर निर्भर करता है कि आप क्या हासिल करना चाहते हैं।
जिपर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.