Closed mboes closed 7 years ago
The general rule in every marshalling operation is that no conversion (even no ops) are performed. For example Double
s must be converted to CDouble
s, etc.
This seems an instance of the same debate, but maybe we did not have coerce
at the time. I think that if we decide that we do want to use coerce
, then we probably want to use it everywhere.
I'm not sure if that'll end up being too confusing for the user though.
Independently of any philosophical debate about the merits of datatype conversions, there is a very practical issue here, which is that ForeignPtr
is nearly always wrapped, yet it's difficult to write a custom marshaller specifically for said wrapper. It would have to go something like this:
fooPtrAntiQuoter :: AntiQuoter HaskellIdentifier
fooPtrAntiQuoter = AntiQuoter
{ aqParser = cDeclAqParser
, aqMarshaller = \purity cTypes cTy cId -> do
hsTy <- convertType_ "fooCtx" purity cTypes cTy
hsExp <- getHsVariable "fooCtx" cId
hsExp' <- [| \cont -> withForeignPtr (unFoo $(return hsExp)) cont |]
return (hsTy, hsExp')
}
But, cDeclAqParser
isn't exported, and getHsVariable
and convertType_
aren't either. And their implementation pulls in a bunch of other functions so copying their code creates a bit of a mess.
A CInt
doesn't necessarily have the same representation as an Int
, so shying away from having to deal with lossyness in the translation or indeed its cost, is perfectly fair. CChar
in fact never has the same range as Char
. But the cases that Data.Coerce
can handle are special: there is no conversion (no representation change, no copying, in fact it doesn't even exist at runtime).
So I see three possible choices (not mutually exclusive):
Language.C.Inline.Context
, and demand that the user write herself a whole new antiquoter if she wants to deal unwrapping to done for her. The antiquoter isn't very complicated in this case.fptrPtrAntiQuoterWith :: (a -> ForeignPtr b) -> Antiquoter
.fptrCtx
to handle arbitrary coercible things. Note that everywhere else, newtype wrappers are already not a problem, because foreign import
can handle newtype wrappers for pointers and C types just fine. So the current PR just makes what is currently possible elsewhere also possible for pointers: https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/ffi-chap.html#newtype-wrapping-of-the-io-monadAh, I see the difference now: you most often can't convert from the wrapped ForeignPtr
to a ForeignPtr
. I missed this detail at the beginning. Is that so? In that case the "practicality" argument is much more compelling
right.
Foreign pointers are seldom naked. They very often are wrapped in some newtype. We use
coerce
to pierce through the wrapper.One could in theory define a custom marshaller in that case, but it's not easy to define a new one by reusing parts of the existing marshaller.