2010-01-04 12 views
67

असाइन किए गए मान के बजाए इकाई को मूल्यांकन करने के लिए स्केल असाइनमेंट के लिए प्रेरणा क्या है?असाइन किए गए मान के बजाए इकाई को मूल्यांकन करने के लिए स्केल असाइनमेंट के लिए प्रेरणा क्या है?

आई/ओ प्रोग्रामिंग में एक आम पैटर्न इस तरह काम करने के लिए है:

while ((bytesRead = in.read(buffer)) != -1) { ... 

लेकिन इस स्काला में संभव नहीं है क्योंकि ...

bytesRead = in.read(buffer) 

.. रिटर्न यूनिट, नहीं बाइट्स का नया मान पढ़ें।

एक कार्यात्मक भाषा से बाहर निकलने के लिए एक दिलचस्प चीज़ की तरह लगता है। मुझे आश्चर्य है कि ऐसा क्यों किया गया था?

+0

डेविड पोलैक ने कुछ पहली हाथ की जानकारी पोस्ट की है, मार्टिन ओडरस्की ने टिप्पणी के जवाब में बहुत अधिक समर्थन किया है। मुझे लगता है कि कोई पोलैक के जवाब को सुरक्षित रूप से स्वीकार कर सकता है। –

उत्तर

66

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

+4

क्या स्कैला का एक कारण है कंपाइलर इस बात पर ध्यान नहीं दे सका कि असाइनमेंट का मूल्य वास्तव में उपयोग किया जाता है, और तदनुसार कुशल बाइटकोड उत्पन्न करता है? –

+39

सेटर्स की उपस्थिति में यह इतना आसान नहीं है: प्रत्येक सेटर को परिणाम वापस करना होगा, जो लिखने का दर्द है। फिर संकलक को इसे अनुकूलित करना होता है, जो कॉल में करना मुश्किल है। –

+0

आपका तर्क समझ में आता है, फिर भी जावा और सी # इसके खिलाफ हैं। मुझे लगता है कि आप जेनरेट बाइट कोड के साथ अजीब कुछ कर रहे हैं, फिर स्काला में क्लास फ़ाइल में संकलित कैसे किया जाएगा और जावा पर डिकंपिल्ड बैक कैसा दिखता है? –

5

मुझे लगता है कि यह कार्यक्रम/भाषा को दुष्प्रभावों से मुक्त रखने के लिए है।

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

+0

हे। साइड इफेक्ट्स से मुक्त स्केल? :) इसके अलावा, 'वैल ए = बी = 1' जैसे एक केस की कल्पना करें (' बी 'के सामने "जादुई" 'वैल' की कल्पना करें) बनाम' वैल ए = 1; वैल बी = 1; '। –

4

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

+2

मुझे लगता है कि यह एक बकवास कारण है! चूंकि ओपी पोस्ट किया गया था, कोड अभी भी संकलित और चलाता है: यह ऐसा नहीं करता है जिसे आप उचित रूप से उम्मीद कर सकते हैं। यह एक और गॉचा है, कम नहीं! –

+1

यदि आप कुछ लिखते हैं जैसे (ए = बी) यह संकलित नहीं होगा। तो कम से कम इस त्रुटि से बचा जा सकता है। – deamon

+1

ओपी ने '==' के बजाय '=' का उपयोग नहीं किया, उसने दोनों का उपयोग किया। वह असाइनमेंट को उस मान को वापस करने की अपेक्षा करता है जिसका उपयोग किया जा सकता है, उदाहरण के लिए, किसी अन्य मान की तुलना करने के लिए (उदाहरण में -1) – IttayD

16

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

यह कई तरीकों से करता है। उदाहरण के लिए, आपके पास for लूप नहीं है जहां आप एक चर घोषित करते हैं और उत्परिवर्तित करते हैं। आप स्थिति को जांचने के साथ ही while लूप पर स्थिति को आसानी से बदल नहीं सकते हैं, जिसका अर्थ है कि आपको अक्सर इसके पहले उत्परिवर्तन दोहराना पड़ता है, और इसके अंत में। while ब्लॉक के अंदर घोषित वैरिएबल while परीक्षण स्थिति से दिखाई नहीं दे रहे हैं, जो do { ... } while (...) बहुत कम उपयोगी बनाता है। और इसी तरह।

वर्कअराउंड:

while ({bytesRead = in.read(buffer); bytesRead != -1}) { ... 

जो कुछ के लिए इसके लायक है।

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

संपादित

David Pollack कुछ वास्तविक तथ्यों, जो स्पष्ट रूप तथ्य यह है कि Martin Odersky खुद अपने जवाब टिप्पणी की, प्रदर्शन से संबंधित मुद्दों तर्क पोलाक द्वारा प्रस्तुत को बल देने के द्वारा समर्थन कर रहे हैं के साथ answered है।

+3

तो संभवतः 'फॉर लूप संस्करण' होगा: '(बाइट्स रीड <- in.read (बफर) अगर (बाइट्स रीड)! = -1' जो महान है सिवाय इसके कि यह काम नहीं करेगा क्योंकि कोई' foreach' नहीं है और 'फिल्टर 'उपलब्ध है! –

8

यह स्कैला के हिस्से के रूप में अधिक "औपचारिक रूप से सही" प्रकार प्रणाली के रूप में हुआ। औपचारिक रूप से बोलने वाला, असाइनमेंट पूरी तरह से दुष्प्रभाव वाला कथन है और इसलिए Unit वापस करना चाहिए।इसका कुछ अच्छा परिणाम है; उदाहरण के लिए:

class MyBean { 
    private var internalState: String = _ 

    def state = internalState 

    def state_=(state: String) = internalState = state 
} 

state_= विधि क्योंकि असाइनमेंट लौटाने Unit रिटर्न Unit (के रूप में एक सेटर के लिए उम्मीद होगी) ठीक।

मैं मानता हूं कि सी-स्टाइल पैटर्न के लिए स्ट्रीम या इसी तरह की प्रतिलिपि बनाने के लिए, यह विशेष डिज़ाइन निर्णय थोड़ा परेशानी हो सकती है। हालांकि, यह वास्तव में अपेक्षाकृत असंभव है और वास्तव में प्रकार प्रणाली की समग्र स्थिरता में योगदान देता है।

+0

धन्यवाद, डैनियल। मुझे लगता है कि अगर मैं स्थिरता यह था कि दोनों असाइनमेंट और सेटर्स ने मूल्य वापस कर दिया है, तो मुझे यह पसंद आएगा! (ऐसा कोई कारण नहीं है कि वे नहीं कर सकते।) मुझे संदेह है कि मैं अवधारणाओं की बारीकियों को समझ नहीं रहा हूं अभी तक "पूरी तरह से दुष्प्रभावपूर्ण कथन" की तरह। –

+2

@ ग्राहम: लेकिन फिर, आपको स्थिरता का पालन करना होगा और अपने सभी सेटर्स में यह सुनिश्चित करना होगा कि वे जटिल हो जाएं, कि वे उनके द्वारा निर्धारित मूल्य वापस कर दें। यह होगा कुछ मामलों में जटिल है और अन्य मामलों में सिर्फ गलत है, मुझे लगता है। (त्रुटि के मामले में आप क्या वापस करेंगे? शून्य? - बल्कि नहीं। कोई नहीं? - तो आपका प्रकार विकल्प होगा [टी]।) मुझे लगता है कि यह लगातार कठिन है उसके साथ – Debilski

5

शायद यह command-query separation सिद्धांत के कारण है?

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

क्यों CQS उपयोगी है की एक छोटी चित्रण: एक List वर्ग है कि तरीकों Sort, Append, First, और Length साथ एक काल्पनिक संकर एफ/OO भाषा पर विचार करें।

func foo(x): 
    var list = new List(4, -2, 3, 1) 
    list.Append(x) 
    list.Sort() 
    # list now holds a sorted, five-element list 
    var smallest = list.First() 
    return smallest + list.Length() 

अधिक कार्यात्मक शैली में जबकि, एक अधिक होने की संभावना कुछ इस तरह लिखते थे: जरूरी OO शैली में, एक इस तरह एक समारोह में लिखने के लिए चाहते हो सकता है

func bar(x): 
    var list = new List(4, -2, 3, 1) 
    var smallest = list.Append(x).Sort().First() 
    # list still holds an unsorted, four-element list 
    return smallest + list.Length() 

ये कोशिश कर होने लगते हैं एक ही काम करने के लिए, लेकिन जाहिर है कि दोनों में से एक गलत है, और तरीकों के व्यवहार के बारे में और जानने के बिना, हम कौन नहीं बता सकते हैं।

सीक्यूएस का उपयोग करते हुए, हम जोर देकर कहते हैं कि Append और Sort सूची में परिवर्तन करने के लिए, उन्हें इकाई प्रकार वापस करना होगा, इस प्रकार हमें दूसरे फॉर्म का उपयोग करके बग बनाने से रोकना चाहिए जब हमें नहीं करना चाहिए। दुष्प्रभावों की उपस्थिति इसलिए विधि हस्ताक्षर में अंतर्निहित हो जाती है।

2

वैसे: मुझे जावा में भी प्रारंभिक जबकि-चाल बेवकूफ लगता है। इस तरह somethign क्यों नहीं?

for(int bytesRead = in.read(buffer); bytesRead != -1; bytesRead = in.read(buffer)) { 
    //do something 
} 

दी, असाइनमेंट दो बार दिखाई देता है, लेकिन कम से कम bytesRead गुंजाइश यह के अंतर्गत आता है में है, और मैं हास्यास्पद काम चाल के साथ खेल नहीं कर रहा हूँ ...

+0

कि चाल एक सुंदर आम है, यह आमतौर पर प्रत्येक ऐप में दिखाई देता है जो एक बफर के माध्यम से पढ़ता है। और यह हमेशा ओपी के संस्करण की तरह दिखता है। – TWiStErRob

1

आप इस के लिए एक समाधान हो सकता है जब तक आपके पास संकेत के लिए संदर्भ प्रकार हो। एक भयानक कार्यान्वयन में, आप मनमाना प्रकारों के लिए निम्नलिखित का उपयोग कर सकते हैं।

case class Ref[T](var value: T) { 
    def := (newval: => T)(pred: T => Boolean): Boolean = { 
    this.value = newval 
    pred(this.value) 
    } 
} 

फिर, बाधा आप बाद में संदर्भ का उपयोग करने की ref.value का उपयोग करना होगा कि के तहत, आप अपने while विधेय के रूप में

val bytesRead = Ref(0) // maybe there is a way to get rid of this line 

while ((bytesRead := in.read(buffer)) (_ != -1)) { // ... 
    println(bytesRead.value) 
} 

लिख सकते हैं और आप एक में bytesRead के खिलाफ जाँच कर सकते हैं इसे टाइप किए बिना अधिक अंतर्निहित तरीके।

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