मैं भाषा और उसकी प्रकृति, साथ ही साथ मेरे डोमेन और यहां तक कि जिस तरह से हम भाषा का उपयोग करते हैं, उसके द्वारा C ++ में ऐसी अवधारणाओं को लागू करने के रूप में मैं पक्षपाती हूं। लेकिन इन बातों को देखते हुए, मुझे लगता है कि अपरिवर्तनीय डिजाइन कम से कम दिलचस्प पहलू हैं जब यह कार्यात्मक प्रोग्रामिंग से जुड़े लाभों के एक बड़े हिस्से को लेने की बात आती है, जैसे थ्रेड सुरक्षा, सिस्टम के बारे में तर्क करने में आसानी, फ़ंक्शंस के लिए अधिक पुन: उपयोग करना (और हम पा सकते हैं। अप्रिय आश्चर्य के बिना किसी भी क्रम में उन्हें मिलाएं), आदि।
इस सरलीकृत C ++ का उदाहरण लें (वहाँ किसी भी छवि प्रसंस्करण विशेषज्ञों के सामने खुद को शर्मिंदा करने से बचने के लिए सादगी के लिए अनुकूलित नहीं किया गया है):
// Inputs an image and outputs a new one with the specified size.
Image resized_image(const Image& src, int new_w, int new_h)
{
Image dst(new_w, new_h);
for (int y=0; y < new_h; ++y)
{
for (int x=0; x < new_w; ++x)
dst[y][x] = src.sample(x / (float)new_w, y / (float)new_h);
}
return dst;
}
जबकि उस फ़ंक्शन का कार्यान्वयन दो काउंटर चर के रूप में स्थानीय (और अस्थायी) राज्य को उत्परिवर्तित करता है और आउटपुट के लिए एक अस्थायी स्थानीय छवि है, इसका कोई बाहरी दुष्प्रभाव नहीं है। यह एक इमेज इनपुट करता है और एक नया आउटपुट देता है। हम इसे अपने दिलों की सामग्री तक बढ़ा सकते हैं। इसके बारे में तर्क करना आसान है, पूरी तरह से परीक्षण करना आसान है। यह अपवाद-सुरक्षित है क्योंकि अगर कुछ भी फेंकता है, तो नई छवि स्वचालित रूप से छोड़ दी जाती है और हमें बाहरी साइड इफेक्ट्स को वापस करने के बारे में चिंता करने की ज़रूरत नहीं है (फ़ंक्शन के दायरे के बाहर कोई बाहरी चित्र संशोधित नहीं किया जा सकता है, इसलिए बोलने के लिए)।
मुझे Image
उपर्युक्त संदर्भ में अपरिवर्तनीय बनाकर, प्राप्त करने के लिए बहुत कम देखा जा सकता है, और संभवतः खो जाने के लिए, संभवतः, उपरोक्त फ़ंक्शन को लागू करने के लिए और अधिक सटीक बनाने के लिए, और संभवतः थोड़ा कम कुशल को छोड़कर।
पवित्रता
इसलिए शुद्ध कार्य ( बाहरी दुष्प्रभावों से मुक्त ) मेरे लिए बहुत दिलचस्प हैं, और मैं सी ++ में भी टीम के सदस्यों को अक्सर उनके पक्ष में रखने के महत्व पर जोर देता हूं। लेकिन अपरिवर्तनीय डिज़ाइन, जो आमतौर पर अनुपस्थित संदर्भ और बारीकियों पर लागू होते हैं, लगभग मेरे लिए उतना दिलचस्प नहीं हैं, क्योंकि भाषा की अनिवार्य प्रकृति को देखते हुए, यह अक्सर कुशलतापूर्वक (दोनों की प्रक्रिया में कुछ स्थानीय अस्थायी वस्तुओं को बदलने में सक्षम होने के लिए उपयोगी और व्यावहारिक है डेवलपर और हार्डवेयर के लिए) एक शुद्ध फ़ंक्शन लागू करना।
हेफ्टी स्ट्रक्चर्स की सस्ती नकल
दूसरी सबसे उपयोगी संपत्ति जो मुझे मिली है वह यह है कि सस्ते में वास्तव में भारी डेटा संरचनाओं की नकल करने की क्षमता है जब ऐसा करने की लागत, जैसा कि अक्सर उनके सख्त इनपुट / आउटपुट प्रकृति को देखते हुए कार्यों को शुद्ध बनाने के लिए खर्च किया जाएगा, गैर-तुच्छ होगा। ये छोटे ढांचे नहीं होंगे जो स्टैक पर फिट हो सकते हैं। वे Scene
एक वीडियो गेम के लिए पूरी तरह से बड़े, भारी ढांचे होंगे ।
उस मामले में नकल ओवरहेड प्रभावी समानता के अवसरों को रोक सकता है, क्योंकि भौतिकी को समानांतर करना और एक दूसरे को लॉक और टोंटी के बिना प्रभावी ढंग से प्रतिपादन करना मुश्किल हो सकता है यदि भौतिकी उस दृश्य को उत्परिवर्तित कर रही है जो कि रेंडरर एक साथ आकर्षित करने की कोशिश कर रहा है, जबकि भौतिकी गहरी होने के साथ-साथ। लागू किए गए भौतिकी के साथ एक फ्रेम के उत्पादन के लिए पूरे खेल के दृश्य को कॉपी करें, समान रूप से अप्रभावी हो सकता है। हालांकि, अगर भौतिकी प्रणाली इस अर्थ में 'शुद्ध' थी कि यह केवल एक दृश्य को इनपुट करता है और भौतिकी के साथ एक नया आउटपुट करता है, और इस तरह की शुद्धता खगोलीय नकल उपरि की लागत पर नहीं आती है, तो यह सुरक्षित रूप से समानांतर रूप से संचालित हो सकता है। रेंडरर बिना किसी के इंतजार के।
तो सस्ते में आपके एप्लिकेशन स्टेट के वास्तविक डेटा को सस्ते में कॉपी करने की क्षमता और आउटपुट के लिए नए, संशोधित संस्करण प्रसंस्करण और मेमोरी उपयोग के लिए संशोधित संस्करण वास्तव में शुद्धता और प्रभावी समानता के लिए नए दरवाजे खोल सकते हैं, और मुझे सीखने के लिए बहुत सारे सबक मिलते हैं। कैसे लगातार डेटा संरचनाओं को लागू किया जाता है। लेकिन जो भी हम इस तरह के पाठों का उपयोग करते हैं वे पूरी तरह से स्थिर नहीं होते हैं, या अपरिहार्य इंटरफेस की पेशकश करते हैं (यह कॉपी-ऑन-राइट का उपयोग कर सकता है, उदाहरण के लिए, या "बिल्डर / क्षणिक"), इस क्षमता को प्राप्त करने के लिए गंदगी सस्ती हो। हमारे कार्यों / प्रणालियों / पाइपलाइन में समानता और शुद्धता के लिए हमारी खोज में मेमोरी उपयोग और मेमोरी एक्सेस को दोगुना किए बिना चारों ओर कॉपी करना और कॉपी करना।
अचल स्थिति
अंत में वहाँ अपरिवर्तनीयता है जिसे मैं इन तीनों में से सबसे कम दिलचस्प मानता हूं, लेकिन इसे लागू कर सकते हैं, एक लोहे की मुट्ठी के साथ, जब कुछ ऑब्जेक्ट डिज़ाइन का उपयोग स्थानीय अस्थायी के रूप में एक शुद्ध कार्य के लिए नहीं किया जाता है, और इसके बजाय एक व्यापक संदर्भ में, एक मूल्यवान "ऑब्जेक्ट-लेवल शुद्धता" की तरह, सभी तरीकों में अब बाहरी साइड इफेक्ट्स नहीं होते हैं (अब विधि के तत्काल स्थानीय दायरे के बाहर सदस्य परिवर्तनशील नहीं होते हैं)।
और जब मैं इसे C ++ जैसी भाषाओं में इन तीनों में से सबसे कम दिलचस्प मानता हूं, तो यह निश्चित रूप से गैर-तुच्छ वस्तुओं के परीक्षण और धागा-सुरक्षा और तर्क को सरल बना सकता है। यह गारंटी के साथ काम करने के लिए एक भार हो सकता है कि किसी वस्तु को उसके निर्माता के बाहर कोई अनूठा राज्य संयोजन नहीं दिया जा सकता है, उदाहरण के लिए, और यह कि हम इसे स्वतंत्र रूप से पास कर सकते हैं, यहां तक कि संदर्भ / सूचक द्वारा लगातार झुकाव के बिना और पढ़ें- केवल पुनरावृत्तियों और हैंडल और इस तरह, गारंटी देते समय (अच्छी तरह से, कम से कम जितना हम भाषा के भीतर कर सकते हैं) कि इसकी मूल सामग्री को उत्परिवर्तित नहीं किया जाएगा।
लेकिन मुझे यह सबसे कम दिलचस्प संपत्ति लगती है क्योंकि ज्यादातर वस्तुएं जिन्हें मैं अस्थायी रूप से, परस्पर रूप में उपयोग करने के लिए, एक शुद्ध कार्य (या यहां तक कि एक व्यापक अवधारणा, "शुद्ध प्रणाली" की तरह लागू करने के लिए, जो एक वस्तु या श्रृंखला हो सकती है, के रूप में फायदेमंद लगती है। केवल किसी चीज को इनपुट करने और कुछ और छूने के बिना कुछ नया आउटपुट करने के अंतिम प्रभाव के साथ कार्य करता है), और मुझे लगता है कि अति-अनिवार्य भाषा में चरम सीमाओं पर ले जाने वाली अपरिहार्यता एक बल्कि प्रति-उत्पादक लक्ष्य है। मैं इसे कोडबेस के उन हिस्सों के लिए लागू करूँगा जहाँ यह वास्तव में सबसे अधिक मदद करता है।
आखिरकार:
[...] ऐसा प्रतीत होता है कि लगातार डेटा संरचनाएं परिदृश्यों को संभालने के लिए पर्याप्त रूप से अपने आप में नहीं होती हैं जहां एक धागा एक ऐसा बदलाव करता है जो अन्य थ्रेड्स को दिखाई देता है। इसके लिए, ऐसा लगता है कि हमें परमाणुओं, संदर्भों, सॉफ्टवेयर लेनदेन स्मृति, या यहां तक कि क्लासिक ताले और सिंक्रनाइज़ेशन तंत्र जैसे उपकरणों का उपयोग करना चाहिए।
स्वाभाविक रूप से यदि आपका डिज़ाइन संशोधनों के लिए कहता है (उपयोगकर्ता-अंत डिज़ाइन अर्थ में) एक साथ कई थ्रेड्स को दिखाई देने के लिए, जैसा कि वे होते हैं, तो हम सिंक्रनाइज़ेशन या कम से कम ड्राइंग बोर्ड से निपटने के लिए कुछ परिष्कृत तरीके से काम करते हैं ( मैंने कार्यात्मक प्रोग्रामिंग में इन प्रकार की समस्याओं से निपटने वाले विशेषज्ञों द्वारा उपयोग किए गए कुछ बहुत विस्तृत उदाहरण देखे हैं)।
लेकिन मैंने पाया है, एक बार जब आप उस तरह की नकल करने की क्षमता और आंशिक रूप से संशोधित मोटी गंदगी के संस्करणों को आउटपुट करने की क्षमता प्राप्त करते हैं, जैसा कि आप एक उदाहरण के रूप में लगातार डेटा संरचनाओं के साथ प्राप्त करेंगे, तो यह अक्सर बहुत सारे दरवाजे और अवसरों को खोल देता है जो आप कर सकते हैं। कोड को समानांतर करने से पहले इस बारे में नहीं सोचा है कि समानांतर पाइपलाइन के सख्त I / O प्रकार में एक दूसरे से पूरी तरह से स्वतंत्र रूप से चल सकते हैं। भले ही एल्गोरिथ्म के कुछ हिस्सों को प्रकृति में धारावाहिक होना पड़ता है, आप उस प्रसंस्करण को एक ही धागे में बदल सकते हैं, लेकिन पाते हैं कि इन अवधारणाओं पर झुकाव ने आसानी से दरवाजे खोल दिए हैं, और चिंता के बिना, 90% विषम काम को समानांतर करते हैं, जैसे।