Fix compiler flags so it compiles OK on all architectures.
[perl4caml.git] / doc / writing-a-wrapper.html
1 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
2 <html>
3   <head>
4     <title>Writing a high-level wrapper around a Perl library</title>
5     <link rel="stylesheet" href="http://www.merjis.com/css/default.css"
6       type="text/css">
7   </head>
8
9   <body bgcolor="#ffffff">
10     <h1>Writing a high-level wrapper around a Perl library</h1>
11
12     <p>
13       This document discusses the theory and practice behind writing
14       a wrapper around a typical object-oriented Perl library. We
15       use <a href="../html/Pl_LWP_UserAgent.html">Pl_LWP_UserAgent</a>
16       as an example. (This is the high-level wrapper around the
17       <a href="http://search.cpan.org/dist/libwww-perl/lib/LWP/UserAgent.pm">LWP::UserAgent</a>
18       library).
19     </p>
20
21     <p>
22       Don't worry - writing wrappers is really not very hard at all. I
23       hope that you, the reader, will write some wrappers around your
24       favorite Perl libraries and contribute them back to
25       <a href="http://www.merjis.com/developers/perl4caml/">perl4caml</a>
26       development.
27     </p>
28
29     <h2>First steps</h2>
30
31     <p>
32       I'm going to use <a href="http://search.cpan.org/dist/libwww-perl/lib/LWP/UserAgent.pm">LWP::UserAgent</a>
33       as my example throughout this document. Substitute that for whatever
34       library you want to wrap up and call from OCaml.
35       First of all make sure you have the library installed and working
36       under Perl, and make sure you have the manual page for that
37       library in front of you:
38     </p>
39
40 <pre>
41 perldoc LWP::UserAgent
42 </pre>
43
44     <p>
45       or <a href="http://search.cpan.org/dist/libwww-perl/lib/LWP/UserAgent.pm">follow
46         this link</a>.
47     </p>
48
49     <h2>Understanding what we're doing</h2>
50
51     <p>
52       The low-level <a href="../html/Perl.html">Perl</a> module offers
53       two useful functions and a useful datatype which we'll be using
54       extensively. The useful functions are:
55     </p>
56
57     <table class="table">
58         <tr>
59           <th> Function name </th>
60           <th> Perl equivalent </th>
61           <th> Description </th>
62         </tr>
63
64         <tr>
65           <td> <code>call_class_method</code> </td>
66           <td> <code>$obj&nbsp;=&nbsp;LWP::UserAgent-&gt;new&nbsp;(args...)</code> </td>
67           <td>
68             <p> Calls a static method or constructor on a class. </p>
69           </td>
70         </tr>
71
72         <tr>
73           <td> <code>call_method</code> </td>
74           <td> <code>$obj-&gt;some_method&nbsp;(args...)</code> </td>
75           <td>
76             <p> Calls an instance method on an object. </p>
77           </td>
78         </tr>
79     </table>
80
81     <p>
82       The useful datatype is called the <code>Perl.sv</code> (an
83       abstract type), which represents a scalar value in Perl (anything
84       you would normally write in Perl with a <code>$</code>, including
85       numbers, strings, references and blessed objects). To find out
86       more about "SVs" see <a href="http://www.perldoc.com/perl5.8.0/pod/perlguts.html">the perlguts(3) man page</a>.
87     </p>
88
89     <p>
90       To see how these three things interact, let's create an
91       <code>LWP::UserAgent</code> object and call a method on it:
92     </p>
93
94 <pre>
95 # #load "perl4caml.cma";;
96 # open Perl;;
97 # let sv = call_class_method "LWP::UserAgent" "new" [];;
98 <i>val sv : Perl.sv = &lt;abstr&gt;</i>
99 # let agent = call_method sv "agent" [];;
100 <i>val agent : Perl.sv = &lt;abstr&gt;</i>
101 # string_of_sv agent;;
102 <i>- : string = "libwww-perl/5.69"</i>
103 </pre>
104
105     <p>
106       Note how the variable <code>sv</code> contains the actual Perl
107       object (an instance of <code>LWP::UserAgent</code>).  To be
108       quite clear, this is the equivalent of the following Perl code:
109     </p>
110
111 <pre>
112 $sv = LWP::UserAgent-&gt;new ();
113 $agent = $sv-&gt;agent ();
114 print $agent;
115 </pre>
116
117     <p>
118       You could actually just continue to use the low-level interface
119       to access Perl objects directly, but there are three problems with
120       this: firstly it's cumbersome because you have to continually
121       convert to and from SVs; secondly it's not type safe
122       (eg. calling <code>string_of_sv</code> might fail if the SV
123       isn't actually a string); thirdly there are more pleasant ways
124       to present this interface.
125     </p>
126
127     <p>
128       Writing a high-level wrapper around these low-level operations
129       is what is described in the rest of this document ...
130     </p>
131
132     <h2>Classes and constructors</h2>
133
134     <p>
135       Our general plan, therefore, will be to create an OCaml class
136       corresponding to <code>LWP::UserAgent</code>, which hides the
137       implementation (the <code>sv</code>, the calls to
138       <code>call_method</code>, and the conversion of arguments
139       to and from SVs). We will also need to write one or more constructor
140       function.
141     </p>
142
143     <p>
144       We will write at least one method for every method exported by
145       the Perl interface. Sometimes we'll write two methods for each
146       Perl method, as in the case where a Perl method is a "getter/setter":
147     </p>
148
149 <pre>
150 $ua-&gt;agent([$product_id])
151    Get/set the product token that is used to identify the user agent
152    on the network.  The agent value is sent as the "User-Agent" header
153    in the requests.
154 </pre>
155
156     <p>
157       becomes two methods in the OCaml version:
158     </p>
159
160 <pre>
161 class lwp_useragent sv = object (self)
162   (* ... *)
163   method agent : string
164   method set_agent : string -&gt; unit
165 end
166 </pre>
167
168     <p>
169       We will also write at least one function for every
170       constructor or static function exported from Perl.
171     </p>
172
173     <p>
174       The OCaml object itself contains the <code>sv</code> which
175       corresponds to the Perl SV (ie. the actual Perl object).
176     </p>
177
178     <p>
179       Here is the shape of our class:
180     </p>
181
182 <pre>
183 (** Wrapper around Perl [LWP::UserAgent] class.
184   *
185   * Copyright (C) 20xx <i>your_organisation</i>
186   *
187   * $ Id $
188   *)
189
190 open Perl
191
192 let _ = eval "use LWP::UserAgent"
193
194 class lwp_useragent sv = object (self)
195
196   <i>The methods will go here ...</i>
197
198 end
199
200 (* The "new" constructor. Note that "new" is a reserved word in OCaml. *)
201 let new_ ... =
202   ...
203   let sv = call_class_method "LWP::UserAgent" "new" [<i>args ...</i>] in
204   new lwp_useragent sv
205
206 <i>Any other static functions will go here ...</i>
207 </pre>
208
209     <p>
210       Notice a few things here:
211     </p>
212
213     <ol>
214       <li> There is some ocamldoc describing the class.
215       <li> We "open Perl" to avoid having to prefix everything with
216         <code>Perl.</code>.
217       <li> We <code>eval "use LWP::UserAgent"</code> when the module
218         is loaded. This is required by Perl.
219       <li> The <code>sv</code> (scalar value representing the actual
220         object) is passed as a parameter to the class.
221     </ol>
222
223     <h2>Writing methods</h2>
224
225     <h3>Getters and setters</h3>
226
227     <p>
228       Of all types of methods, getters and setters are the easiest
229       to write. First of all, check the manual page to find out what
230       type the slot is. You'll need to write one get method and
231       one set method. (Rarely you'll find getters and setters which
232       are quasi-polymorphic, for instance they can take a string or
233       an arrayref. You'll need to think more deeply about these,
234       because they require one set method for each type, and the
235       get method can be complicated).
236     </p>
237
238     <p>
239       Here's our getter and setter for the agent slot, described above.
240       The agent is a string:
241     </p>
242
243 <pre>
244   method agent =
245     string_of_sv (call_method sv "agent" [])
246   method set_agent v =
247     call_method_void sv "agent" [sv_of_string v]
248 </pre>
249
250     <p>
251       Note:
252     </p>
253
254     <ol>
255       <li> The get method is just called <code>agent</code> (not
256         "get_agent"). This is the standard for OCaml code.
257       <li> We use <code>string_of_sv</code> and <code>sv_of_string</code>
258         to convert to and from SVs. This will ensure that the
259         class interface will have the correct type (string), and
260         thus be type safe as far as the calling code is concerned,
261         and also means the caller doesn't need to worry about
262         SVs.
263       <li> The set method called <code>call_method_void</code> which
264         we haven't seen before. This is exactly the same as
265         <code>call_method</code> except that the method is called
266         in a "void context" - in other words, any return value is
267         thrown away. This is slightly more efficient than ignoring
268         the return value.
269     </ol>
270
271     <p>
272       Here's another example, with a boolean slot:
273     </p>
274
275 <pre>
276   method parse_head =
277     bool_of_sv (call_method sv "parse_head" [])
278   method set_parse_head v =
279     call_method_void sv "parse_head" [sv_of_bool v]
280 </pre>
281
282     <h3>Ordinary methods</h3>
283
284     <p>
285       Other methods are perhaps simpler to wrap than getters and
286       setters. <code>LWP::UserAgent</code> contains an interesting
287       method called <code>request</code> (which actually runs the
288       request).
289     </p>
290
291     <p>
292       What's particularly interesting about this method are the
293       parameter and return value. It takes an <code>HTTP::Request</code>
294       object and returns an <code>HTTP::Response</code>.
295     </p>
296
297     <p>
298       I have already wrapped <code>HTTP::Request</code> and
299       <code>HTTP::Response</code> as modules
300       <a href="../html/Pl_HTTP_Request.html">Pl_HTTP_Request</a> and
301       <a href="../html/Pl_HTTP_Response.html">Pl_HTTP_Response</a>
302       respectively. You should go and look at the code in those
303       modules now.
304     </p>
305
306     <p>
307       If <code>request</code> requires a parameter, what should that
308       parameter be? Naturally it should be the SV corresponding to
309       the <code>HTTP::Request</code> object. To get this, I provided
310       an <code>#sv</code> method on the <code>http_request</code> class.
311     </p>
312
313     <p>
314       And what will <code>request</code> return? Naturally it will
315       return an SV which corresponds to the (newly created inside
316       Perl) <code>HTTP::Response</code> object. We need to wrap
317       this up and create a new OCaml <code>http_response</code> object,
318       <em>containing that SV</em>.
319     </p>
320
321     <p>
322       This is what the final method looks like:
323     </p>
324
325 <pre>
326   method request (request : http_request) =
327     let sv = call_method sv "request" [request#sv] in
328     new http_response sv
329 </pre>
330
331     <p>
332       It's actually not so complicated.
333     </p>
334
335     <h2>Writing constructors and static functions</h2>
336
337     <p>
338       Constructors are fairly simple, although the <code>new_</code>
339       function inside <code>Pl_LWP_UserAgent</code> is complicated
340       by the many optional arguments which <code>LWP::UserAgent-&gt;new</code>
341       can take.
342     </p>
343
344     <p>
345       Here is the guts, omitting all but one of the optional args:
346     </p>
347
348 <pre>
349 let new_ ?agent (* ... *) () =
350   let args = ref [] in
351   let may f = function None -&gt; () | Some v -&gt; f v in
352   may (fun v -&gt;
353          args := sv_of_string "agent" :: sv_of_string v :: !args) agent;
354 (* ... *)
355   let sv = call_class_method "LWP::UserAgent" "new" !args in
356   new lwp_useragent sv
357 </pre>
358
359     <p>
360       It works simply enough, first building up a list of <code>sv</code>s
361       corresponding to the arguments, then calling
362       <code>call_class_method</code> to create the Perl object, then
363       returning a constructed OCaml <code>lwp_useragent</code> object
364       containing that <code>sv</code>.
365     </p>
366
367     <h2>Contributing wrappers back to perl4caml</h2>
368
369     <p>
370       If you write a wrapper for a Perl class, particularly one from
371       <a href="http://www.cpan.org/">CPAN</a>, I urge you to
372       contribute it back to the <a
373       href="http://www.merjis.com/developers/perl4caml/">perl4caml</a>
374       development effort. Your contribution enriches the project
375       as a whole, and makes OCaml more useful too.
376     </p>
377
378     <hr>
379     <address><a href="mailto:rich@annexia.org">Richard W.M. Jones</a></address>
380 <!-- Created: Thu Oct 16 13:36:59 BST 2003 -->
381 <!-- hhmts start -->
382 Last modified: Thu Oct 16 14:39:02 BST 2003
383 <!-- hhmts end -->
384   </body>
385 </html>