source: tags/pre_1_0_pre_hash_modifications/ccl/examples/CocoaBridgeDoc.txt @ 2475

Last change on this file since 2475 was 2475, checked in by anonymous, 14 years ago

This commit was manufactured by cvs2svn to create tag
'pre_1_0_pre_hash_modifications'.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.8 KB
Line 
1A Cocoa Bridge for OpenMCL
2
3Randall D. Beer
4beer@eecs.cwru.edu
5http://vorlon.cwru.edu/~beer
6
7
8INTRODUCTION
9
10The purpose of CocoaBridge is to make Cocoa as easy as possible to use
11from OpenMCL, in order to support GUI application and development
12environment activities.  It builds on the capabilities provided in the
13APPLE-OBJC example.  The eventual goal is complete integration of
14Cocoa into CLOS.  The current release provides Lisp-like syntax and
15naming conventions for ObjC object creation and message sending, with
16automatic type processing and compile-time checking of message
17sends. It also provides some convenience facilities for working with
18Cocoa.
19
20A small sample Cocoa program can be invoked by evaluating (REQUIRE
21'TINY) and then (CCL::TINY-SETUP). This program provides a simple example
22of using several of the bridge's capabilities
23
24
25BASICS
26
27The main things you need to know are:
28
291) You create and initialize ObjC objects using
30MAKE-OBJC-INSTANCE. This should be replaced by MAKE-INSTANCE as CLOS
31integration improves
32
33Example:
34[[NSNumber alloc] initWithFloat: 2.7] in ObjC becomes
35(MAKE-OBJC-INSTANCE 'NS-NUMBER :INIT-WITH-FLOAT 2.7) in Lisp
36
37Note that class names and init keywords are translated from ObjC to Lisp in
38pretty much the obvious way
39
402) You send messages to ObjC objects using SEND
41
42Examples:
43[w alphaValue] becomes (SEND W 'ALPHA-VALUE)
44[w setAlphaValue: 0.5] becomes (SEND W :SET-ALPHA-VALUE 0.5)
45[v mouse: p inRect: r] becomes (SEND V :MOUSE P :IN-RECT R)
46
47Note that message keywords are translated to Lisp in pretty much the obvious
48way.  From within a method, you can also use SEND-SUPER.
49
50
513) The @CLASS macro from APPLE-OBJC is currently used to refer to named ObjC
52classes, which can also be sent messages via SEND. This should be replaced by
53FIND-CLASS as CLOS integration improves.
54
55Example:
56[NSColor whiteColor] becomes (SEND (@CLASS NS-COLOR) 'WHITE-COLOR)
57
58
594) New ObjC classes and methods are currently defined using DEF-OBJC-CLASS and
60DEFINE-OBJC-METHOD from APPLE-OBJC.  This should be replaced by DEFCLASS and
61DEFMETHOD as CLOS integration improves.
62
63
64NAME TRANSLATION
65
66There are a standard set of naming conventions for Cocoa classes,
67 messages, etc.  As long as these are followed, the bridge is fairly
68 good at automaticallly translating between ObjC and Lisp names.
69
70Examples:
71"NSURLHandleClient" <==> NS-URL-HANDLE-CLIENT
72"NSOpenGLView" <==> NS-OPENGL-VIEW
73"nextEventMatchingMask:untilDate:inMode:dequeue:" <==>
74(:NEXT-EVENT-MATCHING-MASK :UNTIL-DATE :IN-MODE :DEQUEUE)
75
76To see how a given ObjC or Lisp name will be translated by the bridge, you can
77use the following functions:
78
79OBJC-TO-LISP-CLASSNAME string
80LISP-TO-OBJC-CLASSNAME symbol
81OBJC-TO-LISP-MESSAGE string
82LISP-TO-OBJC-MESSAGE keyword-list
83OBJC-TO-LISP-INIT string
84LISP-TO-OBJC-INIT keyword-list
85
86Of course, there will always be exceptions to any naming convention.
87Please let me know if you come across any name translation problems
88that seem to be bugs.  Otherwise, the bridge provides two ways of
89dealing with exceptions:
90
911) You can pass a string as the class name of MAKE-OBJC-INSTANCE and
92as the message to SEND.  These strings will be directly interpreted as
93ObjC names, with no translation. This is useful for a one-time
94exception.
95
96Examples:
97(MAKE-OBJC-INSTANCE "WiErDclass")
98(SEND o "WiErDmEsSaGe:WithARG:" x y)
99
1002) You can define a special translation rule for your exception. This is useful
101for an exceptional name that you need to use throughout your code.
102
103Examples:
104(DEFINE-CLASSNAME-TRANSLATION "WiErDclass" WEIRD-CLASS)
105(DEFINE-MESSAGE-TRANSLATION "WiErDmEsSaGe:WithARG:" (:WEIRD-MESSAGE :WITH-ARG))
106(DEFINE-INIT-TRANSLATION "WiErDiNiT:WITHOPTION:" (:WEIRD-INIT :OPTION)
107
108The normal rule in ObjC names is that each word begins with a capital letter
109(except possibly the first).  Using this rule literally, "NSWindow" would be
110translated as N-S-WINDOW, which seems wrong.  "NS" is a special word in ObjC
111that should not be broken at each capital letter. Likewise "URL", "PDF",
112"OpenGL", etc. Most common special words used in Cocoa are already defined in
113the bridge, but you can define new ones as follows: (DEFINE-SPECIAL-OBJC-WORD
114"QuickDraw")
115
116Note that message keywords in a SEND such as (SEND V :MOUSE P :IN-RECT R) may
117look like Lisp keyword args, but they really aren't. All keywords must be
118present and the order is significant. Neither (:IN-RECT :MOUSE) nor (:MOUSE)
119translate to "mouse:inRect:"
120
121Note that an "init" prefix is optional in the initializer keywords, so
122(MAKE-OBJC-INSTANCE 'NS-NUMBER :INIT-WITH-FLOAT 2.7) can also be expressed as
123(MAKE-OBJC-INSTANCE 'NS-NUMBER :WITH-FLOAT 2.7)
124
125
126STRETS
127
128Some Cocoa methods return small structures (such as those used to represent
129points, rects, sizes and ranges). Although this is normally hidden by the ObjC
130compiler, such messages are sent in a special way, with the storage for the
131STructure RETurn (STRET) passed as an extra argument. This STRET and special
132SEND must normally be made explicit in Lisp.  Thus
133
134NSRect r = [v1 bounds];
135[v2 setBounds r];
136
137in ObjC becomes
138
139(RLET ((R :<NSR>ect))
140  (SEND/STRET R V1 'BOUNDS)
141  (SEND V2 :SET-BOUNDS R))
142 
143In order to make STRETs easier to use, the bridge provides two conveniences:
144
1451) The SLET and SLET* macros may be used to define local variables that are
146initialized to STRETs using a normal SEND syntax. Thus, the following is
147equivalent to the above RLET:
148
149(SLET ((R (SEND V 'BOUNDS)))
150 (SEND V2 :SET-BOUNDS R))
151 
1522) The arguments to a SEND are evaluated inside an implicit SLET, so instead of
153the above, one could in fact just write:
154
155(SEND V1 :SET-BOUNDS (SEND V2 'BOUNDS))
156
157There are also several psuedo-functions provided for convenience by the ObjC
158compiler. The following are currently supported by the bridge: NS-MAKE-POINT,
159NS-MAKE-RANGE, NS-MAKE-RECT, and NS-MAKE-SIZE. These can be used within a SLET
160initform or within a message send:
161
162(SLET ((P (NS-MAKE-POINT 100.0 200.0)))
163  (SEND W :SET-FRAME-ORIGIN P))
164 
165or
166 
167(SEND W :SET-ORIGIN (NS-MAKE-POINT 100.0 200.0))
168
169However, since these aren't real functions, a call like the following won't
170work:
171
172(SETQ P (NS-MAKE-POINT 100.0 200.0))
173
174The following convenience macros are also provided: NS-MAX-RANGE, NS-MIN-X,
175NS-MIN-Y, NS-MAX-X, NS-MAX-Y, NS-MID-X, NS-MID-Y, NS-HEIGHT, and NS-WIDTH.
176
177Note that there is also a SEND-SUPER/STRET for use within methods.
178
179
180OPTIMIZATION
181
182The bridge works fairly hard to optimize message sends under two conditions. In
183both of these cases, a message send should be nearly as efficient as in ObjC:
184
1851) When both the message and the receiver's class are known at compile-time. In
186general, the only way the receiver's class is known is if you declare it, which
187you can do either via a DECLARE or THE form.  For example:
188
189(SEND (THE NS-WINDOW W) 'CENTER)
190
191Note that there is no way in ObjC to name the class of a class.  Thus
192the bridge provides a @METACLASS declaration. The type of an instance
193of "NSColor" is NS-COLOR.  The type of the *class* "NSColor" is
194(@METACLASS NS-COLOR):
195
196(LET ((C (@CLASS NS-COLOR)))
197  (DECLARE ((@METACLASS NS-COLOR) C))
198  (SEND C 'WHITE-COLOR))
199 
2002) When only the message is known at compile-time, but its type
201signature is unique. Of the over 6000 messages currently provided by
202Cocoa, only about 50 of them have nonunique type signatures.  An
203example of a message whose type signature is not unique is SET.  It
204returns VOID for NSColor, but ID for NSSet.  In order to optimize
205sends of messages with nonunique type signatures, the class of the
206receiver must be declared at compile-time.
207
208If the type signature is nonunique or the message is unknown at compile-time,
209then a slower runtime call must be used.
210
211The ability of the bridge to optimize most constant message sends even
212when the receiver's class is unknown crucially depends on a type
213signature table that the bridge maintains.  When the bridge is first
214loaded, it initializes this table by scanning all methods of all ObjC
215classes defined in the environment.  If new methods are later defined,
216this table must be updated. After a major change (such as loading a
217new framework with many classes), you should evaluate
218(UPDATE-TYPE-SIGNATURES) to rebuild the type signature table.
219
220Because SEND, SEND-SUPER, SEND/STRET and SEND-SUPER/STRET are macros,
221they cannot be FUNCALLed, APPLYed or passed as functional arguments.
222The functions %SEND and %SEND/STRET are provided for this
223purpose. There are also %SEND-SUPER and %SEND-SUPER/STRET functions
224for use within methods. However, these functions should be used only
225when necessary since they perform general (nonoptimized) message
226sends.
227
228
229VARIABLE ARITY MESSAGES
230
231There are a few messages in Cocoa that take variable numbers of arguments. 
232Perhaps the most common examples involve formatted strings:
233
234[NSClass stringWithFormat: "%f %f" x y]
235
236In the bridge, this would be written as follows:
237
238(SEND (@CLASS NS-STRING)
239      :STRING-WITH-FORMAT #@"%f %f"
240      (:DOUBLE-FLOAT X :DOUBLE-FLOAT Y))
241
242Note that the types of the variable arguments must be given, since the compiler
243has no way of knowing these types in general.
244
245Variable arity messages can also be sent with the %SEND function:
246
247(%SEND (@CLASS NS-STRING)
248       :STRING-WITH-FORMAT #@"%f %f"
249       (LIST :DOUBLE-FLOAT X :DOUBLE-FLOAT Y))
250
251Because the ObjC runtime system does not provide any information on
252which messages are variable arity, they must be explicitly defined.
253The standard variable arity messages in Cocoa are predefined.  If you
254need to define a new variable arity message, use
255(DEFINE-VARIABLE-ARITY-MESSAGE "myVariableArityMessage:")
256
257
258TYPE COERCION
259
260OpenMCL's FFI handles many common conversions between Lisp and foreign data,
261such as unboxing floating-point args and boxing floating-point results.  The
262bridge adds a few more automatic conversions:
263
2641) NIL is equivalent to (%NULL-PTR) for any message argument that requires a
265pointer
266
2672) T/NIL are equivalent to #$YES/#$NO for any boolean argument
268
2693) A #$YES/#$NO returned by any method that returns BOOL will be automatically
270converted to T/NIL
271
272To make this last conversion work, the bridge has to engage in a bit
273of hackery.  The bridge uses ObjC run-time type info.  Unfortunately,
274BOOL is typed as CHAR by ObjC.  Thus, a method that returns CHAR might
275actually return only BOOL, or it might return any CHAR.  The bridge
276currently assumes that any method that returns CHAR actually returns
277BOOL.  But it provides a facility for defining exceptions to this
278assumption: (DEFINE-RETURNS-BOOLEAN-EXCEPTION "charValue").
279Eventually, the best way to handle issues like this is probably to get
280our method type info directly from the header files rather than using
281ObjC's runtime type system.
282
283Note that no automatic conversion is currently performed between Lisp
284strings and NSStrings.  However, APPLE-OBJ provides a convenient
285syntax for creating constant NSStrings: (SEND W :SET-TITLE #@"My
286Window"), as well as facilities for converting between Lisp strings
287and NSStrings.  Note that #@"Hello" is a full ObjC object, so messages
288can be sent to it: (SEND #@"Hello" 'LENGTH)
289
Note: See TracBrowser for help on using the repository browser.