डी

2013-05-16 10 views
6

में बतख टाइपिंग मैं डी के लिए नया हूं, और मैं सोच रहा था कि संकलन-समय-चेक ​​बतख टाइपिंग आसानी से करना संभव है या नहीं।डी

उदाहरण के लिए, मैं विधियों का एक सेट परिभाषित करना चाहता हूं, और यह आवश्यक है कि उन तरीकों को किसी फ़ंक्शन में पारित किए जाने वाले प्रकार के लिए परिभाषित किया जाए। यह डी में interface से थोड़ा अलग है क्योंकि मुझे यह घोषणा नहीं करना पड़ेगा कि "टाइप एक्स इंटरफ़ेस वाई लागू करता है" - विधियों को अभी मिलेगा, या संकलन विफल हो जाएगा। साथ ही, यह किसी भी प्रकार, न केवल structs और कक्षाओं पर होने की अनुमति देना अच्छा होगा। केवल संसाधन मैं मिल सकता है this email thread था, जिससे पता चलता है कि निम्नलिखित दृष्टिकोण यह करने के लिए एक सभ्य तरीका होगा:

void process(T)(T s) 
    if(__traits(hasMember, T, "shittyNameThatProbablyGetsRefactored")) 
    // and presumably something to check the signature of that method 
{ 
    writeln("normal processing"); 
} 

... और पता चलता है कि आप इतना है कि निम्नलिखित एक पुस्तकालय कॉल इम्प्लीमेन्ट्स में शामिल नहीं हो सका संभव होगा:

struct Interface { 
    bool foo(int, float); 
    static void boo(float); 
    ... 
} 

static assert (Implements!(S, Interface)); 
struct S { 
    bool foo(int i, float f) { ... } 
    static void boo(float f) { ... } 
    ... 
} 

void process(T)(T s) if (Implements!(T, Interface)) { ... } 

उन कार्यों के लिए ऐसा करना संभव है जो कक्षा या संरचना में परिभाषित नहीं हैं? क्या ऐसा करने के लिए अन्य/नए तरीके हैं? क्या कुछ भी ऐसा ही किया गया है?

जाहिर है, बाधाओं का यह सेट गो के प्रकार प्रणाली के समान है। मैं किसी भी लौ युद्ध शुरू करने की कोशिश नहीं कर रहा हूं - मैं बस डी का उपयोग इस तरह से कर रहा हूं कि गो भी अच्छी तरह से काम करेगा।

+0

क्या आप सभी उपयोग मामलों को संभालने के लिए एक ही फ़ंक्शन बनाने की कोशिश कर रहे हैं? मुझे लगता है कि इसके लिए [स्थैतिक foreach] की आवश्यकता होगी (http://d.puremagic.com/issues/show_bug.cgi?id=4085), लेकिन मुझे यकीन नहीं है। शायद कुछ सीटीएफई जादू काम करेगा? इसके अलावा ब्याज: http://www.digitalmars.com/d/archives/digitalmars/D/static_foreach_108369.html – tjameson

+0

@tjameson हां, मुझे ऊपर दिए गए उदाहरण के लिए विश्वास है कि आपको अपने 'इंटरफ़ेस में जो भी तरीके परिभाषित किया गया है, उसके माध्यम से आपको लूप करना होगा संकलन समय पर संरचना। हालांकि, यदि वे मौजूद हैं तो मैं एक ही लक्ष्य को प्राप्त करने के अन्य तरीकों के लिए भी खुला हूं। – Dan

+0

डी लपेट गया है और अनचाहे है (http://dlang.org/phobos-prerelease/std_typecons.html#.wrap और http://dlang.org/phobos-prerelease/std_typecons.html#.unwrap) गो के समान सुविधा प्रदान करें बतख टाइपिंग। – DejanLekic

उत्तर

7

यह वास्तव में डी में करने के लिए एक बहुत ही आम बात है। यह कैसे काम करता है। उदाहरण के लिए, रेंज के सबसे बुनियादी प्रकार - इनपुट रेंज - 3 कार्यों होना चाहिए:

bool empty(); //Whether the range is empty 
T front(); // Get the first element in the range 
void popFront(); //pop the first element off of the range 

वाली टेम्प्लेट कार्यों तो है कि क्या एक प्रकार किसी मान्य श्रेणी है की जाँच करने के std.range.isInputRange का उपयोग करें। उदाहरण के लिए, std.algorithm.find का सबसे बुनियादी अधिभार लग रहा है

R find(alias pred = "a == b", R, E)(R haystack, E needle) 
if (isInputRange!R && 
    is(typeof(binaryFun!pred(haystack.front, needle)) : bool)) 
{ ... } 

isInputRange!R तरह true है अगर R एक मान्य इनपुट रेंज है, और is(typeof(binaryFun!pred(haystack.front, needle)) : bool)true है अगर predhaystack.front और needle स्वीकार करता है और एक प्रकार है जो परोक्ष bool के लिए परिवर्तनीय है देता है। तो, यह अधिभार पूरी तरह से स्थिर बतख टाइपिंग पर आधारित है।

isInputRange खुद के लिए के रूप में, ऐसा लगता है कि

template isInputRange(R) 
{ 
    enum bool isInputRange = is(typeof(
    { 
     R r = void;  // can define a range object 
     if (r.empty) {} // can test for empty 
     r.popFront();  // can invoke popFront() 
     auto h = r.front; // can get the front of the range 
    })); 
} 

कुछ यह एक विशिष्ट व्यक्ति-विषयक टेम्पलेट है, तो जब यह प्रयोग किया जाता है, वह अपने नाम, जो इस मामले में प्रकार bool का एक enum है साथ प्रतीक के साथ प्रतिस्थापित हो जाता है । और booltrue है यदि अभिव्यक्ति का प्रकार गैर- void है। typeof(x) परिणाम void में परिणाम अगर अमान्य है; अन्यथा, यह x अभिव्यक्ति का प्रकार है। और is(y) परिणाम true में y गैर-void है। तो, isInputRangetrue होने पर समाप्त हो जाएगा यदि typeof अभिव्यक्ति संकलन में कोड और false अन्यथा है।

isInputRange में अभिव्यक्ति की पुष्टि करता है कि आप प्रकार R के एक चर घोषणा कर सकते हैं, R एक सदस्य है कि empty जो एक हालत में इस्तेमाल किया जा सकता नामित (यह एक समारोह, चर, या जो कुछ भी हो सकता है), R एक समारोह है कि नाम popFront जो कोई तर्क नहीं लेता है, और R में सदस्य front है जो एक मूल्य देता है। यह एपीआई इनपुट इनपुट की अपेक्षा की जाती है, और typeof के अंदर अभिव्यक्ति संकलित होगी यदि R उस एपीआई का पालन करता है, और इसलिए isInputRange उस प्रकार के लिए true होगा। अन्यथा, यह false होगा।

डी की मानक लाइब्रेरी में ऐसे कुछ नामांकित टेम्पलेट्स (आमतौर पर गुण कहा जाता है) है और इसकी टेम्पलेट बाधाओं में उनका भारी उपयोग होता है। विशेष रूप से std.traits उनमें से कुछ हैं। इसलिए, यदि आप इस तरह के लक्षण कैसे लिखे गए हैं, इसके बारे में अधिक उदाहरण चाहते हैं, तो आप वहां देख सकते हैं (हालांकि उनमें से कुछ काफी जटिल हैं)। इस तरह के लक्षणों के आंतरिक हमेशा विशेष रूप से सुंदर नहीं होते हैं, लेकिन वे बतख टाइपिंग परीक्षणों को अच्छी तरह से encapsulate करते हैं ताकि टेम्पलेट की बाधाएं बहुत साफ और अधिक समझ में आ सकें (यदि वे इस तरह के परीक्षण सीधे डाले गए थे तो वे बहुत अधिक उलझन में होंगे)।

तो, डी में स्थिर बतख टाइपिंग के लिए यह सामान्य दृष्टिकोण है। यह अच्छी तरह से लिखने के तरीके को समझने में थोड़ा सा अभ्यास करता है, लेकिन यह करने का यह मानक तरीका है, और यह काम करता है। ऐसे लोग हैं जिन्होंने आपके Implements!(S, Interface) सुझाव के समान कुछ करने की कोशिश करने का सुझाव दिया है, लेकिन वास्तव में अभी तक कुछ भी नहीं आया है, और ऐसा दृष्टिकोण वास्तव में कम लचीला होगा, जिससे यह कई लक्षणों के लिए उपयुक्त हो सकता है (हालांकि यह निश्चित रूप से बुनियादी लोगों के साथ काम करने के लिए बनाया जा सकता है)। भले ही, मैंने जिस दृष्टिकोण का वर्णन किया है वह वर्तमान में ऐसा करने का मानक तरीका है।

इसके अलावा, यदि आप श्रेणियों के बारे में ज्यादा नहीं जानते हैं, तो मैं this पढ़ने का सुझाव दूंगा।

+0

यह वास्तव में सबसे सरल और डी में मेटा प्रोग्रामिंग के बारे में असुविधाजनक चीजों में से एक है। "कार्यान्वयन" को लागू करने में कोई समस्या नहीं है (मेरा जवाब देखें) लेकिन वास्तव में उपयोगी होने के लिए, इसे मूल वाक्यविन्यास के माध्यम से समर्थित होना चाहिए टेम्पलेट टीएमपीएल (टी: डकटाइप इंटरफेस)। थोड़ा अधिक लचीला है कि isXRange है, लेकिन बहुत अधिक पठनीय और बहुत बेहतर त्रुटि संदेश। ऐसा मत सोचो कि हम जल्द ही ऐसा कुछ उम्मीद कर सकते हैं। –

2

लागू! (एस, इंटरफेस) संभव है लेकिन मानक पुस्तकालय में जाने या बेहतर भाषा समर्थन पाने के लिए पर्याप्त ध्यान नहीं मिला।

http://dpaste.1azy.net/6d8f2dc4

: शायद अगर मैं इसे बतख टाइपिंग के लिए जाने का रास्ता है कह केवल एक ही नहीं होगा, हम इसे :) अवधारणा लागू करने की

सबूत चारों ओर टिंकर करने के लिए एक मौका होगा

import std.traits; 

bool Implements(T, Interface)() 
    if (is(Interface == interface)) 
{ 
    foreach (method; __traits(allMembers, Interface)) 
    { 
     foreach (compareTo; MemberFunctionsTuple!(Interface, method)) 
     { 
      bool found = false; 

      static if (!hasMember!(T, method)) 
      { 
       pragma(msg, T, " has no member ", method); 
       return false; 
      } 
      else 
      {    
       foreach (compareWhat; __traits(getOverloads, T, method)) 
       { 
        if (is(typeof(compareTo) == typeof(compareWhat))) 
        { 
         found = true; 
         break; 
        } 
       } 

       if (!found) 
       { 
        return false; 
       } 
      } 
     } 
    } 
    return true; 
} 

interface Test 
{ 
    bool foo(int, double); 
    void boo(); 
} 

struct Tested 
{ 
    bool foo(int, double); 
// void boo(); 
} 

pragma(msg, Implements!(Tested, Test)()); 

void main() 
{ 
}