Skip to content

GitLab

  • Menu
Projects Groups Snippets
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
  • Sign in / Register
  • GHC GHC
  • Project information
    • Project information
    • Activity
    • Labels
    • Members
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributors
    • Graph
    • Compare
    • Locked Files
  • Issues 4,869
    • Issues 4,869
    • List
    • Boards
    • Service Desk
    • Milestones
    • Iterations
  • Merge requests 456
    • Merge requests 456
  • CI/CD
    • CI/CD
    • Pipelines
    • Jobs
    • Schedules
    • Test Cases
  • Deployments
    • Deployments
    • Releases
  • Analytics
    • Analytics
    • Value stream
    • CI/CD
    • Code review
    • Insights
    • Issue
    • Repository
  • Wiki
    • Wiki
  • Snippets
    • Snippets
  • Activity
  • Graph
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
Collapse sidebar
  • Glasgow Haskell Compiler
  • GHCGHC
  • Issues
  • #7204
Closed
Open
Created Aug 31, 2012 by Simon Peyton Jones@simonpjDeveloper

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 of Marshal
  • (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
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information
Assignee
Assign to
Time tracking