[MLton] Two questions about FFI types

Matthew Fluet fluet@cs.cornell.edu
Tue, 10 May 2005 11:04:28 -0400 (EDT)


> > 1. Some of the mysql functions take a number of C strings (character 
> > pointers), that behave differently if they are null. Unfortunately there 
> > doesn't appear to be a way to give a type to these C functions for 
> > _import; string doesn't work because I can't pass null, and 
> > MLton.Pointer.t doesn't work because I can't pass string. The only two 
> > solutions I have to this are (a) to import the function at multiple types, 
> > and then call the one that matches my dynamic set of nulls--there are then 
> > 2^n imports in general! or (b) write a C stub that takes, for each 
> > argument, a char* and a bool to indicate if it is supposed to "be null". 
> 
> Of these two, obviously (b) is the better solution since it requires
> only one import.

Why should the number of imports matter?  The end user of the mysql 
library won't be affected -- they should be passing string option-s for 
each argument that can either be a C string or NULL.  Granted, it is a bit 
of annoying boilerplate, but I don't see why it makes (b) obviously 
better.

> If you're willing to suffer copying the strings, you could use
> MLton.Pointer.t.  Then, when you want to pass an SML string, you copy
> it to a C string using malloc, pass it, and then free it upon return.
> When you want to pass NULL, use MLton.Pointer.null.  But I like the
> previous solution better.

Another variation on this, would be to statically (on the C side) allocate 
a large enough char array and import its base address.  Then you don't 
need to malloc and free each time.  Of course, you need a separate array 
for each argument.

> Alternatively, you could access the primitive directly from your
> program with
> 
>   val a2v = _prim "Array_toVector": 'a array -> 'a vector;
> 
> To do this, you must compile the file that uses _prim with the
> annotation "allowPrim true", using either the MLB "ann" syntax or
> -default-ann from the command line.

This doesn't quite work, as the opaque signature on CharArray and 
CharVector hide the fact that their types are monomorphic instantiations 
of the polymorphic array and vector type constructors.  Hence, applying 
a2v to a CharArray.array is a type error.  Fortunately, _prim peers right 
through opaque signatures, so you can import the primitive as:

  val a2v = _prim "Array_toVector": CharArray.array -> CharVector.vector;