बहुत समय पहले मैंने जावा के बजाय स्काला का उपयोग शुरू नहीं किया था। मेरे लिए भाषाओं के बीच "रूपांतरण" प्रक्रिया Either
का हिस्सा (चेक किए गए) के बजाय एस का उपयोग करना सीख रहा था Exception
। मैं थोड़ी देर के लिए इस तरह से कोडिंग कर रहा हूं, लेकिन हाल ही में मैंने सोचा कि अगर यह वास्तव में जाने का एक बेहतर तरीका है।
एक प्रमुख लाभ Either
यह है Exception
कि बेहतर प्रदर्शन है; एक Exception
ढेर का पता लगाने का निर्माण करने की जरूरत है और फेंक दिया जा रहा है। जहाँ तक मुझे समझ में आता है, हालाँकि, फेंकना Exception
माँग का हिस्सा नहीं है, लेकिन स्टैक-ट्रेस का निर्माण करना है।
लेकिन फिर भी, एक हमेशा / इनहेरिट निर्माण कर सकते हैं Exception
के साथ scala.util.control.NoStackTrace
, और इससे भी अधिक, मैं मामलों के बहुत सारे देख जहां एक की बाईं ओर Either
तथ्य एक में है Exception
(प्रदर्शन को बढ़ावा देने forgoing)।
एक अन्य लाभ Either
संकलक-सुरक्षा है; Scala संकलक गैर-संभाला Exception
s (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
, बल्कि इसके परिणामस्वरूप पक्षपाती है।