diff options
Diffstat (limited to 'Doc/Manual')
-rw-r--r-- | Doc/Manual/Perl5.html | 366 |
1 files changed, 366 insertions, 0 deletions
diff --git a/Doc/Manual/Perl5.html b/Doc/Manual/Perl5.html index 49e8965fa..db8c0e602 100644 --- a/Doc/Manual/Perl5.html +++ b/Doc/Manual/Perl5.html @@ -68,6 +68,15 @@ <li><a href="#Perl5_nn46">Modifying the proxy methods</a> </ul> <li><a href="#Perl5_nn47">Adding additional Perl code</a> +<li><a href="#Perl5_directors">Cross language polymorphism</a> +<ul> +<li><a href="#Perl5_nn48">Enabling directors</a> +<li><a href="#Perl5_nn49">Director classes</a> +<li><a href="#Perl5_nn50">Ownership and object destruction</a> +<li><a href="#Perl5_nn51">Exception unrolling</a> +<li><a href="#Perl5_nn52">Overhead and code bloat</a> +<li><a href="#Perl5_nn53">Typemaps</a> +</ul> </ul> </div> <!-- INDEX --> @@ -2993,6 +3002,363 @@ set_transform($im, $a); </pre> </div> +<H2><a name="Perl5_directors"></a>31.11 Cross language polymorphism</H2> + + +<p> +Proxy classes provide a more natural, object-oriented way to access +extension classes. As described above, each proxy instance has an +associated C++ instance, and method calls to the proxy are passed to the +C++ instance transparently via C wrapper functions. +</p> + +<p> +This arrangement is asymmetric in the sense that no corresponding +mechanism exists to pass method calls down the inheritance chain from +C++ to Perl. In particular, if a C++ class has been extended in Perl +(by extending the proxy class), these extensions will not be visible +from C++ code. Virtual method calls from C++ are thus not able access +the lowest implementation in the inheritance chain. +</p> + +<p> +Changes have been made to SWIG to address this problem and +make the relationship between C++ classes and proxy classes more +symmetric. To achieve this goal, new classes called directors are +introduced at the bottom of the C++ inheritance chain. The job of the +directors is to route method calls correctly, either to C++ +implementations higher in the inheritance chain or to Perl +implementations lower in the inheritance chain. The upshot is that C++ +classes can be extended in Perl and from C++ these extensions look +exactly like native C++ classes. Neither C++ code nor Perl code needs +to know where a particular method is implemented: the combination of +proxy classes, director classes, and C wrapper functions takes care of +all the cross-language method routing transparently. +</p> + +<H3><a name="Perl5_nn48"></a>31.11.1 Enabling directors</H3> + + +<p> +The director feature is disabled by default. To use directors you +must make two changes to the interface file. First, add the "directors" +option to the %module directive, like this: +</p> + +<div class="code"> +<pre> +%module(directors="1") modulename +</pre> +</div> + +<p> +Without this option no director code will be generated. Second, you +must use the %feature("director") directive to tell SWIG which classes +and methods should get directors. The %feature directive can be applied +globally, to specific classes, and to specific methods, like this: +</p> + +<div class="code"> +<pre> +// generate directors for all classes that have virtual methods +%feature("director"); + +// generate directors for all virtual methods in class Foo +%feature("director") Foo; +</pre> +</div> + +<p> +You can use the %feature("nodirector") directive to turn off +directors for specific classes or methods. So for example, +</p> + +<div class="code"> +<pre> +%feature("director") Foo; +%feature("nodirector") Foo::bar; +</pre> +</div> + +<p> +will generate directors for all virtual methods of class Foo except +bar(). +</p> + +<p> +Directors can also be generated implicitly through inheritance. +In the following, class Bar will get a director class that handles +the methods one() and two() (but not three()): +</p> + +<div class="code"> +<pre> +%feature("director") Foo; +class Foo { +public: + Foo(int foo); + virtual void one(); + virtual void two(); +}; + +class Bar: public Foo { +public: + virtual void three(); +}; +</pre> +</div> + +<p> +then at the Perl side you can define +</p> + +<div class="targetlang"> +<pre> +use mymodule; + +package MyFoo; +use base 'mymodule::Foo'; + +sub one { + print "one from Perl\n"; +} +</pre> +</div> + + +<H3><a name="Perl5_nn49"></a>31.11.2 Director classes</H3> + + + + + +<p> +For each class that has directors enabled, SWIG generates a new class +that derives from both the class in question and a special +<tt>Swig::Director</tt> class. These new classes, referred to as director +classes, can be loosely thought of as the C++ equivalent of the Perl +proxy classes. The director classes store a pointer to their underlying +Perl object and handle various issues related to object ownership. +</p> + +<p> +For simplicity let's ignore the <tt>Swig::Director</tt> class and refer to the +original C++ class as the director's base class. By default, a director +class extends all virtual methods in the inheritance chain of its base +class (see the preceding section for how to modify this behavior). +Thus all virtual method calls, whether they originate in C++ or in +Perl via proxy classes, eventually end up in at the implementation in +the director class. The job of the director methods is to route these +method calls to the appropriate place in the inheritance chain. By +"appropriate place" we mean the method that would have been called if +the C++ base class and its extensions in Perl were seamlessly +integrated. That seamless integration is exactly what the director +classes provide, transparently skipping over all the messy extension API +glue that binds the two languages together. +</p> + +<p> +In reality, the "appropriate place" is one of only two possibilities: +C++ or Perl. Once this decision is made, the rest is fairly easy. If +the correct implementation is in C++, then the lowest implementation of +the method in the C++ inheritance chain is called explicitly. If the +correct implementation is in Perl, the Perl API is used to call the +method of the underlying Perl object (after which the usual virtual +method resolution in Perl automatically finds the right +implementation). +</p> + +<p> +Now how does the director decide which language should handle the method call? +The basic rule is to handle the method in Perl, unless there's a good +reason not to. The reason for this is simple: Perl has the most +"extended" implementation of the method. This assertion is guaranteed, +since at a minimum the Perl proxy class implements the method. If the +method in question has been extended by a class derived from the proxy +class, that extended implementation will execute exactly as it should. +If not, the proxy class will route the method call into a C wrapper +function, expecting that the method will be resolved in C++. The wrapper +will call the virtual method of the C++ instance, and since the director +extends this the call will end up right back in the director method. Now +comes the "good reason not to" part. If the director method were to blindly +call the Perl method again, it would get stuck in an infinite loop. We avoid this +situation by adding special code to the C wrapper function that tells +the director method to not do this. The C wrapper function compares the +pointer to the Perl object that called the wrapper function to the +pointer stored by the director. If these are the same, then the C +wrapper function tells the director to resolve the method by calling up +the C++ inheritance chain, preventing an infinite loop. +</p> + +<p> +One more point needs to be made about the relationship between director +classes and proxy classes. When a proxy class instance is created in +Perl, SWIG creates an instance of the original C++ class. +This is exactly what happens without directors and +is true even if directors are enabled for the particular class in +question. When a class <i>derived</i> from a proxy class is created, +however, SWIG then creates an instance of the corresponding C++ director +class. The reason for this difference is that user-defined subclasses +may override or extend methods of the original class, so the director +class is needed to route calls to these methods correctly. For +unmodified proxy classes, all methods are ultimately implemented in C++ +so there is no need for the extra overhead involved with routing the +calls through Perl. +</p> + +<H3><a name="Perl5_nn50"></a>31.11.3 Ownership and object destruction</H3> + + +<p> +Memory management issues are slightly more complicated with directors +than for proxy classes alone. Perl instances hold a pointer to the +associated C++ director object, and the director in turn holds a pointer +back to a Perl object. By default, proxy classes own their C++ +director object and take care of deleting it when they are garbage +collected. +</p> + +<p> +This relationship can be reversed by calling the special +<tt>DISOWN()</tt> method of the proxy class. After calling this +method the director +class increments the reference count of the Perl object. When the +director class is deleted it decrements the reference count. Assuming no +outstanding references to the Perl object remain, the Perl object +will be destroyed at the same time. This is a good thing, since +directors and proxies refer to each other and so must be created and +destroyed together. Destroying one without destroying the other will +likely cause your program to segfault. +</p> + +<p> +Also note that due to the proxy implementation, the <tt>DESTROY()</tt> +method on directors can be called for several reasons, many of which +have little to do with the teardown of an object instance. To help +disambiguate this, a second argument is added to the <tt>DESTROY()</tt> +call when a C++ director object is being released. So, to avoid running +your clean-up code when an object is not really going away, or after it +has already been reclaimed, it is suggested that custom destructors in +Perl subclasses looks something like: +</p> + +<div class="targetlang"> +<pre> +sub DESTROY { + my($self, $final) = @_; + if($final) { + # real teardown code + } + shift->SUPER::DESTROY(@_); +} +</pre> +</div> + + +<H3><a name="Perl5_nn51"></a>31.11.4 Exception unrolling</H3> + + +<p> +With directors routing method calls to Perl, and proxies routing them +to C++, the handling of exceptions is an important concern. By default, the +directors ignore exceptions that occur during method calls that are +resolved in Perl. To handle such exceptions correctly, it is necessary +to temporarily translate them into C++ exceptions. This can be done with +the %feature("director:except") directive. The following code should +suffice in most cases: +</p> + +<div class="code"> +<pre> +%feature("director:except") { + if ($error != NULL) { + throw Swig::DirectorMethodException(); + } +} +</pre> +</div> + +<p> +This code will check the Perl error state after each method call from +a director into Perl, and throw a C++ exception if an error occurred. +This exception can be caught in C++ to implement an error handler. +</p> + +<p> +It may be the case that a method call originates in Perl, travels up +to C++ through a proxy class, and then back into Perl via a director +method. If an exception occurs in Perl at this point, it would be nice +for that exception to find its way back to the original caller. This can +be done by combining a normal %exception directive with the +<tt>director:except</tt> handler shown above. Here is an example of a +suitable exception handler: +</p> + +<div class="code"> +<pre> +%exception { + try { $action } + catch (Swig::DirectorException &e) { SWIG_fail; } +} +</pre> +</div> + +<p> +The class Swig::DirectorException used in this example is actually a +base class of Swig::DirectorMethodException, so it will trap this +exception. Because the Perl error state is still set when +Swig::DirectorMethodException is thrown, Perl will register the +exception as soon as the C wrapper function returns. +</p> + +<H3><a name="Perl5_nn52"></a>31.11.5 Overhead and code bloat</H3> + + +<p> +Enabling directors for a class will generate a new director method for +every virtual method in the class' inheritance chain. This alone can +generate a lot of code bloat for large hierarchies. Method arguments +that require complex conversions to and from target language types can +result in large director methods. For this reason it is recommended that +you selectively enable directors only for specific classes that are +likely to be extended in Perl and used in C++. +</p> + +<p> +Compared to classes that do not use directors, the call routing in the +director methods does add some overhead. In particular, at least one +dynamic cast and one extra function call occurs per method call from +Perl. Relative to the speed of Perl execution this is probably +completely negligible. For worst case routing, a method call that +ultimately resolves in C++ may take one extra detour through Perl in +order to ensure that the method does not have an extended Perl +implementation. This could result in a noticeable overhead in some cases. +</p> + +<p> +Although directors make it natural to mix native C++ objects with Perl +objects (as director objects) via a common base class pointer, one +should be aware of the obvious fact that method calls to Perl objects +will be much slower than calls to C++ objects. This situation can be +optimized by selectively enabling director methods (using the %feature +directive) for only those methods that are likely to be extended in +Perl. +</p> + +<H3><a name="Perl5_nn53"></a>31.11.6 Typemaps</H3> + + +<p> +Typemaps for input and output of most of the basic types from director +classes have been written. These are roughly the reverse of the usual +input and output typemaps used by the wrapper code. The typemap +operation names are 'directorin', 'directorout', and 'directorargout'. +The director code does not currently use any of the other kinds of typemaps. +It is not clear at this point which kinds are appropriate and +need to be supported. +</p> + + </body> |