source: trunk/source/doc/src/objc-bridge.xml @ 8895

Last change on this file since 8895 was 8895, checked in by mikel, 12 years ago

working on objective-c bridge docs

File size: 32.2 KB
1<?xml version="1.0" encoding="utf-8"?>
2<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" ""[
3          <!ENTITY rest "<varname>&amp;rest</varname>">
4          <!ENTITY key "<varname>&amp;key</varname>">
5          <!ENTITY optional "<varname>&amp;optional</varname>">
6          <!ENTITY body "<varname>&amp;body</varname>">
7          <!ENTITY aux "<varname>&amp;aux</varname>">
8          <!ENTITY allow-other-keys "<varname>&amp;allow-other-keys</varname>">
9          <!ENTITY CCL "Clozure CL">
10          ]>
11<chapter id="The-Objective-C-Bridge">
12  <title>The Objective-C Bridge</title>
14  <para>Mac OS X APIs use a language called Objective-C, which is
15    approximately C with some object-oriented extensions modeled on
16    Smalltalk.  The Objective-C bridge makes it possible to work with
17    Objective-C objects and classes from Lisp, and to define classes
18    in Lisp which can be used by Objective-C.</para>
19  <para>The ultimate purpose of the Objective-C and Cocoa bridges is
20    to make Cocoa (the standard user-interface framework on Mac OS X)
21    as easy as possible to use from &CCL;, in order to support the
22    development of GUI applications and IDEs on Mac OS X (and on any
23    platform that supports Objective-C, such as GNUStep).  The
24    eventual goal, which is much closer than it used to be, is
25    complete integration of Cocoa into CLOS.</para>
26  <para>The current release provides Lisp-like syntax and naming
27    conventions for the basic Objective-C operations, with automatic type
28    processing and messages checked for validity at compile-time.  It
29    also provides some convenience facilities for working with
30    Cocoa.</para>
32  <sect1 id="Using-Objective-C-Classes">
33    <title>Using Objective-C Classes</title>
35    <para>The class of most standard CLOS classes is named
36      STANDARD-CLASS. In the Objective-C object model, each class is
37      an instance of a (usually unique) metaclass, which is itself an
38      instance of a "base" metaclass (often the metaclass of the class
39      named "NSObject".) So, the Objective-C class named "NSWindow"
40      and the Objective-C class "NSArray" are (sole) instances of
41      their distinct metaclasses whose names are also "NSWindow" and
42      "NSArray", respectively. (In the Objective-C world, it's much
43      more common and useful to specialize class behavior such as
44      instance allocation.)</para>
45    <para>When &CCL; first loads foreign libraries containing
46      Objective-C classes, it identifies the classes they contain. The
47      foreign class name, such as "NSWindow", is mapped to an external
48      symbol in the "NS" package via the bridge's translation rules,
49      such as NS:NS-WINDOW.  A similar transformation happens to the
50      metaclass name, with a "+" prepended, yielding something like
51      NS:+NS-WINDOW.</para>
52    <para>These classes are integrated into CLOS such that the
53      metaclass is an instance of the class OBJC:OBJC-METACLASS and
54      the class
55      is an instance of the metaclass. SLOT-DESCRIPTION metaobjects are
56      created for each instance variable, and the class and metaclass go
57      through something very similar to the "standard" CLOS class
58      initialization protocol (with a difference being that these classes
59      have already been allocated.)</para>
60    <para>Performing all this initialization, which is done when you
61      (require "COCOA"), currently takes several
62      seconds; it could conceivably be sped up some, but it's never likely
63      to be fast.</para>
64    <para>When the process is complete, CLOS is aware of several hundred
65      new Objective-C classes and their metaclasses. &CCL;'s runtime system can
66      reliably recognize MACPTRs to Objective-C classes as being CLASS objects, and
67      can (fairly reliably but heuristically) recognize instances of those
68      classes (though there are complicating factors here; see below.)
69      SLOT-VALUE can be used to access (and, with care, set) instance
70      variables in Objective-C instances. To see this, do:</para>
71    <programlisting>
72      ? (require "COCOA")
73    </programlisting>
74    <para>and, after waiting a bit longer for a Cocoa listener window to
75      appear, activate that Cocoa listener and do:</para>
76    <programlisting>? (describe (ccl::send ccl::*NSApp* 'key-window))
77    </programlisting>
78    <para>This sends a message asking for the key window, which is the window
79      that has the input focus (often the frontmost), and then describes
80      it. As we can see, NS:NS-WINDOWs have lots of interesting slots.</para>
81  </sect1>
83  <sect1 id="Instantiating-Objective-C-Objects">
84    <title>Instantiating Objective-C Objects</title>
85    <para>Making an instance of an Objective-C class (whether the class in
86      question is predefined or defined by the application) involves
87      calling MAKE-INSTANCE with the class and a set of initargs as
88      arguments.  As with STANDARD-CLASS, making an instance involves
89      initializing (with INITIALIZE-INSTANCE) an object allocated with
90      ALLOCATE-INSTANCE.</para>
91    <para>For example, you can create an ns:ns-number like this:</para>
92    <programlisting>
93      ? (make-instance 'ns:ns-number :init-with-int 42)
94      #&lt;NS-CF-NUMBER 42 (#x85962210)>
95    </programlisting>
96    <para>It's worth looking at how this would be done if you were
97      writing in Objective C:</para>
98    <programlisting>
99      [[NSNumber alloc] initWithInt: 42]
100    </programlisting>
101    <para>Allocating an instance of an Objective-C class involves sending the
102      class an "alloc" message, and then using those initargs that
103      <emphasis>don't</emphasis> correspond to slot initags as the
104      "init" message to be sent to the newly-allocated instance.  So, the
105      example above could have been done more verbosely as:</para>
106    <programlisting>
107      ? (defvar *n* (ccl::send (find-class 'ns:ns-number) 'alloc))
108      *N*
110      ? (setq *n* (ccl::send *n* :init-with-int 42))
111      #&lt;NS-CF-NUMBER 42 (#x16D340)>
112    </programlisting>
113    <para>That setq is important; this is a case where init
114      decides to replace the object and return the new one, instead
115      of modifying the existing one.
116      In fact, if you leave out the setq and
117      then try to view the value of *N*, &CCL; will freeze.  There's
118      little reason to ever do it this way; this is just to show
119      what's going on.</para>
120    <para>You've seen that an Objective-C initialization method doesn't have to
121      return the same object it was passed.  In fact, it doesn't have
122      to return any object at all; in this case, the initialization fails
123      and make-instance returns nil.</para>
124    <para>In some special cases, such as loading an ns:ns-window-controller
125      from a .nib file, it may be necessary for you to pass the
126      instance itself as one of the parameters to the initialization
127      method.  It goes like this:</para>
128    <programlisting>
129      ? (defvar *controller*
130      (make-instance 'ns:ns-window-controller))
131      *CONTROLLER*
133      ? (setq *controller*
134      (ccl::send *controller*
135      :init-with-window-nib-name #@"DataWindow"
136      :owner *controller*))
137      #&lt;NS-WINDOW-CONTROLLER &lt;NSWindowController: 0x1fb520> (#x1FB520)>
138    </programlisting>
139    <para>This example calls (make-instance) with no initargs.  When you
140      do this, the object is only allocated, and not initialized.  It
141      then sends the "init" message to do the initialization by hand.</para>
142  </sect1>
144  <sect1 id="Calling-Objective-C-Methods">
145    <title>Calling Objective-C Methods</title>
146    <para>In Objective-C, methods are called "messages", and there's
147      a special syntax to send a message to an object:</para>
148    <programlisting>
149      [w alphaValue]
150      [w setAlphaValue: 0.5]
151      [v mouse: p inRect: r]
152    </programlisting>
153    <para>The first line sends the method "alphaValue" to the object
154      <literal>w</literal>, with no parameters.  The second line sends
155      the method "setAlphaValue", with the parameter 0.5.  The third
156      line sends the method "mouse:inRect:" - yes, all one long word -
157      with the parameters <literal>p</literal> and
158      <literal>r</literal>.</para>
159    <para>In Lisp, these same three lines are:</para>
160    <programlisting>
161      (send w 'alpha-value)
162      (send w :set-alpha-value 0.5)
163      (send v :mouse p :in-rect r)
164    </programlisting>
165    <para>Notice that when a method has no parameters, its name is an ordinary
166      symbol (it doesn't matter what package the symbol is in, as
167      only its name is checked).  When a method has parameters,
168      each part of its name is a keyword, and the keywords alternate
169      with the values.</para>
170    <para>These two lines break those rules, and both  will
171      result in error messages:</para>
172    <programlisting>
173      (send w :alpha-value)
174      (send w 'set-alpha-value 0.5)
175    </programlisting>
176    <para>Instead of (send), you can also invoke (send-super), with the
177      same interface.  It has roughly the same purpose as CLOS's
178      (call-next-method); when you use (send-super), the message is
179      handled by the superclass.  This can be used to get at the
180      original implementation of a method when it is shadowed by a
181      method in your subclass.</para>
183    <sect2 id="Type-Coercion-for-ObjC-Method-Calls">
184          <title>Type Coercion for Objective-C Method Calls</title>
185      <para>&CCL;'s FFI handles many common conversions between
186        Lisp and foreign data, such as unboxing floating-point args
187        and boxing floating-point results.  The bridge adds a few more
188        automatic conversions:</para>
189      <para>NIL is equivalent to (%NULL-PTR) for any message
190        argument that requires a pointer.</para>
191      <para>T/NIL are equivalent to #$YES/#$NO for any boolean argument.</para>
192      <para>A #$YES/#$NO returned by any method that returns BOOL
193        will be automatically converted to T/NIL.</para>
194    </sect2>
196    <sect2 id="Methods-which-Return-Structures">
197          <title>Methods which Return Structures</title>
198      <para>Some Cocoa methods return small structures, such as
199        those used to represent points, rects, sizes and ranges. When
200        writing in Objective C, the compiler hides the implementation
201        details.  Unfortunately, in Lisp we must be slightly more
202        aware of them.</para>
203      <para>Methods which return structures are called in a special
204        way; the caller allocates space for the result, and passes a
205        pointer to it as an extra argument to the method.  This is
206        called a Structure Return, or STRET.  Don't look at me; I
207        don't name these things.</para>
208      <para>Here's a simple use of this in Objective C.  The first line
209            sends the "bounds" message to v1, which returns a rectangle.
210            The second line sends the "setBounds" message to v2, passing
211            that same rectangle as a parameter.</para>
212      <programlisting>
213        NSRect r = [v1 bounds];
214        [v2 setBounds r];
215          </programlisting>
216      <para>In Lisp, we must explicitly allocate the memory, which
217        is done most easily and safely with <xref linkend="m_rlet"/>.
218        We do it like this:</para>
219      <programlisting>
220(rlet ((r :&lt;NSR&gt;ect))
221          (send/stret r v1 'bounds)
222          (send v2 :set-bounds r))
223      </programlisting>
224      <para>The rlet allocates the storage (but doesn't initialize
225        it), and makes sure that it will be deallocated when we're
226        done.  It binds the variable r to refer to it.  The call to
227        <literal>send/stret</literal> is just like an ordinary call to
228        <literal>send</literal>, except that r is passed as an extra,
229        first parameter.  The third line, which calls
230        <literal>send</literal>, does not need to do anything special,
231        because there's nothing complicated about passing a structure
232        as a parameter.</para>
233          <para>In order to make STRETs easier to use, the bridge
234            provides two conveniences.</para>
235      <para>First, you can use the macros <literal>slet</literal>
236        and <literal>slet*</literal> to allocate and initialize local
237        variables to foreign structures in one step.  The example
238        above could have been written more tersely as:</para>
239      <programlisting>
240(slet ((r (send v1 'bounds)))
241      (send v2 :set-bounds r))
242          </programlisting>
243      <para>Second, when one call to <literal>send</literal> is made
244        inside another, the inner one has an implicit
245        <literal>slet</literal> around it.  So, one could in fact
246        just write:</para>
247      <programlisting>
248(send v1 :set-bounds (send v2 'bounds))
249      </programlisting>
250      <para>There are also several psuedo-functions provided for convenience
251        by the Objective-C compiler, to make objects of specific types. The
252        following are currently supported by the bridge: NS-MAKE-POINT,
253        NS-MAKE-RANGE, NS-MAKE-RECT, and NS-MAKE-SIZE.</para>
254      <para>These pseudo-functions can be used within an SLET initform:</para>
255      <programlisting>
256(slet ((p (ns-make-point 100.0 200.0)))
257      (send w :set-frame-origin p))
258      </programlisting>
259      <para>Or within a call to <literal>send</literal>:</para>
260      <programlisting>
261(send w :set-origin (ns-make-point 100.0 200.0))
262      </programlisting>
263      <para>However, since these aren't real functions, a call like the
264        following won't work:</para>
265      <programlisting>
266(setq p (ns-make-point 100.0 200.0))
267      </programlisting>
268      <para>To extract fields from these objects, there are also some
269        convenience macros: NS-MAX-RANGE, NS-MIN-X,
270        NS-MIN-Y, NS-MAX-X, NS-MAX-Y, NS-MID-X, NS-MID-Y,
271        NS-HEIGHT, and NS-WIDTH.</para>
272      <para>Note that there is also a <literal>send-super/stret</literal>
273        for use within methods.  Like <literal>send-super</literal>,
274        it ignores any shadowing methods in a subclass, and calls the
275        version of a method which belongs to its superclass.</para>
276    </sect2>
278    <sect2 id="Variable-Arity-Messages">
279          <title>Variable-Arity Messages</title>
280      <para>
281        There are a few messages in Cocoa which take variable numbers
282        of arguments. Perhaps the most common examples involve
283        formatted strings:</para>
284      <programlisting>
285[NSClass stringWithFormat: "%f %f" x y]
286      </programlisting>
287      <para>In Lisp, this would be written:</para>
288      <programlisting>
289(send (find-class 'ns:ns-string)
290      :string-with-format #@"%f %f"
291      (:double-float x :double-float y))
292      </programlisting>
293      <para>Note that it's necessary to specify the foreign types of the
294        variables (in this example, :double-float), because the
295        compiler has no general way of knowing these types.  (You
296        might think that it could parse the format string, but this
297        would only work for format strings which are not determined
298        at runtime.)</para>
299      <para>Because the Objective-C runtime system does not provide any information
300        on which messages are variable arity, they must be explicitly
301        declared. The standard variable arity messages in Cocoa are
302        predeclared by the bridge.  If you need to declare a new
303        variable arity message, use
304        (DEFINE-VARIABLE-ARITY-MESSAGE "myVariableArityMessage:").</para>
305    </sect2>
307    <sect2 id="Optimization">
308          <title>Optimization</title>
309      <para>The bridge works fairly hard to optimize message sends,
310        when it has enough information to do so.  There are two cases
311        when it does.  In either, a message send should be nearly as
312        efficient as when writing in Objective C.</para>
313      <para>The first case is when both the message and the
314        receiver's class are known at compile-time. In general, the
315        only way the receiver's class is known is if you declare it,
316        which you can do with either a DECLARE or a THE form.  For
317        example:</para>
318      <programlisting>
319(send (the ns:ns-window w) 'center)
320          </programlisting>
321      <para>Note that there is no way in Objective-C to name the class of a
322        class.  Thus the bridge provides a declaration, @METACLASS.
323        The type of an instance of "NSColor" is ns:ns-color.  The type
324        of the <emphasis>class</emphasis> "NSColor" is (@metaclass
325        ns:ns-color):</para>
326      <programlisting>
327(let ((c (find-class 'ns:ns-color)))
328  (declare ((ccl::@metaclass ns:ns-color) c))
329  (send c 'white-color))
330      </programlisting>
331      <para>The other case that alllows optimization is when only
332        the message is known at compile-time, but its type signature
333        is unique. Of the more-than-6000 messages currently provided
334        by Cocoa, only about 50 of them have nonunique type
335        signatures.</para>
336      <para>An example of a message with a type signature that is
337        not unique is SET.  It returns VOID for NSColor, but ID for
338        NSSet.  In order to optimize sends of messages with nonunique
339        type signatures, the class of the receiver must be declared at
340        compile-time.</para>
341      <para>If the type signature is nonunique or the message is
342        unknown at compile-time, then a slower runtime call must be
343        used.</para>
344      <para>When the receiver's class is unknown, the bridge's
345        ability to optimize relies on a type-signature table which it
346        maintains.  When first loaded, the bridge initializes this
347        table by scanning every method of every Objective-C class.  When new
348        methods are defined later, the table must be updated.  This
349        happens automatically when you define methods in Lisp.  After
350        any other major change, such as loading an external framework,
351        you should rebuild the table:</para>
352      <programlisting>
353? (update-type-signatures)
354      </programlisting>
355      <para>Because <literal>send</literal> and its relatives
356        <literal>send-super</literal>, <literal>send/stret</literal>,
357        and <literal>send-super/stret</literal> are macros, they
358        cannot be <literal>funcall</literal>ed,
359        <literal>apply</literal>ed, or passed as arguments to
360        functions.</para>
361      <para>To work around this, there are function equivalents to
362        them: <literal>%send</literal>,
363        <literal>%send-super</literal>,
364        <literal>%send/stret</literal>, and
365        <literal>%send-super/stret</literal>.  However, these
366        functions should be used only when the macros will not do,
367        because they are unable to optimize.</para>
368    </sect2>
369  </sect1>
371  <sect1 id="Defining-Objective-C-Classes">
372    <title>Defining Objective-C Classes</title>
373    <para>You can define your own foreign classes, which can then be
374      passed to foreign functions; the methods which you implement in
375      Lisp will be made available to the foreign code as
376      callbacks.</para>
377    <para>You can also define subclasses of existing classes,
378      implementing your subclass in Lisp even though the parent class
379      was in Objective C.  One such subclass is CCL::NS-LISP-STRING.
380      It is also particularly useful to make subclasses of
381      NS-WINDOW-CONTROLLER.</para>
382    <para>We can use the MOP to define new Objective-C classes, but
383      we have to do something a little funny: the :METACLASS that we'd
384      want to use in a DEFCLASS option generally doesn't exist until
385      we've created the class (recall that Objective-C classes have, for the
386      sake of argument, unique and private metaclasses.) We can sort
387      of sleaze our way around this by specifying a known Objective-C
388      metaclass object name as the value of the DEFCLASS :METACLASS
389      object; the metaclass of the root class NS:NS-OBJECT,
390      NS:+NS-OBJECT, makes a good choice. To make a subclass of
391      NS:NS-WINDOW (that, for simplicity's sake, doesn't define any
392      new slots), we could do:</para>
393    <programlisting>
394(defclass example-window (ns:ns-window)
395  ()
396  (:metaclass ns:+ns-object))
397    </programlisting>
398    <para>That'll create a new Objective-C class named EXAMPLE-WINDOW whose
399      metaclass is the class named +EXAMPLE-WINDOW. The class will be
400      an object of type OBJC:OBJC-CLASS, and the metaclass will be of
401      type OBJC:OBJC-METACLASS.  EXAMPLE-WINDOW will be a subclass of
402      NS-WINDOW.</para>
404    <sect2 id="Defining-classes-with-foreign-slots">
405          <title>Defining classes with foreign slots</title>
406      <para>If a slot specification in an Objective-C class
407        definition contains the keyword :FOREIGN-TYPE, the slot will
408        be a "foreign slot" (i.e. an Objective-C instance variable). Be aware
409        that it is an error to redefine an Objective-C class so that its
410        foreign slots change in any way, and &CCL; doesn't do
411        anything consistent when you try to.</para>
412      <para>The value of the :FOREIGN-TYPE initarg should be a
413        foreign type specifier. For example, if we wanted (for some
414        reason) to define a subclass of NS:NS-WINDOW that kept track
415        of the number of key events it had received (and needed an
416        instance variable to keep that information in), we could
417        say:</para>
418      <programlisting>
419(defclass key-event-counting-window (ns:ns-window)
420  ((key-event-count :foreign-type :int
421                    :initform 0
422                    :accessor window-key-event-count))
423  (:metaclass ns:+ns-object))
424      </programlisting>
425      <para>Foreign slots are always SLOT-BOUNDP, and the initform
426        above is redundant: foreign slots are initialized to binary
427        0.</para>
428    </sect2>
430    <sect2 id="Defining-classes-with-Lisp-slots">
431          <title>Defining classes with Lisp slots</title>
432      <para>A slot specification in an Objective-C class definition that
433        doesn't contain the :FOREIGN-TYPE initarg defines a
434        pretty-much normal lisp slot that'll happen to be associated
435        with "an instance of a foreign class". For instance:</para>
436      <programlisting>
437(defclass hemlock-buffer-string (ns:ns-string)
438  ((hemlock-buffer :type hi::hemlock-buffer
439                   :initform hi::%make-hemlock-buffer
440                   :accessor string-hemlock-buffer))
441  (:metaclass ns:+ns-object))
442          </programlisting>
443      <para>As one might expect, this has memory-management
444        implications: we have to maintain an association between a
445        MACPTR and a set of lisp objects (its slots) as long as the
446        Objective-C instance exists, and we have to ensure that the Objective-C
447        instance exists (does not have its -dealloc method called)
448        while lisp is trying to think of it as a first-class object
449        that can't be "deallocated" while it's still possible to
450        reference it. Associating one or more lisp objects with a
451        foreign instance is something that's often very useful; if you
452        were to do this "by hand", you'd have to face many of the same
453        memory-management issues.</para>
454    </sect2>
455  </sect1>
457  <sect1 id="Defining-Objective-C-Methods">
458    <title>Defining Objective-C Methods</title>
459    <para>In Objective-C, unlike in CLOS, every method belongs to some
460      particular class.  This is probably not a strange concept to
461      you, because C++ and Java do the same thing.  When you use Lisp
462      to define Objective-C methods, it is only possible to define methods
463      belonging to Objective-C classes which have been defined in
464      Lisp.</para>
465    <para>The macro <literal>define-objc-method</literal> is used
466      for this.  As described in , the names of Objective-C methods are
467      broken into pieces, each piece followed by a parameter.  The
468      types of all parameters must be explicitly declared.</para>
469    <para>Right now, I'm not sure how to formally describe the usage
470      of define-objc-method, so I'm going to do it with some short
471      examples.  Let us define a class to use in them:</para>
472    <programlisting>
473(defclass data-window-controller (ns:ns-window-controller)
474  ((window :foreign-type :id :accessor window)
475   (data :initform nil :accessor data))
476  (:metaclass ns:+ns-object))
477    </programlisting>
478    <para>There's nothing special about this class.  It inherits
479      from ns:ns-window-controller.  It has two slots:
480      <literal>window</literal> is a foreign slot, stored in the Objective-C
481      world; and <literal>data</literal> is an ordinary slot, stored
482      in the Lisp world.</para>
483    <para>Here is an example of how to define a method which takes
484      no arguments.  It happens to be an initialization method, but
485      that's not important:</para>
486    <programlisting>
487(define-objc-method ((:id get-window)
488                     data-window-controller)
489    (window self))
490    </programlisting>
491    <para>The return type of this method is the foreign type :id,
492      which is used for all Objective-C objects.  The name of the method is
493      <literal>get-window</literal>.  The body of the method is the
494      single line (window self).  The variable <literal>self</literal>
495      is bound, within the body, to the instance which is receiving
496      the message.  The call to <literal>window</literal> uses the
497      CLOS accessor to get the value of the window field.</para>
498    <para>Here's an example which takes a parameter.  Notice that
499      the name of the method without a parameter was an ordinary
500      symbol, but with a parameter, it's a keyword:</para>
501    <programlisting>
502(define-objc-method ((:id :init-with-multiplier (:int multiplier))
503                     data-window-controller)
504    (setf (data self) (make-array 100))
505  (dotimes (i 100)
506    (setf (aref (data self) i)
507          (* i multiplier)))
508  self)
509    </programlisting>
510    <para>To Objective-C code which uses the class, the name of this
511      method is "initWithMultiplier:".  The name of the parameter is
512      <literal>multiplier</literal>, and its type is :int.  The body
513      of the method does some meaningless things.  Then it returns
514      <literal>self</literal>, because this is an initialization
515      method.</para>
516    <para>Here's an example with more than one parameter:</para>
517    <programlisting>
518(define-objc-method ((:id :init-with-multiplier (:int multiplier)
519                          :and-addend (:int addend))
520                     data-window-controller)
521    (setf (data self) (make-array size))
522  (dotimes (i 100)
523    (setf (aref (data self) i)
524          (+ (* i multiplier)
525             addend)))
526  self)
527    </programlisting>
528    <para>To Objective-C, the name of this method is
529      "initWithMultiplier:andAddend:".  Both parameters are of type
530      :int; the first is named <literal>multiplier</literal>, and the
531      second is <literal>addend</literal>.  Again, the method returns
532      <literal>self</literal>.</para>
533    <para>Here is a method which does not return any value, a
534      so-called "void method".  Where our other methods said :id, this
535      one says :void for the return type:</para>
536    <programlisting>
537(define-objc-method ((:void :take-action (:id sender))
538                     data-window-controller)
539    (declare (ignore sender))
540  (dotimes (i 100)
541    (setf (aref (data self) i)
542          (- (aref (data self) i)))))
543    </programlisting>
544    <para>This method would be called "takeAction:" in Objective-C.  The
545      convention for methods that are going to be used as Cocoa
546      actions is that they take one parameter, which is the object
547      responsible for triggering the action.  However, this method
548      doesn't actually need to use that parameter, so it explicitly
549      ignores it to avoid a compiler warning.  As promised, the method
550      doesn't return any value.</para>
551    <para>There is also an alternate syntax, illustrated here.  The
552      following two method definitions are equivalent:</para>
553    <programlisting>
554(define-objc-method ("applicationShouldTerminate:"
555                     "LispApplicationDelegate")
556    (:id sender :&lt;BOOL>)
557         (declare (ignore sender))
558         nil)
560  (define-objc-method ((:&lt;BOOL>
561                        :application-should-terminate sender)
562                       lisp-application-delegate)
563      (declare (ignore sender))
564    nil)
565    </programlisting>
566    <sect2 id="Method-Redefinition-Constraints">
567          <title>Method Redefinition Constraints</title>
568      <para>Objective C was not designed, as Lisp was, with runtime
569        redefinition in mind.  So, there are a few constraints about
570        how and when you can replace the definition of an Objective C
571        method.  Currently, if you break these rules, nothing will
572        collapse, but the behaviour will be confusing; so
573        don't.</para>
574      <para>Objective C methods can be redefined at runtime, but
575        their signatures shouldn't change.  That is, the types of the
576        arguments and the return type have to stay the same.  The
577        reason for this is that changing the signature changes the
578        selector which is used to call the method.</para>
579      <para>When a method has already been defined in one class, and
580        you define it in a subclass, shadowing the original method,
581        they must both have the same type signature.  There is no such
582        constraint, though, if the two classes aren't related and the
583        methods just happen to have the same name.</para>
584    </sect2>
585  </sect1>
587  <sect1 id="How-Objective-C-Names-are-Mapped-to-Lisp-Symbols">
588    <title>How Objective-C Names are Mapped to Lisp Symbols</title>
589    <para>There is a standard set of naming conventions for Cocoa
590      classes, messages, etc.  As long as they are followed, the
591      bridge is fairly good at automaticallly translating between Objective-C
592      and Lisp names.</para>
593    <para>For example, "NSOpenGLView" becomes ns:ns-opengl-view;
594      "NSURLHandleClient" becomes ns:ns-url-handle-client; and
595      "nextEventMatchingMask:untilDate:inMode:dequeue:" becomes
596      (:next-event-matching-mask :until-date :in-mode :dequeue).  What
597      a mouthful.</para>
598    <para>To see how a given Objective-C or Lisp name will be translated by
599      the bridge, you can use the following functions:</para>
600        <simplelist type="vert">
601          <member>(ccl::objc-to-lisp-classname string)</member>
602          <member>(ccl::lisp-to-objc-classname symbol)</member>
603          <member>(ccl::objc-to-lisp-message string)</member>
604          <member>(ccl::lisp-to-objc-message string)</member>
605          <member>(ccl::objc-to-lisp-init string)</member>
606          <member>(ccl::lisp-to-objc-init keyword-list)</member>
607        </simplelist>
609    <para>Of course, there will always be exceptions to any naming
610      convention.  Please tell us on the mailing lists if you come
611      across any name translation problems that seem to be bugs.
612      Otherwise, the bridge provides two ways of dealing with
613      exceptions:</para>
614    <para>First, you can pass a string as the class name of
615      MAKE-OBJC-INSTANCE and as the message to SEND.  These strings
616      will be directly interpreted as Objective-C names, with no
617      translation. This is useful for a one-time exception.  For
618      example:</para>
619    <programlisting>
620(ccl::make-objc-instance "WiErDclass")
621(ccl::send o "WiErDmEsSaGe:WithARG:" x y)
622    </programlisting>
623    <para>Alternatively, you can define a special translation rule
624      for your exception.  This is useful for an exceptional name that
625      you need to use througout your code.  Some examples:</para>
626    <programlisting>
627(ccl::define-classname-translation "WiErDclass" wierd-class)
628(ccl::define-message-translation "WiErDmEsSaGe:WithARG:" (:weird-message :with-arg))
629(ccl::define-init-translation "WiErDiNiT:WITHOPTION:" (:weird-init :option))
630    </programlisting>
631    <para>The normal rule in Objective-C names is that each word begins with a
632      capital letter (except possibly the first).  Using this rule
633      literally, "NSWindow" would be translated as N-S-WINDOW, which
634      seems wrong.  "NS" is a special word in Objective-C that should not be
635      broken at each capital letter. Likewise "URL", "PDF", "OpenGL",
636      etc. Most common special words used in Cocoa are already defined
637      in the bridge, but you can define new ones as follows:</para>
638    <programlisting>
639(ccl::define-special-objc-word "QuickDraw")
640    </programlisting>
641    <para>Note that message keywords in a SEND such as (SEND V
642      :MOUSE P :IN-RECT R) may look like the keyword arguments in a
643      Lisp function call, but they really aren't. All keywords must be
644      present and the order is significant. Neither (:IN-RECT :MOUSE)
645      nor (:MOUSE) translate to "mouse:inRect:"</para>
646    <para>Also, as a special exception, an "init" prefix is optional
647      in the initializer keywords, so (MAKE-OBJC-INSTANCE 'NS-NUMBER
648      :INIT-WITH-FLOAT 2.7) can also be expressed as
650  </sect1>
Note: See TracBrowser for help on using the repository browser.