Use a class to control FFI marshalling
There has been a string of tickets concerning argument/result types for foreign
declarations: #3008 (closed), #5529 (closed), #5610 (closed), #5664 (closed). This ticket suggest a new idea that Simon and I came up with this morning.
The current story is that a newtype
can only be used in an FFI decl if the newtype's data constructor is in scope. This is enshrined in the FFI spec, but it's inconvenient and somewhat controversial. But suppose instead the ability to be passed to a foreign
call was controlled by a class? Thus
class Marshal a where
type RepType a
marshal :: a -> RepType a
unMarshal :: RepType a -> a
instance Marshal Int where
type RepType Int = Int
marshal = id
unMarshal = id
newtype Age a = MkAge a
instance Marshal a => Marshal (Age a) where
type RepType (Age a) = RepType a
marshal (Age x) = marshal x
unMarshal x = Age x
An author can control whether a newtype is marshalable by making it an instance of Marshal
(or not). Moreover newtype deriving
will work just fine on class Marshal
so you can write
newtype Age a = MkAge a deriving( Marshal )
The FFI stub generation machinery would do the following. Given a declaration
foreign import foo :: T -> IO S
it will generate a Haskell foo
thus:
foo :: T -> S
foo t = case (marshal t) of
I# x# -> case "ccall foo x#" of
r# -> unMarshal (F# r#)
(I'm being a bit sloppy about the IO part, becuase it's not part of the main point here.)
In this example I've assumed that (after some type-level reductions)
RepType T = Int
RepType S = Float
but it should be OK provided the RepType T
reduces to one of a fixed set of primitive types that GHC knows how to marshal.
So the rules become that an argument type T
must satisfy two conditions:
-
T
must be an instance ofMarshal
-
(RepType T)
must reduce to one of a fixed family of primitive types,Int
,Float
and so on.
Trac metadata
Trac field | Value |
---|---|
Version | 7.4.2 |
Type | FeatureRequest |
TypeOfFailure | OtherFailure |
Priority | normal |
Resolution | Unresolved |
Component | Compiler |
Test case | |
Differential revisions | |
BlockedBy | |
Related | |
Blocking | |
CC | |
Operating system | |
Architecture |