Changes between Version 7 and Version 8 of ObjectiveC/Classes

Jan 13, 2009 2:11:04 PM (7 years ago)



  • ObjectiveC/Classes

    v7 v8  
    33= Haskell Objective-C FFI: Objective-C Classes =
    5 == Using classes ==
    7 We might import ObjC classes like so:
    8 {{{
    9 foreign import objc "@class UIView" o'UIView :: Class
    10 }}}
    11 '''Problem:''' We also need to introduce the class type `C'UIView`. So far, the FFI has no support for the import of types.  Maybe we need a `foreign type` declaration.
    135== Declaring classes ==
    15 One option might be something like
     7Importing an ObjC class has two components: (1) we declare the class type, i.e., the Haskell type of objects of that class, and (2) we import the class object; i.e., the object on which we invoke class methods.
    17 foreign export "@class MyUIView : UIView" myUIView :: C'UIView
     9foreign class objc "UIKit/UIKit.h UIView" C'UIView            -- declares the class type
     10foreign import objc "UIKit/UIKit.h UIView" o'UIView :: Class  -- imports the class object
     12The class type is implemented as a newtype of a `ForeignPtr`.  The type is abstract, but can be passed to and received from ObjC land; i.e., it is a ''foreign type'' in the sense of Section 3.2 of the Haskell FFI.  The class object is looked up by the module initialisation code using `objc_lookUpClass` and `Class` is defined in `Foreign.ObjectiveC` and corresponds to the type `Class` of the ObjC runtime.
     14=== Finaliser ===
     16A `foreign class` declaration can optionally specify a finaliser for the objects of the declared class.  By default, the finaliser sends a `release` message to the finalised object.  If a custom finaliser is specified, it needs to be implemented in ObjC (as per the requirements of `Foreign.ForeignPtr`).
     18== Implementing ObjC classes in Haskell ==
     20Any ObjC class implemented in Haskell requires an `@interface` definition in a standard ObjC header file.  Instead, of a `.m` file that contains the implementation, we provide the implementation in Haskell.  In Haskell, we specify in the `foreign class` declaration that the curent Haskell module implements the class; thusly,
     22foreign class objc "MyClass.h @implementation MyClass" MyClass
     24For any Haskell module that implements one or more class, we generate an ObjC stub file (not unlike the C stubs generated by GHC for foreign export wrappers in the C FFI).  The stub file contains the actual class implementation.
     26=== Class and instance methods ===
     28For any class or instance method of a class implemented in Haskell, we have one `foreign export` statement; for example,
     30foreign export objc "-[MyClass doSomethingCool:]" doSomethingCool :: MyClass -> UIView -> IO BOOL
    20 === Option 1: value definition ===
     33['''FIXME:''' ''Need to make sure that we can determine the ObjC signature from the Haskell signature in every case.'']
    22 The class definition value `myUIView` contains the details of the class definition.  However, it is odd, because `C'UIView` should usually be the type of instances if of `UIView`.
     35=== Ivars and properties ===
    24 === Option 2: incremental definition ===
     37Any ivars and properties of a class need to be defined in the header with the interface.  We can import or export setters and getters of properties as any other selector.  However, if the class is implemented in Haskell, we might want to have the ObjC compiler synthesize the setter and getter.  We can achieve this via a `@synthesize` directive in the `foreign import` of the setter and getter.
     39foreign import objc "@synthesize myProperty -[MyClass myProperty]" myProperty
     40  :: MyClass -> IO CInt
     41foreign import objc "@synthesize myProperty -[MyClass setMyProperty:]" setMyProperty
     42  :: MyClass -> CInt -> IO ()
     44The synthesize directive includes the property name, as the property declaration may have specified non-default names for the setter and getter.  Moreover, the directive should be duplicated by specifying it in the setter and getter (except for a `readonly` property) – this is much like header file specifications are replicated across foreign declarations in the C FFI.
    26 In addition to the `foreign export` declaring the class, the class is populated with methods in further `foreign export` declarations.
    28 We have the following problems:
    29  * The ObjC runtime uses two functions to initiate and finalise the declaration of a new class, namely `objc_allocateClassPair` and `objc_registerClassPair`.  All ivars must be added between these two calls (except for the 64-bit runtime, I guess, but the runtime ref doesn't say that).  Methods and protocols can still be added after registering.
    30  * `objc_allocateClassPair` expects the superclass as a value of type `Class`.  The documentation does not say whether the superclass must already be registered (or whether it is sufficient to have it allocated at that point).
    31 Problems arise because Haskell declarations are unordered, so we should make no assumption about the order of foreign declarations.  Moreover, we need to have foreign imported all class that we subclass (and which are not locally defined) – or we just call `objc_getClass`.  On the other hand, when you subclass an existing class, you almost certainly need to foreign import the superclass anyway, to implement the methods for the new class (so an implicit `objc_getClass` is probably not worth the effort).
    33 What about ObjC classes that have been declared in other Haskell modules, do we have to foreign import them again or do we just import the Haskell representation?
    35 We may have to compute the class DAG and make sure we generate class initialisation code that at module load time allocates, registers, and subclasses all Objective-C classes in the right order.
    37 == BIG Questions ==
    39 === How do we represent ObjC classes in Haskell land? ===
    41 It could just be a pointer.  The advantage of a pointer is that there is no issue of keeping ObjC land and Haskell land data in sync (BIG PLUS).  However, what does it mean to export a class in that case?  In fact, we would need to allocate, populate, and register the class in ObjC land and then '''import''' it into Haskell land.  This clashes with that the Haskell identifier mentioned in a `foreign export` is at a usage, not a defining occurrence.
    43 === How do we populate ObjC classes with ivars, methods & properties in Haskell land? ===
     46We provide no special support to access the ivars directly beyond the functionality already available in the C FFI for Haskell.