#7204: Use a class to control FFI marshalling
---------------------------------+------------------------------------------
    Reporter:  simonpj           |       Owner:                  
        Type:  feature request   |      Status:  new             
    Priority:  normal            |   Milestone:                  
   Component:  Compiler          |     Version:  7.4.2           
    Keywords:                    |          Os:  Unknown/Multiple
Architecture:  Unknown/Multiple  |     Failure:  None/Unknown    
  Difficulty:  Unknown           |    Testcase:                  
   Blockedby:                    |    Blocking:                  
     Related:                    |  
---------------------------------+------------------------------------------
 There has been a string of tickets concerning argument/result types for
 `foreign` declarations: #3008, #5529, #5610, #5664.  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 of `Marshal`
  * `(RepType T)` must reduce to one of a fixed family of primitive types,
 `Int`, `Float` and so on.

-- 
Ticket URL: <http://hackage.haskell.org/trac/ghc/ticket/7204>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler

_______________________________________________
Glasgow-haskell-bugs mailing list
Glasgow-haskell-bugs@haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-bugs

Reply via email to