lightweight struct handling in FFI?

Simon Marlow simonmar at microsoft.com
Thu Sep 19 07:08:48 EDT 2002


> From: Antony Courtney [mailto:antony at apocalypse.org] 
> 
> While the FFI spec. is excellent, I'd really like to see a companion 
> document with real examples of how to use the FFI for the 
> easy, obvious 
> kinds of library interfacing tasks that are likely to arise 
> in practice.

There are quite a few examples in fptools/libraries in the CVS
repository.  These libraries all use the FFI: IO, Time, Directory,
CPUTime, Network.Socket, Text.Regex.Posix, and the new System.Posix
stuff.

I agree, it would be nice to have some introductory material on
programming the FFI "for real", though.

> Such examples would hopefully help answer things like the following 
> rather naieve question that I have:
> 
> Is there a particular "best" way to deal with C functions that take 
> "lightweight" struct values (or pointers to such structs), 

To answer your question, there are several choices, each with its own
advantages and disadvantages.  You'll find examples of these in the
libraries I mentioned above.  I'm assuming that you want to use the FFI
directly (possibly with help from c2hs or hsc2hs), rather than use one
of the higher level tools.

1. Fully marshal the structure to/from Haskell.

The best way to do this is to write a Haskell datatype for the
structure, and define a Storable instance for it.  You can use a tool to
help you write the Storable instance in a portable way: hsc2hs and c2hs
are good for this.

Full marshalling is likely to be a good choice when you want to do lots
of manipulation of the structure on the Haskell side.

2. Keep the structure in its C representation, and manipulate the
structure using peek/poke in Haskell.

This is a good choice if manipulation on the Haskell side is limited,
for example if a single field is required to be extracted, and you don't
want to marshal the entire struct into Haskell.  Also, sometimes the
representation is partially abstract on the C side (many C structs in
POSIX for example are only partially specified by the standard), so
fully marshalling it is not an option.

If the lifetime of the struct is well-known and scoped (such as across a
single call to a foreign function), then the MarshalAlloc.alloca family
of functions can be used to allocate it.  Again, to portably peek/poke
individual fields, you'll probably find that hsc2hs or c2hs are useful.

If the lifetime of the structure does not work well with alloca, or you
want it to be garbage collected, then use a ForeignPtr instead.  The new
functions mallocForeignPtr and mallocForeignPtrBytes provide for this
kind of allocation, and will perform better in GHC than using explicit
malloc/free.

Hope this helps,

	Simon



More information about the FFI mailing list