Greetings to the List!
Having learned ML and several other functional languages in a
programming class, I decided that it would be nice to be able to
program in a functional language on my Mac. I chose caml for various
reasons, partly because of the clean foreign-function interface. To
make the language useful for more than command-line apps, I'm writing a
bridge between caml and Objective-C (specifically, Cocoa).
I have little experience in caml itself, and so have no intuition about
idiomatic programming, especially with objects (most of my functional
experience is in ML). What I want to know is, what would be a clean
and idiomatic interface to this bridge on the caml side?
Things that I've been considering in the design:
-- Except by parsing the objective-c header files, you can't know what
types a function takes and returns, and in particular it may return
null. This is especially the case in objective-c because types and
bindings are dynamic. As a result, you can't know much about a method
when calling it from caml other than the number of arguments it takes,
or even if the object answers it. (if it doesn't, this should throw an
exception).
-- You can send messages to nil in objc, and it will return nil.
-- Objective-C uses 32-bit integers, but most methods that use them
accept and return small numbers. The current model is to use ints, but
throw an exception if it overflows... I'll probably add an int32 type
to the interface as well for those times when this is unacceptable.
-- Common things that would have to go across the interface quite often
would be NSArray <=> list and NSString <=> string. These may be
important enough to warrant special handling.
-- Memory management can be messy.
I've written the core of the bridge, at least in the caml->objc
direction, and it works on a hello world program. The model is to look
up classes and selectors (essentially methods) by name, and then to
pass messages to a class or to an object.
It consists of some datatypes and foreign functions in a module:
> module ObjCGlue = struct
> type objcid
> type objcclass
> type objcsel
>
> type cobj = NULL
> | BOOL of bool
> | INT of int
> | CHAR of char
> | STR of string
> | FLOAT of float
> | ID of objcid
> | SEL of objcsel
> | CLASS of objcclass
>
> (* starts up the runtime system, allocates an autoreleasepool *)
> external _start : unit -> unit = "camlGlueStartup"
>
> (* returns a selector of the given name. remember those colons! *)
> external _selNamed : string -> objcsel = "camlGlueStrToSel"
>
> (* returns a class of the given name, or null if none exists.
> perhaps should throw an exception instead *)
> external _classNamed : string -> cobj = "camlGlueStrToClass"
>
> (* sends a message to an object *)
> external _message : objcid -> objcsel -> cobj list -> cobj
> = "camlGlueMessageSend"
>
> (* invokes a class method *)
> external _classMethod : objcclass -> objcsel -> cobj list -> cobj
> = "camlGlueClassMethod"
>
> (* ... lots convenience functions to make testing easier ... *)
> end;;
Any suggestions would be much appreciated.
Thanks a lot for your time,
Mike Hamburg