बहुत समय पहले मैंने जावा के बजाय स्काला का उपयोग शुरू नहीं किया था। मेरे लिए भाषाओं के बीच "रूपांतरण" प्रक्रिया Eitherका हिस्सा (चेक किए गए) के बजाय एस का उपयोग करना सीख रहा था Exception। मैं थोड़ी देर के लिए इस तरह से कोडिंग कर रहा हूं, लेकिन हाल ही में मैंने सोचा कि अगर यह वास्तव में जाने का एक बेहतर तरीका है।
एक प्रमुख लाभ Eitherयह है Exceptionकि बेहतर प्रदर्शन है; एक Exceptionढेर का पता लगाने का निर्माण करने की जरूरत है और फेंक दिया जा रहा है। जहाँ तक मुझे समझ में आता है, हालाँकि, फेंकना Exceptionमाँग का हिस्सा नहीं है, लेकिन स्टैक-ट्रेस का निर्माण करना है।
लेकिन फिर भी, एक हमेशा / इनहेरिट निर्माण कर सकते हैं Exceptionके साथ scala.util.control.NoStackTrace, और इससे भी अधिक, मैं मामलों के बहुत सारे देख जहां एक की बाईं ओर Eitherतथ्य एक में है Exception(प्रदर्शन को बढ़ावा देने forgoing)।
एक अन्य लाभ Eitherसंकलक-सुरक्षा है; Scala संकलक गैर-संभाला Exceptions (Java संकलक के विपरीत) के बारे में शिकायत नहीं करेगा । लेकिन अगर मैं गलत नहीं हूँ, तो यह निर्णय उसी तर्क के साथ लिया जाता है जिस पर इस विषय पर चर्चा की जा रही है, इसलिए ...
वाक्य रचना के संदर्भ में, मुझे लगता है कि Exception-स्टाइल रास्ता साफ है। निम्नलिखित कोड ब्लॉक की जांच करें (दोनों समान कार्यक्षमता प्राप्त करते हैं):
Either अंदाज:
def compute(): Either[String, Int] = {
val aEither: Either[String, String] = if (someCondition) Right("good") else Left("bad")
val bEithers: Iterable[Either[String, Int]] = someSeq.map {
item => if (someCondition(item)) Right(item.toInt) else Left("bad")
}
for {
a <- aEither.right
bs <- reduce(bEithers).right
ignore <- validate(bs).right
} yield compute(a, bs)
}
def reduce[A,B](eithers: Iterable[Either[A,B]]): Either[A, Iterable[B]] = ??? // utility code
def validate(bs: Iterable[Int]): Either[String, Unit] = if (bs.sum > 22) Left("bad") else Right()
def compute(a: String, bs: Iterable[Int]): Int = ???
Exception अंदाज:
@throws(classOf[ComputationException])
def compute(): Int = {
val a = if (someCondition) "good" else throw new ComputationException("bad")
val bs = someSeq.map {
item => if (someCondition(item)) item.toInt else throw new ComputationException("bad")
}
if (bs.sum > 22) throw new ComputationException("bad")
compute(a, bs)
}
def compute(a: String, bs: Iterable[Int]): Int = ???
उत्तरार्द्ध मुझे बहुत साफ दिखता है, और दोनों मामलों में विफलता को संभालने वाला कोड (या तो पैटर्न-मिलान Eitherया try-catch) बहुत स्पष्ट है।
तो मेरा सवाल है - क्यों इस्तेमाल Eitherकिया (जाँच) Exception?
अपडेट करें
उत्तर पढ़ने के बाद, मुझे एहसास हुआ कि मैं अपनी दुविधा के मूल को प्रस्तुत करने में विफल रहा हूँ। मेरी चिंता की कमी के साथ नहीं है try-catch; एक या तो एक के Exceptionसाथ "पकड़" सकता है Try, या catchअपवाद को लपेटने के लिए उपयोग कर सकता है Left।
मेरे साथ मुख्य समस्या Either/ Tryआती है जब मैं कोड लिखता हूं जो रास्ते में कई बिंदुओं पर विफल हो सकता है; इन परिदृश्यों में, जब एक विफलता का सामना करना पड़ता है, तो मुझे अपने पूरे कोड में उस विफलता का प्रचार करना पड़ता है, इस प्रकार कोड को और अधिक बोझिल बना दिया जाता है (जैसा कि पूर्वोक्त उदाहरणों में दिखाया गया है)।
वास्तव में कोड Exceptionका उपयोग किए बिना कोड को तोड़ने का एक और तरीका है return(जो वास्तव में स्काला में एक और "वर्जित" है)। Eitherदृष्टिकोण की तुलना में कोड अभी भी स्पष्ट होगा , और Exceptionशैली की तुलना में थोड़ा कम साफ होने के बावजूद , गैर-पकड़े गए Exceptionएस का कोई डर नहीं होगा ।
def compute(): Either[String, Int] = {
val a = if (someCondition) "good" else return Left("bad")
val bs: Iterable[Int] = someSeq.map {
item => if (someCondition(item)) item.toInt else return Left("bad")
}
if (bs.sum > 22) return Left("bad")
val c = computeC(bs).rightOrReturn(return _)
Right(computeAll(a, bs, c))
}
def computeC(bs: Iterable[Int]): Either[String, Int] = ???
def computeAll(a: String, bs: Iterable[Int], c: Int): Int = ???
implicit class ConvertEither[L, R](either: Either[L, R]) {
def rightOrReturn(f: (Left[L, R]) => R): R = either match {
case Right(r) => r
case Left(l) => f(Left(l))
}
}
मूल रूप से return Leftजगह throw new Exception, और या तो निहित विधि rightOrReturn, स्टैक अप स्वचालित अपवाद प्रचार के लिए एक पूरक है।
Try। Eitherबनाम के हिस्से के बारे में Exceptionकहा गया है कि Eitherएस का उपयोग तब किया जाना चाहिए जब विधि का दूसरा मामला "गैर-असाधारण" हो। सबसे पहले, यह एक बहुत, बहुत अस्पष्ट परिभाषा imho है। दूसरा, क्या यह वास्तव में वाक्यविन्यास दंड के लायक है? मेरा मतलब है, मैं वास्तव में Eitherएस का उपयोग करने में कोई आपत्ति नहीं करता अगर यह सिंटैक्स ओवरहेड के लिए नहीं होते जो वे प्रस्तुत करते हैं।
Eitherमेरे लिए एक सन्यासी की तरह दिखता है। इसका उपयोग तब करें जब आपको कार्यात्मक संरचना के लाभ की आवश्यकता होती है जो कि भिक्षु प्रदान करते हैं। या, शायद नहीं ।
Eitherअपने आप में एक सन्यासी नहीं है। प्रक्षेपण या तो बाईं ओर या दाईं ओर करने के लिए एक इकाई है, लेकिन Eitherअपने आप में नहीं है। आप इसे एक मोनाड बना सकते हैं, इसे "बायसिंग" करके या तो बाईं ओर या दाईं ओर कर सकते हैं, हालांकि। हालाँकि, तब आप दोनों पक्षों के एक निश्चित शब्दार्थ प्रदान करते हैं Either। स्काला Eitherमूल रूप से निष्पक्ष था, लेकिन हाल ही में पक्षपाती था, इसलिए कि आजकल, यह वास्तव में एक सनक है, लेकिन "मठ" एक निहित संपत्ति नहीं है Either, बल्कि इसके परिणामस्वरूप पक्षपाती है।