2015-02-20 4 views
26

इस कोड को देखते हुए:जड़ समर्थन विशेषता ऑब्जेक्ट अपस्टिंग क्यों नहीं करता है?

trait Base { 
    fn a(&self); 
    fn b(&self); 
    fn c(&self); 
    fn d(&self); 
} 

trait Derived : Base { 
    fn e(&self); 
    fn f(&self); 
    fn g(&self); 
} 

struct S; 

impl Derived for S { 
    fn e(&self) {} 
    fn f(&self) {} 
    fn g(&self) {} 
} 

impl Base for S { 
    fn a(&self) {} 
    fn b(&self) {} 
    fn c(&self) {} 
    fn d(&self) {} 
} 

दुर्भाग्य से, मैं &Base करने के लिए &Derived डाली नहीं कर सकता। मैं सोच रहा था कि ऐसा क्यों था, क्योंकि Derived vtable को Base विधियों को एक तरफ या किसी अन्य तरीके से संदर्भित करना है।

खैर, LLVM आईआर निरीक्षण से पता चलता है निम्नलिखित:

@vtable4 = internal unnamed_addr constant { 
    void (i8*)*, 
    i64, 
    i64, 
    void (%struct.S*)*, 
    void (%struct.S*)*, 
    void (%struct.S*)*, 
    void (%struct.S*)* 
} { 
    void (i8*)* @_ZN2i813glue_drop.98717h857b3af62872ffacE, 
    i64 0, 
    i64 1, 
    void (%struct.S*)* @_ZN6S.Base1a20h57ba36716de00921jbaE, 
    void (%struct.S*)* @_ZN6S.Base1b20h3d50ba92e362d050pbaE, 
    void (%struct.S*)* @_ZN6S.Base1c20h794e6e72e0a45cc2vbaE, 
    void (%struct.S*)* @_ZN6S.Base1d20hda31e564669a8cdaBbaE 
} 

@vtable26 = internal unnamed_addr constant { 
    void (i8*)*, 
    i64, 
    i64, 
    void (%struct.S*)*, 
    void (%struct.S*)*, 
    void (%struct.S*)*, 
    void (%struct.S*)*, 
    void (%struct.S*)*, 
    void (%struct.S*)*, 
    void (%struct.S*)* 
} { 
    void (i8*)* @_ZN2i813glue_drop.98717h857b3af62872ffacE, 
    i64 0, 
    i64 1, 
    void (%struct.S*)* @_ZN9S.Derived1e20h9992ddd0854253d1WaaE, 
    void (%struct.S*)* @_ZN9S.Derived1f20h849d0c78b0615f092aaE, 
    void (%struct.S*)* @_ZN9S.Derived1g20hae95d0f1a38ed23b8aaE, 
    void (%struct.S*)* @_ZN6S.Base1a20h57ba36716de00921jbaE, 
    void (%struct.S*)* @_ZN6S.Base1b20h3d50ba92e362d050pbaE, 
    void (%struct.S*)* @_ZN6S.Base1c20h794e6e72e0a45cc2vbaE, 
    void (%struct.S*)* @_ZN6S.Base1d20hda31e564669a8cdaBbaE 
} 

सभी जंग vtables पहले खेतों में नाशक, आकार और संरेखण के लिए सूचक होते हैं, और जब supertrait तरीकों को संदर्भित subtrait vtables उन्हें नकल नहीं है, न ही सुपरर्ट्रेट vtables के अप्रत्यक्ष संदर्भ का उपयोग करें। वे सिर्फ विधि पॉइंटर्स verbatim की प्रतियां हैं और कुछ भी नहीं।

है कि डिजाइन को देखते हुए यह समझने के लिए क्यों यह काम नहीं करता आसान है। रनटाइम में एक नया vtable निर्माण करने की आवश्यकता होगी, जो संभवतः ढेर पर रहेंगे, और यह वास्तव में एक सुरुचिपूर्ण (या इष्टतम) समाधान नहीं है।

वहाँ कुछ समाधान जाहिर है, इंटरफ़ेस करने के लिए स्पष्ट Upcast विधियां जोड़ने की तरह हैं, लेकिन यह ठीक से काम करने के लिए काफी बॉयलरप्लेट (या मैक्रो उन्माद) का एक सा की आवश्यकता है।

अब, सवाल यह है कि - क्यों यह किसी तरह कि विशेषता वस्तु upcasting सक्षम होगा में लागू नहीं किया गया? जैसे, subtrait के vtable में सुपरर्ट्रेट के vtable में एक पॉइंटर जोड़ना। अभी के लिए, जंग का गतिशील प्रेषण LSP को संतुष्ट नहीं करता है, जो वस्तु-उन्मुख डिजाइन के लिए एक बहुत ही बुनियादी सिद्धांत है।

बेशक आप स्थिर प्रेषण का उपयोग कर सकते हैं, जो वास्तव में जंग में उपयोग करने के लिए बहुत ही सुरुचिपूर्ण है, लेकिन यह आसानी से कोड ब्लोट की ओर जाता है जो कभी-कभी कम्प्यूटेशनल प्रदर्शन की तुलना में अधिक महत्वपूर्ण होता है - जैसे एम्बेडेड सिस्टम पर, और जंग डेवलपर्स ऐसे समर्थन का दावा करने का दावा करते हैं भाषा के मामलों का प्रयोग करें। इसके अलावा, कई मामलों में आप सफलतापूर्वक ऐसे मॉडल का उपयोग कर सकते हैं जो शुद्ध ओओ नहीं है, जिसे जंग के कार्यात्मक डिजाइन द्वारा प्रोत्साहित किया जाता है। फिर भी, जंग कई उपयोगी ओओ पैटर्न का समर्थन करता है ... तो एलएसपी क्यों नहीं?

किसी को भी इस तरह के डिजाइन के पीछे तर्क यह पता है?

+9

एक साइड नोट के रूप में: जंग वस्तु-उन्मुख भाषा नहीं है। लक्षण इंटरफेस नहीं हैं, वे हास्केल से टाइप क्लास की तरह हैं। जंग में उप-प्रकार भी नहीं होता है, इसलिए एलएसपी इसके लिए कुछ हद तक अक्षम नहीं है क्योंकि इसकी परिभाषा उप-संबंध संबंध से जुड़ी हुई है। –

+5

फिर भी, जैसा कि मैंने कहा था, जंग कई ओओ-स्टाइल एब्स्ट्रैक्शन का समर्थन करता है, और गुणों को विरासत में रखने की अनुमति है, जो कि एक प्रकार के पदानुक्रम के समान कुछ बनाते हैं। मेरे लिए, लक्षण वस्तुओं के लिए एलएसपी का समर्थन करना स्वाभाविक प्रतीत होता है, भले ही ओओ भाषा का मुख्य प्रतिमान न हो। – kFYatek

+0

कृपया उपयोगी उत्तरों को उतारने और एक उत्तर को स्वीकार करने के लिए सुनिश्चित करें यदि यह आपकी समस्या का समाधान करता है! यदि कोई जवाब स्वीकार्य नहीं है, तो टिप्पणियों को छोड़कर विचार करें कि समस्या को अलग करने के लिए अपने प्रश्न को क्यों संपादित करें या संपादित करें। – Shepmaster

उत्तर

15

मैं जब मैं जंग के साथ शुरू किया एक ही दीवार में भाग गया। अब, जब मैं लक्षणों के बारे में सोचता हूं, तो कक्षाओं के बारे में सोचने की तुलना में मेरे पास एक अलग छवि है।

trait X : Y {} का मतलब है जब आप struct S के लिए विशेषता X लागू आप भी जरूरत S के लिए विशेषता Y लागू करने के लिए।

बेशक इसका मतलब है कि &X जानता है कि यह &Y भी है, और इसलिए उपयुक्त कार्य प्रदान करता है। यदि आपको पॉइंटर्स को Y के पहले vtable पर ट्रैवर्स करने की आवश्यकता होती है तो इसे कुछ रनटाइम-प्रयास (अधिक पॉइंटर ड्रेरेन्शन) की आवश्यकता होगी।

फिर, वर्तमान डिजाइन + अन्य vtables करने के लिए अतिरिक्त संकेत शायद ज्यादा चोट नहीं होता है, और आसान कास्टिंग लागू किया जा करने की अनुमति होगी। तो शायद हमें दोनों की जरूरत है? internal.rust-lang.org

26

पर वास्तव में चर्चा की जा रही है, मुझे लगता है कि मुझे कारण मिला है।मुझे किसी भी विशेषता के लिए अपस्टास्टिंग समर्थन जोड़ने का एक शानदार तरीका मिला है, और इस तरह प्रोग्रामर यह चुनने में सक्षम है कि विशेषता में उस अतिरिक्त vtable प्रविष्टि को जोड़ना है या नहीं, जो कि समान व्यापार-बंद है सी ++ वर्चुअल बनाम गैर वर्चुअल विधियों: लालित्य और मॉडल शुद्धता बनाम प्रदर्शन।

इस प्रकार कोड लागू किया जा सकता है:

trait Base : AsBase { 
    ... 
} 

trait AsBase { 
    fn as_base(&self) -> &Base; 
} 

impl<T: Base> AsBase for T { 
    fn as_base(&self) -> &Base { self } 
} 
पाठ्यक्रम एक का

एक &mut सूचक या एक Box (है कि एक आवश्यकता है कि T एक 'static प्रकार होना चाहिए कहते हैं) कास्टिंग के लिए अतिरिक्त पद्धतियां जोड़ने सकता है, लेकिन यह एक सामान्य विचार है। यह हर व्युत्पन्न प्रकार के लिए बॉयलरप्लेट के बिना हर व्युत्पन्न प्रकार के सुरक्षित और सरल (हालांकि निहित नहीं) की अनुमति देता है।

+0

वाह! और यह अचूक दिखता है। –

+0

दुर्भाग्यवश, इस 'इम्प्ल ट्राइट' दृष्टिकोण का उपयोग क्षेत्र कुछ हद तक संकीर्ण है, यदि एक जटिल विशेषता आर्किटेक्चर का उपयोग किया जाता है। http://play.integer32.com/?gist=bbe93906ddab1beaa34eb33e11eda41a&version=nightly अंतरण कार्यान्वयन को समाप्त करने की संभावना के बिना (यानी 'आईएनएल <टी: AsBranchOne +! AsBranchTwo> ') को' as_ * इंस्टॉल करना आवश्यक है() 'विधियों को रोकने के लिए सीधे घोंसले की विशेषता में विधियों। – snuk182

9

जून 2017 के रूप में, यह "उप ​​विशेषता बलात्कार" (या "सुपर विशेषता बलात्कार") की स्थिति इस प्रकार है:

  • एक स्वीकार किए जाते हैं आरएफसी #0401 बलात्कार के एक भाग के रूप में इस का उल्लेख है। तो यह रूपांतरण पूरी तरह से किया जाना चाहिए।

    coerce_inner (T) = U जहां TU की एक उप-विशेषता है,

  • हालांकि, यह अभी तक लागू नहीं हुआ है। एक संबंधित मुद्दा #18600 है।

एक डुप्लिकेट समस्या #5665 भी है। वहां टिप्पणियां बताती हैं कि इसे लागू करने से क्या रोकें।

  • असल में, समस्या यह है कि सुपर-लक्षणों के लिए vtables कैसे प्राप्त करें। Vtables का वर्तमान लेआउट निम्नानुसार है (x86-64 मामले में):
    +-----+-------------------------------+ 
    | 0- 7|pointer to "drop glue" function| 
    +-----+-------------------------------+ 
    | 8-15|size of the data    | 
    +-----+-------------------------------+ 
    |16-23|alignment of the data   | 
    +-----+-------------------------------+ 
    |24- |methods of Self and supertraits| 
    +-----+-------------------------------+ 
    
    इसमें बाद में एक सुपर-ट्राइट के लिए एक vtable शामिल नहीं है। हमारे पास कम से कम vtables के साथ कुछ tweaks है।
  • बेशक इस समस्या को कम करने के तरीके हैं, लेकिन कई अलग-अलग फायदे/नुकसान के साथ! हीरा विरासत होने पर वीटेबल आकार के लिए एक लाभ होता है। एक और तेजी से माना जाता है।

वहाँ @typelist वे a draft RFC तैयार जो सुव्यवस्थित लग रहा है कहते हैं, लेकिन वे (नवंबर 2016) के बाद गायब हो गया की तरह लग रहे।

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