Changeset 91
- Timestamp:
- 02/01/07 18:56:35 (5 years ago)
- Files:
-
- trunk/examples/inherit/inherit.d (modified) (6 diffs)
- trunk/examples/inherit/test.py (modified) (3 diffs)
- trunk/html_doc/class_wrapping.html (modified) (1 diff)
- trunk/html_doc/inherit.html (modified) (1 diff)
- trunk/infrastructure/pyd/class_wrap.d (modified) (6 diffs)
- trunk/raw_html/class_wrapping.html (modified) (1 diff)
- trunk/raw_html/inherit.html (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/examples/inherit/inherit.d
r68 r91 5 5 6 6 class Base { 7 this(int i) { writefln("Base.this(): ", i); } 7 8 void foo() { 8 9 writefln("Base.foo"); … … 14 15 15 16 class Derived : Base { 17 this(int i) { super(i); writefln("Derived.this(): ", i); } 16 18 void foo() { 17 19 writefln("Derived.foo"); … … 19 21 } 20 22 21 class WrapDerive : Derived{23 class BaseWrap : Base { 22 24 mixin OverloadShim; 25 this(int i) { super(i); } 26 void foo() { 27 get_overload(&super.foo, "foo"); 28 } 29 void bar() { 30 get_overload(&super.bar, "bar"); 31 } 32 } 33 34 class DeriveWrap : Derived { 35 mixin OverloadShim; 36 this(int i) { super(i); } 23 37 void foo() { 24 38 get_overload(&super.foo, "foo"); … … 34 48 35 49 Base return_poly_base() { 36 if (b1 is null) b1 = new Base ;50 if (b1 is null) b1 = new Base(1); 37 51 return b1; 38 52 } 39 53 40 54 Base return_poly_derived() { 41 if (b2 is null) b2 = new Derived ;55 if (b2 is null) b2 = new Derived(2); 42 56 return b2; 43 57 } 44 58 45 59 Base return_poly_wrap() { 46 if (b3 is null) b3 = new WrapDerive;60 if (b3 is null) b3 = new DeriveWrap(3); 47 61 return b3; 48 62 } … … 57 71 58 72 wrapped_class!(Base) b; 73 b.hide(); 59 74 b.def!(Base.foo); 60 75 b.def!(Base.bar); … … 62 77 63 78 wrapped_class!(Derived) d; 79 d.hide(); 64 80 d.def!(Derived.foo); 65 81 finalize_class(d); 66 82 67 wrapped_class!(WrapDerive) w; 68 w.def!(WrapDerive.foo); 69 finalize_class(w); 83 wrapped_class!(BaseWrap, "Base") bw; 84 bw.init!(void function(int)); 85 bw.def!(BaseWrap.foo); 86 bw.def!(BaseWrap.bar); 87 finalize_class(bw); 88 89 wrapped_class!(DeriveWrap, "Derived") dw; 90 dw.init!(void function(int)); 91 dw.parent!(BaseWrap); 92 dw.def!(DeriveWrap.foo); 93 finalize_class(dw); 70 94 } 95 trunk/examples/inherit/test.py
r68 r91 12 12 import inherit 13 13 14 b = inherit.Base( )15 d = inherit.Derived( )14 b = inherit.Base(1) 15 d = inherit.Derived(2) 16 16 17 17 b.foo() … … 26 26 inherit.call_poly(d) 27 27 28 w = inherit.WrapDerive()29 inherit.call_poly(w)28 #w = inherit.WrapDerive() 29 #inherit.call_poly(w) 30 30 31 class PyClass(inherit. WrapDerive):31 class PyClass(inherit.Derived): 32 32 def foo(self): 33 33 print 'PyClass.foo' 34 34 35 p = PyClass( )35 p = PyClass(3) 36 36 #print "The basic inheritance support breaks down here:" 37 37 inherit.call_poly(p) … … 41 41 b1 = inherit.return_poly_base() 42 42 print "inherit.return_poly_base returned instance of Base" 43 assert type(b1) == inherit.Base 43 b1.foo() 44 b1.bar() 45 #assert type(b1) == inherit.Base 44 46 b2 = inherit.return_poly_derived() 45 47 b2a = inherit.return_poly_derived() 46 48 print "inherit.return_poly_derived returned instance of Derived" 47 assert type(b2) == inherit.Derived49 #assert type(b2) == inherit.Derived 48 50 print "inherit.return_poly_derived returned the same object twice" 49 51 assert b2 is b2a 50 52 b3 = inherit.return_poly_wrap() 51 print "inherit.return_poly_wrap returned instance of WrapDerive"52 assert type(b3) == inherit. WrapDerive53 print "inherit.return_poly_wrap returned instance of DeriveWrap" 54 assert type(b3) == inherit.Derived 53 55 54 56 print trunk/html_doc/class_wrapping.html
r86 r91 58 58 <dt><code>static void init(<span class="t_arg">C</span> ...) ();</code></dt> 59 59 <dd>This allows you to expose the class's constructors to Python. If the class provides a zero-argument constructor, there is no need to specify it; it is always available. Each element of <span class="t_arg">C</span> should be a function type. Each function type should correspond to a constructor. (That is, the arguments to the function should be the same as arguments to the class constructor. The return type is ignored.) There is an additional limitation at this time: No two constructors may have the same number of arguments. Pyd will always attempt to call the first constructor with the right number of arguments. If you wish to support a constructor with default arguments, you must specify each possible constructor call as a different template argument to this function. The examples show a few uses of the <code>init</code> function.</dd> 60 61 <dt><code>static void parent(<span class="t_arg">Parent</span>) ();</code></dt> 62 <dd>This allows the user to manually specify a class as this class's parent. This is intended for a very specific purpose (related to how Pyd handles <a href="inherit.html">inheritance</a>), and should not be used heedlessly. If a class's parent was previously wrapped, then Pyd will detect this and set up a parent-child relationship automatically, in which case it is not neccessary to specify this.</dd> 63 64 <dt><code>static void hide();</code></dt> 65 <dd>Causes this class to be wrapped, but not actually directly exposed to Python. This can be useful if you want to return instances of a class without allowing Python code to instantiate them. This is mainly used when handling <a href="inherit.html">inheritance</a>.</dd> 60 66 61 67 <dt><code>static void iter(<span class="t_arg">iter_t</span>) ();</code></dt> trunk/html_doc/inherit.html
r86 r91 122 122 PyClass.foo</pre> 123 123 124 <p>However, BaseWrap has no particular relationship to Derived. You may remember that Derived overloads <tt>bar</tt> but not <tt>foo</tt>. When we wrapped Derived in <tt>PydMain</tt>, we specified the <tt>foo</tt> overload but not the <tt>bar</tt> overload. Because Derived's parent class is no longer wrapped, Pyd no longer has any way to know about the <tt>bar</tt> method of the Derived class.</tt></p> 125 126 <p>The solution is to explicitly tell Pyd that Derived's parent is BaseWrap. Furthermore, it is probably best to go the extra mile, by wrapping an <tt>OverloadShim</tt> subclass of Derived (call it DerivedWrap), and telling Pyd that BaseWrap is <em>its</em> parent. Additionally, the original <tt>Base</tt> and <tt>Derived</tt> classes should still be wrapped, in the event that functions return instances of them to Python, but should not actually be exposed to Python. The complete solution ends up looking like this:</p> 127 128 <pre class="code"><span class="keyword">import</span> pyd.pyd; 129 <span class="keyword">import</span> std.stdio; 130 131 <span class="keyword">class</span> Base { 132 <span class="keyword">void</span> foo() { writefln(<span class="string">"Base.foo"</span>); } 133 <span class="keyword">void</span> bar() { writefln(<span class="string">"Base.bar"</span>); } 134 } 135 136 <span class="keyword">class</span> Derived : Base { 137 <span class="keyword">void</span> foo() { writefln(<span class="string">"Derived.foo"</span>); } 138 } 139 140 <span class="keyword">class</span> BaseWrap : Base { 141 <span class="keyword">mixin</span> OverloadShim; 142 <span class="keyword">void</span> foo() { 143 get_overload(&<span class="keyword">super</span>.foo, <span class="string">"foo"</span>); 144 } 145 <span class="keyword">void</span> bar() { 146 get_overload(&<span class="keyword">super</span>.bar, <span class="string">"bar"</span>); 147 } 148 } 149 150 <span class="keyword">class</span> DerivedWrap : Derived { 151 <span class="keyword">mixin</span> OverloadShim; 152 <span class="keyword">void</span> foo() { 153 get_overload(&<span class="keyword">super</span>.foo, <span class="string">"foo"</span>); 154 } 155 } 156 157 <span class="keyword">extern</span> (C) <span class="keyword">void</span> PydMain() { 158 module_init(); 159 160 wrapped_class!(Base) b; 161 w.hide(); 162 w.def!(Base.foo); 163 w.def!(Base.bar); 164 finalize_class(w); 165 166 wrapped_class!(Derived) d; 167 d.hide(); 168 d.def!(Derived.foo); 169 finalize_class(d); 170 171 wrapped_class!(BaseWrap, <span class="string">"Base"</span>) bw; 172 bw.def!(BaseWrap.foo); 173 bw.def!(BaseWrap.bar); 174 finalize_class(bw); 175 176 wrapped_class!(DerivedWrap, <span class="string">"Derived"</span>) dw; 177 dw.parent!(BaseWrap); 178 dw.def!(DerivedWrap.foo); 179 finalize_class(dw); 180 }</pre> 181 182 <p><i>(I recognize that this is astoundingly ugly. However, it is the best solution I can come up with without resorting to code generation.)</i></p> 183 184 <p>The <a href="http://dsource.org/projects/pyd/browser/trunk/examples/inherit/inherit.d"><tt>inherit</tt> example</a> in the Pyd distribution provides a more complete version of this example, including how wrapper code should handle constructors.</p> 185 186 <p><i>(TODO: Add support for interfaces and abstract classes.)</i></p> 187 124 188 </div> 125 189 trunk/infrastructure/pyd/class_wrap.d
r69 r91 86 86 null, /*tp_setattro*/ 87 87 null, /*tp_as_buffer*/ 88 0, /*tp_flags*/88 0, /*tp_flags*/ 89 89 null, /*tp_doc*/ 90 90 null, /*tp_traverse*/ … … 250 250 static if (is(T == class)) pragma(msg, "wrapped_class: " ~ classname); 251 251 static const char[] _name = classname; 252 static bool _private = false; 252 253 alias T wrapped_type; 253 254 /** … … 333 334 } 334 335 336 static void parent(Parent) () { 337 wrapped_class_type!(T).tp_base = &wrapped_class_type!(Parent); 338 } 339 340 static void hide() { 341 _private = true; 342 } 343 335 344 // Iteration wrapping support requires StackThreads 336 345 version(Pyd_with_StackThreads) { … … 394 403 type.tp_name = (module_name ~ "." ~ name ~ \0).ptr; 395 404 396 // Check for wrapped parent classes 397 static if (is(T B == super)) { 398 foreach (C; B) { 399 static if (is(C == class) && !is(C == Object)) { 400 if (is_wrapped!(C)) { 401 type.tp_base = &wrapped_class_type!(C); 405 // Check for wrapped parent classes, if one was not explicitly supplied. 406 if (type.tp_base is null) { 407 static if (is(T B == super)) { 408 foreach (C; B) { 409 static if (is(C == class) && !is(C == Object)) { 410 if (is_wrapped!(C)) { 411 type.tp_base = &wrapped_class_type!(C); 412 } 402 413 } 403 414 } … … 437 448 } 438 449 439 // If a ctor wasn't supplied, try the default. 440 if (type.tp_init is null) { 441 static if (is(T == class)) { 442 type.tp_init = &wrapped_init!(T).init; 443 } else { 444 type.tp_init = &wrapped_struct_init!(T).init; 450 if (CLS._private) { 451 type.tp_init = null; 452 } else { 453 // If a ctor wasn't supplied, try the default. 454 static if (is(typeof(new T))) { 455 if (type.tp_init is null) { 456 static if (is(T == class)) { 457 type.tp_init = &wrapped_init!(T).init; 458 } else { 459 type.tp_init = &wrapped_struct_init!(T).init; 460 } 461 } 445 462 } 446 463 } 447 464 if (PyType_Ready(&type) < 0) { 448 // XXX: This will probably crash the interpreter, as it isn't normally449 // caught and translated.450 465 throw new Exception("Couldn't ready wrapped type!"); 451 466 } 452 467 Py_INCREF(cast(PyObject*)&type); 453 PyModule_AddObject(Pyd_Module_p(modulename), name.ptr, cast(PyObject*)&type); 468 if (!CLS._private) { 469 PyModule_AddObject(Pyd_Module_p(modulename), name.ptr, cast(PyObject*)&type); 470 } 454 471 is_wrapped!(T) = true; 455 472 static if (is(T == class)) { … … 460 477 template OverloadShim() { 461 478 std.traits.ReturnType!(dg_t) get_overload(dg_t, T ...) (dg_t dg, char[] name, T t) { 462 python.PyObject* _pyobj = wrapped_gc_objects[cast(void*)this]; 463 if (_pyobj.ob_type != &wrapped_class_type!(typeof(this))) { 479 python.PyObject** _pyobj = cast(void*)this in wrapped_gc_objects; 480 python.PyTypeObject** _pytype = this.classinfo in wrapped_classes; 481 if (_pyobj is null || _pytype is null || (*_pyobj).ob_type != *_pytype) { 464 482 // If this object's type is not the wrapped class's type (that is, 465 483 // if this object is actually a Python subclass of the wrapped 466 484 // class), then call the Python object. 467 python.PyObject* method = python.PyObject_GetAttrString( _pyobj, (name ~ \0).ptr);485 python.PyObject* method = python.PyObject_GetAttrString(*_pyobj, (name ~ \0).ptr); 468 486 if (method is null) handle_exception(); 469 487 dg_t pydg = PydCallable_AsDelegate!(dg_t)(method); trunk/raw_html/class_wrapping.html
r86 r91 42 42 <dt><code>static void init(<span class="t_arg">C</span> ...) ();</code></dt> 43 43 <dd>This allows you to expose the class's constructors to Python. If the class provides a zero-argument constructor, there is no need to specify it; it is always available. Each element of <span class="t_arg">C</span> should be a function type. Each function type should correspond to a constructor. (That is, the arguments to the function should be the same as arguments to the class constructor. The return type is ignored.) There is an additional limitation at this time: No two constructors may have the same number of arguments. Pyd will always attempt to call the first constructor with the right number of arguments. If you wish to support a constructor with default arguments, you must specify each possible constructor call as a different template argument to this function. The examples show a few uses of the <code>init</code> function.</dd> 44 45 <dt><code>static void parent(<span class="t_arg">Parent</span>) ();</code></dt> 46 <dd>This allows the user to manually specify a class as this class's parent. This is intended for a very specific purpose (related to how Pyd handles <a href="inherit.html">inheritance</a>), and should not be used heedlessly. If a class's parent was previously wrapped, then Pyd will detect this and set up a parent-child relationship automatically, in which case it is not neccessary to specify this.</dd> 47 48 <dt><code>static void hide();</code></dt> 49 <dd>Causes this class to be wrapped, but not actually directly exposed to Python. This can be useful if you want to return instances of a class without allowing Python code to instantiate them. This is mainly used when handling <a href="inherit.html">inheritance</a>.</dd> 44 50 45 51 <dt><code>static void iter(<span class="t_arg">iter_t</span>) ();</code></dt> trunk/raw_html/inherit.html
r86 r91 106 106 PyClass.foo</pre> 107 107 108 <p>However, BaseWrap has no particular relationship to Derived. You may remember that Derived overloads <tt>bar</tt> but not <tt>foo</tt>. When we wrapped Derived in <tt>PydMain</tt>, we specified the <tt>foo</tt> overload but not the <tt>bar</tt> overload. Because Derived's parent class is no longer wrapped, Pyd no longer has any way to know about the <tt>bar</tt> method of the Derived class.</tt></p> 109 110 <p>The solution is to explicitly tell Pyd that Derived's parent is BaseWrap. Furthermore, it is probably best to go the extra mile, by wrapping an <tt>OverloadShim</tt> subclass of Derived (call it DerivedWrap), and telling Pyd that BaseWrap is <em>its</em> parent. Additionally, the original <tt>Base</tt> and <tt>Derived</tt> classes should still be wrapped, in the event that functions return instances of them to Python, but should not actually be exposed to Python. The complete solution ends up looking like this:</p> 111 112 <pre class="code"><span class="keyword">import</span> pyd.pyd; 113 <span class="keyword">import</span> std.stdio; 114 115 <span class="keyword">class</span> Base { 116 <span class="keyword">void</span> foo() { writefln(<span class="string">"Base.foo"</span>); } 117 <span class="keyword">void</span> bar() { writefln(<span class="string">"Base.bar"</span>); } 118 } 119 120 <span class="keyword">class</span> Derived : Base { 121 <span class="keyword">void</span> foo() { writefln(<span class="string">"Derived.foo"</span>); } 122 } 123 124 <span class="keyword">class</span> BaseWrap : Base { 125 <span class="keyword">mixin</span> OverloadShim; 126 <span class="keyword">void</span> foo() { 127 get_overload(&<span class="keyword">super</span>.foo, <span class="string">"foo"</span>); 128 } 129 <span class="keyword">void</span> bar() { 130 get_overload(&<span class="keyword">super</span>.bar, <span class="string">"bar"</span>); 131 } 132 } 133 134 <span class="keyword">class</span> DerivedWrap : Derived { 135 <span class="keyword">mixin</span> OverloadShim; 136 <span class="keyword">void</span> foo() { 137 get_overload(&<span class="keyword">super</span>.foo, <span class="string">"foo"</span>); 138 } 139 } 140 141 <span class="keyword">extern</span> (C) <span class="keyword">void</span> PydMain() { 142 module_init(); 143 144 wrapped_class!(Base) b; 145 w.hide(); 146 w.def!(Base.foo); 147 w.def!(Base.bar); 148 finalize_class(w); 149 150 wrapped_class!(Derived) d; 151 d.hide(); 152 d.def!(Derived.foo); 153 finalize_class(d); 154 155 wrapped_class!(BaseWrap, <span class="string">"Base"</span>) bw; 156 bw.def!(BaseWrap.foo); 157 bw.def!(BaseWrap.bar); 158 finalize_class(bw); 159 160 wrapped_class!(DerivedWrap, <span class="string">"Derived"</span>) dw; 161 dw.parent!(BaseWrap); 162 dw.def!(DerivedWrap.foo); 163 finalize_class(dw); 164 }</pre> 165 166 <p><i>(I recognize that this is astoundingly ugly. However, it is the best solution I can come up with without resorting to code generation.)</i></p> 167 168 <p>The <a href="http://dsource.org/projects/pyd/browser/trunk/examples/inherit/inherit.d"><tt>inherit</tt> example</a> in the Pyd distribution provides a more complete version of this example, including how wrapper code should handle constructors.</p> 169 170 <p><i>(TODO: Add support for interfaces and abstract classes.)</i></p> 171 108 172 </div> 109 173
