ANN: H98 FFI Addendum 1.0, Release Candidate 7

Manuel M T Chakravarty chak@cse.unsw.edu.au
Tue, 24 Sep 2002 12:01:41 +1000 (EST)


Ross Paterson <ross@soi.city.ac.uk> wrote,

> On Sun, Sep 22, 2002 at 02:49:36PM +1000, Manuel M T Chakravarty wrote:
> > Ross Paterson <ross@soi.city.ac.uk> wrote,
> > Another problem is that I don't think you would really gain
> > anything.  runST is safe as given the available ST functions
> > and the type constraints on runST guarantee that everything
> > is fine.  Now with an imported C function you will never
> > have any static guarantee beyond your believe of what the C
> > routine does.  In particular, you would even break the
> > safety guarantees that currently exist for the ST monad, as
> > you could now implement "bad" ST functions.  (A similar
> > argument can be even made for the marshalling support
> > functions, as it is impossible to make static guarantees
> > about the safeness of the peek and poke functions.)
> 
> Sure, a program using the ffi could break anything if the appropriate
> properties don't hold.  All the more reason to be clear about what the
> obligations are.
> 
> The aim is not to prohibit dishonesty, but rather to enable honesty.
> The situation is analogous to foreign functions with pure return types,
> which removes many instances of unsafePerformIO.  By writing
> 
> 	foreign import ccall "math.h sin" c_sin :: CDouble -> CDouble
> 
> one asserts that this function is pure.  By writing
> 
> 	foreign import ccall getparts :: CString -> STPtr s Record -> ST s ()
> 
> one would be asserting that this function had no side-effects except for
> modifying the record it was given a pointer to.  There would be similar
> obligations on people implementing allocators and instances of
> 
> 	class Storable a where
> 		...
> 		peekSTPtr :: STPtr s a -> ST s a
> 		pokeSTPtr :: STPtr s a -> a -> ST s ()
> 
> Put them all together and you have a piece of code that has no effects
> outside of the memory region s, and is safe for runST, provided
> each primitive conforms to its obligations.  The point is that those
> obligations are clearly defined.  Not formally defined, but that's not
> what the FFI spec is about.

I agree that it makes sense to specify the obligations to
FFI primitives.  However, for functions like `peekByteOff'
it is rather difficult to even informally state these
obligations, as it is, for example, unclear how to define
the "boundaries" of raw memory objects; this becomes only
worse when these objects weren't allocated by Haskell FFI
functions. 

Even defining that a C functions need to be "pure" is not
that strong a statement.  sin() may have side effects in
building tables to cache same intermediate results in the
hope to speed up later computations.  All we can ask for is
that sin() is referentially transparent.  Similarly, we can
demand that any expression "unsafePerformIO e" must produce
the same result when evaluated multiple times.

Nevertheless, any additions to the FFI spec that more
precisely identify what use of the FFI primitives is
acceptable would surely be a good thing.

Manuel