कम या ज्यादा सदस्य (अर्थात नेस्टेड) प्रकारों का उपयोग निर्भर विधि के प्रकार की आवश्यकता को जन्म दे सकता है। विशेष रूप से, मैं यह सुनिश्चित करता हूं कि निर्भर विधि के बिना क्लासिक केक पैटर्न एक विरोधी पैटर्न होने के करीब है।
तो समस्या क्या है? स्काला में नेस्टेड प्रकार उनके संलग्न उदाहरण पर निर्भर हैं। नतीजतन, आश्रित विधि प्रकारों की अनुपस्थिति में, उस उदाहरण के बाहर उनका उपयोग करने का प्रयास निराशाजनक रूप से कठिन हो सकता है। यह डिजाइनों को चालू कर सकता है जो शुरू में सुरुचिपूर्ण लगते हैं और मठों में आकर्षक लगते हैं जो बुरे तरीके से कठोर होते हैं और रिफ्लेक्टर के लिए मुश्किल होते हैं।
मैं बताता हूं कि मैं अपने एडवांस स्काला प्रशिक्षण पाठ्यक्रम के दौरान एक अभ्यास के साथ देता हूं ,
trait ResourceManager {
type Resource <: BasicResource
trait BasicResource {
def hash : String
def duplicates(r : Resource) : Boolean
}
def create : Resource
// Test methods: exercise is to move them outside ResourceManager
def testHash(r : Resource) = assert(r.hash == "9e47088d")
def testDuplicates(r : Resource) = assert(r.duplicates(r))
}
trait FileManager extends ResourceManager {
type Resource <: File
trait File extends BasicResource {
def local : Boolean
}
override def create : Resource
}
class NetworkFileManager extends FileManager {
type Resource = RemoteFile
class RemoteFile extends File {
def local = false
def hash = "9e47088d"
def duplicates(r : Resource) = (local == r.local) && (hash == r.hash)
}
override def create : Resource = new RemoteFile
}
यह क्लासिक केक पैटर्न का एक उदाहरण है: हमारे पास अमूर्तता का एक परिवार है जिसे धीरे-धीरे एक उत्तराधिकार के माध्यम से परिष्कृत किया जाता है ( ResourceManager
/ Resource
द्वारा परिष्कृत किया जाता है FileManager
/ File
जो बदले में NetworkFileManager
/ द्वारा परिष्कृत होते हैं RemoteFile
)। यह एक खिलौना उदाहरण है, लेकिन पैटर्न वास्तविक है: इसका उपयोग स्काला कंपाइलर में किया जाता है और इसका उपयोग स्केल एक्लिप्स प्लगइन में बड़े पैमाने पर किया जाता है।
यहाँ उपयोग में अमूर्तता का एक उदाहरण है,
val nfm = new NetworkFileManager
val rf : nfm.Resource = nfm.create
nfm.testHash(rf)
nfm.testDuplicates(rf)
ध्यान दें कि पथ निर्भरता का मतलब है कि संकलक गारंटी देगा कि testHash
और testDuplicates
विधियों को NetworkFileManager
केवल उन तर्कों के साथ बुलाया जा सकता है जो इसके अनुरूप हैं, अर्थात। यह अपना है RemoteFiles
, और कुछ नहीं।
यह निर्विवाद रूप से एक वांछनीय संपत्ति है, लेकिन मान लीजिए कि हम इस परीक्षण कोड को एक अलग स्रोत फ़ाइल में स्थानांतरित करना चाहते थे? आश्रित विधि प्रकारों के साथ यह ResourceManager
पदानुक्रम के बाहर उन विधियों को फिर से परिभाषित करने के लिए बहुत आसान है ,
def testHash4(rm : ResourceManager)(r : rm.Resource) =
assert(r.hash == "9e47088d")
def testDuplicates4(rm : ResourceManager)(r : rm.Resource) =
assert(r.duplicates(r))
यहां निर्भर विधि प्रकारों के उपयोग पर ध्यान दें: दूसरे तर्क का प्रकार ( rm.Resource
) पहले तर्क के मूल्य पर निर्भर करता है ( rm
)।
आश्रित विधि प्रकारों के बिना ऐसा करना संभव है, लेकिन यह बहुत ही अजीब है और तंत्र काफी अचूक है: मैं इस पाठ्यक्रम को लगभग दो वर्षों से सिखा रहा हूं, और उस समय में, कोई भी काम नहीं कर रहा है, जो बिना किसी समाधान के लागू हुआ है।
इसे अपने लिए आजमाएं ...
// Reimplement the testHash and testDuplicates methods outside
// the ResourceManager hierarchy without using dependent method types
def testHash // TODO ...
def testDuplicates // TODO ...
testHash(rf)
testDuplicates(rf)
इसके साथ संघर्ष करते हुए थोड़े समय के बाद आप शायद यह जान पाएंगे कि मैं (या शायद यह डेविड मैकाइवर क्यों था, हम याद नहीं कर सकते कि हममें से किसने यह शब्द गढ़ा था) इसे बेकरी ऑफ डूम कहते हैं।
संपादित करें: सर्वसम्मति है कि बेकरी ऑफ डूम डेविड मैकाइवर का सिक्का था ...
बोनस के लिए: स्कैला का सामान्य प्रकार में आश्रित प्रकार (और इसके एक भाग के रूप में आश्रित विधि प्रकार) प्रोग्रामिंग भाषा बीटा से प्रेरित था ... वे स्वाभाविक रूप से बीटा के सुसंगत घोंसले के शिकार से उत्पन्न होते हैं। मैं किसी अन्य भी बेहोश मुख्यधारा प्रोग्रामिंग भाषा के बारे में नहीं जानता, जिसके इस रूप में निर्भर प्रकार हैं। Coq, Cayenne, Epigram और Agda जैसी भाषाओं में आश्रित टाइपिंग का एक अलग रूप है, जो कुछ मायनों में अधिक सामान्य है, लेकिन जो कि स्केला के विपरीत, टाइप सिस्टम का हिस्सा होने के कारण काफी अलग है, इसमें सबटाइपिंग नहीं है।