Changeset 57

Show
Ignore:
Timestamp:
12/12/06 23:49:57 (5 years ago)
Author:
KirkMcDonald
Message:

Inheritance improvements; bugfixes

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/examples/inherit/inherit.d

    r56 r57  
    1919} 
    2020 
     21class WrapDerive : Derived { 
     22    mixin OverloadShim; 
     23    void foo() { 
     24        get_overload(&super.foo, "foo"); 
     25    } 
     26} 
     27 
    2128void call_poly(Base b) { 
    22     writef("call_poly: "); 
     29    writefln("call_poly:"); 
    2330    b.foo(); 
    2431} 
     
    3845    d.def!(Derived.foo); 
    3946    finalize_class(d); 
     47 
     48    wrapped_class!(WrapDerive) w; 
     49    w.def!(WrapDerive.foo); 
     50    finalize_class(w); 
    4051} 
  • trunk/examples/inherit/test.py

    r56 r57  
    2626inherit.call_poly(d) 
    2727 
    28 class PyClass(inherit.Derived): 
     28w = inherit.WrapDerive() 
     29inherit.call_poly(w) 
     30 
     31class PyClass(inherit.WrapDerive): 
    2932    def foo(self): 
    3033        print 'PyClass.foo' 
    3134 
    3235p = PyClass() 
    33 print "The basic inheritance support breaks down here:" 
     36#print "The basic inheritance support breaks down here:" 
    3437inherit.call_poly(p) 
  • trunk/examples/testdll/testdll.d

    r52 r57  
    124124} 
    125125 
     126void throws() { 
     127    throw new Exception("Yay! An exception!"); 
     128} 
     129 
    126130extern (C) 
    127131export void inittestdll() { 
     
    139143    def!(func_test); 
    140144    def!(dg_test); 
     145    def!(throws); 
    141146 
    142147    module_init("testdll"); 
  • trunk/html_doc/basics.html

    r52 r57  
    2020<a class="nav" href="except_wrapping.html">Exception wrapping</a><br /> 
    2121<a class="nav" href="pydobject.html">PydObject</a><br /> 
     22<a class="nav" href="vsboost.html">vs. Boost.Python</a><br /> 
    2223<a class="nav" href="credits.html">Credits</a> 
    2324</div> 
  • trunk/html_doc/celerid.html

    r52 r57  
    2020<a class="nav" href="except_wrapping.html">Exception wrapping</a><br /> 
    2121<a class="nav" href="pydobject.html">PydObject</a><br /> 
     22<a class="nav" href="vsboost.html">vs. Boost.Python</a><br /> 
    2223<a class="nav" href="credits.html">Credits</a> 
    2324</div> 
  • trunk/html_doc/class_wrapping.html

    r52 r57  
    2020<a class="nav" href="except_wrapping.html">Exception wrapping</a><br /> 
    2121<a class="nav" href="pydobject.html">PydObject</a><br /> 
     22<a class="nav" href="vsboost.html">vs. Boost.Python</a><br /> 
    2223<a class="nav" href="credits.html">Credits</a> 
    2324</div> 
     
    103104<dt><code>opIn_r</code></dt> <dd>Python expects the <code>in</code> operator to return a boolean value (it is a containment test). D convention is for <code>in</code> to search for the value in the container, and to return a pointer to the found item, or <code>null</code> if the item is not found. That said, D does not enforce any particular signature on the <code>in</code> overload, while the Python/C API does. Pyd will check the boolean result of a call to <code>opIn_r</code>, and return that value to Python.</dd> 
    104105</dl> 
     106 
     107<h3><a class="anchor" name="inheritance">Inheritance</a></h3> 
     108 
     109<p>If you wrap both a class and a child of that class, Pyd is smart enough to make the resulting Python classes have a parent-child relationship. Any methods of the parent class will automatically be available to the child class. If the child class overloads any of those methods, it is important that the user wrap them in the module's init function. For example:</p> 
     110 
     111<pre class="code"><span class="keyword">import</span> std.stdio; 
     112 
     113<span class="keyword">class</span> Base { 
     114    <span class="keyword">void</span> foo() { writefln(<span class="string">"Base.foo"</span>); } 
     115    <span class="keyword">void</span> bar() { writefln(<span class="string">"Base.bar"</span>); } 
     116} 
     117 
     118<span class="keyword">class</span> Derived : Base { 
     119    <span class="keyword">void</span> foo() { writefln(<span class="string">"Derived.foo"</span>); } 
     120}</pre> 
     121 
     122<p>These would be exposed to Python by putting this code in out init function after the call to <code>module_init</code>:</p> 
     123 
     124<pre class="code">wrapped_class!(Base) b; 
     125b.def!(Base.foo); 
     126b.def!(Base.bar); 
     127finalize_class(b); 
     128 
     129wrapped_class!(Derived) d; 
     130d.def!(Derived.foo); 
     131finalize_class(d);</pre> 
     132 
     133<p>When used in Python, we get the expected behavior:</p> 
     134 
     135<pre class="code">&gt;&gt;&gt; issubclass(Derived, Base) 
     136True 
     137&gt;&gt;&gt; b = Base() 
     138&gt;&gt;&gt; d = Derived() 
     139&gt;&gt;&gt; b.foo() 
     140Base.foo 
     141&gt;&gt;&gt; b.bar() 
     142Base.bar 
     143&gt;&gt;&gt; d.foo() 
     144Derived.foo 
     145&gt;&gt;&gt; d.bar() 
     146Base.bar</pre> 
     147 
     148<p>There is one weakness in the default behavior. Take a function like the following:</p> 
     149 
     150<pre class="code"><span class="keyword">void</span> polymorphic_call(Base b) { 
     151    b.foo(); 
     152}</pre> 
     153 
     154<p>And in Python:</p> 
     155 
     156<pre class="code"><span class="keyword">class</span> PyClass(Base): 
     157    <span class="keyword">def</span> foo(self): 
     158        <span class="keyword">print</span> <span class="string">"PyClass.foo"</span> 
     159 
     160&gt;&gt;&gt; p = PyClass() 
     161&gt;&gt;&gt; polymorphic_call(p) 
     162Base.foo</pre> 
     163 
     164<p>Optimally, we would want <code>polymorphic_call</code> to call PyClass.foo. This requires some additional work on the D side of things. To get this behavior, then rather than expose Base directly, we must expose a wrapper class:</p> 
     165 
     166<pre class="code"><span class="keyword">class</span> BaseWrap : Base { 
     167    <span class="keyword">mixin</span> OverloadShim; 
     168    <span class="keyword">void</span> foo() { 
     169        get_overload(&amp;<span class="keyword">super</span>.foo, <span class="string">"foo"</span>); 
     170    } 
     171    <span class="keyword">void</span> bar() { 
     172        get_overload(&amp;<span class="keyword">super</span>.bar, <span class="string">"bar"</span>); 
     173    } 
     174}</pre> 
     175 
     176<p>Now, we must replace the old wrapping of Base with this:</p> 
     177 
     178<pre class="code">wrapped_class!(BaseWrap, <span class="string">"Base"</span>) w; 
     179w.def!(BaseWrap.foo); 
     180w.def!(BaseWrap.bar); 
     181finalize_class(w);</pre> 
     182 
     183<p>Now our subclass will perform just like we expect:</p> 
     184 
     185<pre class="code">&gt;&gt;&gt; p = PyClass() 
     186&gt;&gt;&gt; polymorphic_call(p) 
     187PyClass.foo</pre> 
    105188 
    106189<h3><a class="anchor" name="examples">Examples</a></h3> 
  • trunk/html_doc/conversion.html

    r52 r57  
    2020<a class="nav" href="except_wrapping.html">Exception wrapping</a><br /> 
    2121<a class="nav" href="pydobject.html">PydObject</a><br /> 
     22<a class="nav" href="vsboost.html">vs. Boost.Python</a><br /> 
    2223<a class="nav" href="credits.html">Credits</a> 
    2324</div> 
  • trunk/html_doc/credits.html

    r52 r57  
    2020<a class="nav" href="except_wrapping.html">Exception wrapping</a><br /> 
    2121<a class="nav" href="pydobject.html">PydObject</a><br /> 
     22<a class="nav" href="vsboost.html">vs. Boost.Python</a><br /> 
    2223<a class="navcur" href="credits.html">Credits</a> 
    2324</div> 
  • trunk/html_doc/except_wrapping.html

    r52 r57  
    2020<a class="navcur" href="except_wrapping.html">Exception wrapping</a><br /> 
    2121<a class="nav" href="pydobject.html">PydObject</a><br /> 
     22<a class="nav" href="vsboost.html">vs. Boost.Python</a><br /> 
    2223<a class="nav" href="credits.html">Credits</a> 
    2324</div> 
  • trunk/html_doc/func_wrapping.html

    r52 r57  
    2020<a class="nav" href="except_wrapping.html">Exception wrapping</a><br /> 
    2121<a class="nav" href="pydobject.html">PydObject</a><br /> 
     22<a class="nav" href="vsboost.html">vs. Boost.Python</a><br /> 
    2223<a class="nav" href="credits.html">Credits</a> 
    2324</div> 
  • trunk/html_doc/index.html

    r52 r57  
    2020<a class="nav" href="except_wrapping.html">Exception wrapping</a><br /> 
    2121<a class="nav" href="pydobject.html">PydObject</a><br /> 
     22<a class="nav" href="vsboost.html">vs. Boost.Python</a><br /> 
    2223<a class="nav" href="credits.html">Credits</a> 
    2324</div> 
  • trunk/html_doc/install.html

    r52 r57  
    2020<a class="nav" href="except_wrapping.html">Exception wrapping</a><br /> 
    2121<a class="nav" href="pydobject.html">PydObject</a><br /> 
     22<a class="nav" href="vsboost.html">vs. Boost.Python</a><br /> 
    2223<a class="nav" href="credits.html">Credits</a> 
    2324</div> 
  • trunk/html_doc/pydobject.html

    r52 r57  
    2020<a class="nav" href="except_wrapping.html">Exception wrapping</a><br /> 
    2121<a class="navcur" href="pydobject.html">PydObject</a><br /> 
     22<a class="nav" href="vsboost.html">vs. Boost.Python</a><br /> 
    2223<a class="nav" href="credits.html">Credits</a> 
    2324</div> 
  • trunk/html_doc/struct_wrapping.html

    r52 r57  
    2020<a class="nav" href="except_wrapping.html">Exception wrapping</a><br /> 
    2121<a class="nav" href="pydobject.html">PydObject</a><br /> 
     22<a class="nav" href="vsboost.html">vs. Boost.Python</a><br /> 
    2223<a class="nav" href="credits.html">Credits</a> 
    2324</div> 
  • trunk/infrastructure/pyd/class_wrap.d

    r56 r57  
    447447} 
    448448 
     449import std.stdio; 
     450 
     451template OverloadShim() { 
     452    std.traits.ReturnType!(dg_t) get_overload(dg_t, T ...) (dg_t dg, char[] name, T t) { 
     453        python.PyObject* _pyobj = wrapped_gc_objects[cast(void*)this]; 
     454        if (_pyobj.ob_type != &wrapped_class_type!(typeof(this))) { 
     455            //writefln("Wrapper class, calling wrapped PyObject"); 
     456            // If this object's type is not the wrapped class's type (that is, 
     457            // if this object is actually a Python subclass of the wrapped 
     458            // class), then call the Python object. 
     459            python.PyObject* method = python.PyObject_GetAttrString(_pyobj, (name ~ \0).ptr); 
     460            if (method is null) handle_exception(); 
     461            dg_t pydg = PydCallable_AsDelegate!(dg_t)(method); 
     462            python.Py_DECREF(method); 
     463            return pydg(t); 
     464        } else { 
     465            //writefln("Wrapper class, calling original delegate"); 
     466            return dg(t); 
     467        } 
     468    } 
     469} 
     470 
    449471/////////////////////// 
    450472// PYD API FUNCTIONS // 
  • trunk/infrastructure/pyd/exception.d

    r55 r57  
    2525private import meta.Nameof; 
    2626private import std.string; 
     27import std.stdio; 
    2728 
    2829/** 
     
    106107 
    107108    ~this() { 
    108         Py_DECREF(m_type); 
    109         Py_DECREF(m_value); 
    110         Py_DECREF(m_trace); 
     109        if (m_type) Py_DECREF(m_type); 
     110        if (m_value) Py_DECREF(m_value); 
     111        if (m_trace) Py_DECREF(m_trace); 
    111112    } 
    112113 
    113114    PyObject* type() { 
    114         Py_INCREF(m_type); 
     115        if (m_type) Py_INCREF(m_type); 
    115116        return m_type; 
    116117    } 
    117118    PyObject* value() { 
    118         Py_INCREF(m_value); 
     119        if (m_value) Py_INCREF(m_value); 
    119120        return m_value; 
    120121    } 
    121122    PyObject* traceback() { 
    122         Py_INCREF(m_trace); 
     123        if (m_trace) Py_INCREF(m_trace); 
    123124        return m_trace; 
    124125    } 
  • trunk/infrastructure/pyd/func_wrap.d

    r54 r57  
    8888} 
    8989 
     90import std.stdio; 
     91 
    9092// Calls callable alias fn with PyTuple args. 
    9193ReturnType!(fn_t) applyPyTupleToAlias(alias fn, fn_t, uint MIN_ARGS) (PyObject* args) { 
     
    99101        argCount = PyObject_Length(args); 
    100102    } 
     103    //writefln("argCount: %s; MIN_ARGS: %s; MAX_ARGS: %s", argCount, MIN_ARGS, MAX_ARGS); 
    101104 
    102105    // Sanity check! 
     
    196199        fn_t fn = (cast(wrapped_class_object!(fn_t)*)self).d_obj; 
    197200 
    198         return exception_catcher(
     201        return exception_catcher(delegate PyObject*()
    199202            return pyApplyToDelegate(fn, args); 
    200203        });