Newtype unwrapping in the FFI

2009-02-12 Thread Simon Peyton-Jones
[This email concerns an infelicity in the FFI spec. I'm directing it primarily 
to the Haskell Prime mailing list, but ccing the libraries list so that people 
there know about the thread. I suggest that replies go to Haskell Prime only.]

Consider this program (see http://hackage.haskell.org/trac/ghc/ticket/3008)

  module NT( N ) where
 newtype N = MkN Int

  module FFI where
 foreign import f :: N - IO ()

Is module FFI OK?  It would definitely be OK if N was defined in the module 
FFI: the FFI spec says that the compiler must automatically unwrap any newtype 
arguments.
http://www.cse.unsw.edu.au/~chak/haskell/ffi/ffi/ffise3.html#x6-120003.2

But it's less clear when N is defined in another module *and* its 
representation isn't exported.  The author of NT might believe that because N's 
representation is hidden, she can change it to, say
data N = MkN Int
without affecting the rest of the world.  But she can't.  This is a nasty 
failure of abstraction.  It is, I believe the only way in which a client of a 
NT could be affected by N's representation, even though that representation is 
allegedly hidden.  (ToDo: check on generalised newtype deriving.) This seems 
Bad to me.

Indeed, the cause of the above bug report is that GHC's implementation assumes 
that the representation is fully hidden if the constructor is not exported, and 
does not expose the representation of N even to separately-compiled modules (at 
least when you are not using -O).

But the point here is not what GHC stumbles on but what is supposed to happen.

Maybe we should fix it.  Proposal:

  * Clarify the spec to say that a newtype can only be automatically
unwrapped if the newtype constructor (MkN in this case) is in scope

It happens that a large set of types from Foreign.C.Types, such as CInt and 
friends, are exported without their constructors, so adopting this new rule 
would require us to change Foreign.C.Types to expose the representation of CInt 
and friends.  (As it happens, nhc requires this already, so there's some 
#ifdeffery there already.)

Simon
___
Haskell-prime mailing list
Haskell-prime@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-prime


RE: Newtype unwrapping in the FFI

2009-02-12 Thread Simon Peyton-Jones
|* Clarify the spec to say that a newtype can only be automatically
|  unwrapped if the newtype constructor (MkN in this case) is in
|  scope
|
| I agree up to here. For user-defined types, not exporting the
| constructor should be a guarantee of abstraction.
|
|  It happens that a large set of types from Foreign.C.Types, such as
|  CInt and friends, are exported without their constructors, so adopting
|  this new rule would require us to change Foreign.C.Types to expose the
|  representation of CInt and friends.  (As it happens, nhc requires this
|  already, so there's some #ifdeffery there already.)
|
| The thing about CInt though is that it is supposed to be abstract *and*
| an FFI type. I want to think of it as a primitive FFI type (though it is
| not a basic type as defined by the FFI). We don't want to know that on
| some system it is Int32 and on others it is Int64. We do not want access
| to the constructor here.

Trouble is, there are a zillion types in Foreign.C.Types, and another zillion 
in Foreign.Posix.Types. Do you want to list them all as blessed in the FFI 
addendum?

S
___
Haskell-prime mailing list
Haskell-prime@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-prime


Re: Newtype unwrapping in the FFI

2009-02-12 Thread Manuel M T Chakravarty

Simon Peyton-Jones:
|* Clarify the spec to say that a newtype can only be  
automatically

|  unwrapped if the newtype constructor (MkN in this case) is in
|  scope
|
| I agree up to here. For user-defined types, not exporting the
| constructor should be a guarantee of abstraction.


I also don't really see an alternative.  The ability to pass a type to  
a foreign function tells us something about the type; there is not  
much we can do about that.



|  It happens that a large set of types from Foreign.C.Types, such as
|  CInt and friends, are exported without their constructors, so  
adopting
|  this new rule would require us to change Foreign.C.Types to  
expose the
|  representation of CInt and friends.  (As it happens, nhc  
requires this

|  already, so there's some #ifdeffery there already.)
|
| The thing about CInt though is that it is supposed to be abstract  
*and*
| an FFI type. I want to think of it as a primitive FFI type (though  
it is
| not a basic type as defined by the FFI). We don't want to know  
that on
| some system it is Int32 and on others it is Int64. We do not want  
access

| to the constructor here.

Trouble is, there are a zillion types in Foreign.C.Types, and  
another zillion in Foreign.Posix.Types. Do you want to list them all  
as blessed in the FFI addendum?


The types in Foreign.C.Types are already listed in the FFI addendum  
(it actually specifies the whole module, just like the report  
specifies what is in the Prelude).


However, I think an argument can be made that hiding the  
implementation of the types in C.Foreign.Types is a Bad Thing.  FFI  
code is inherently architecture dependent due to the varying sizes and  
representations of C types.  Hiding that variation behind a newtype  
serves only to obscure that dependency, it certainly doesn't resolve  
it.  I know that Section 6.2 of the FFI addendum requires these  
exports to be abstract, but I now tend to think that this was a mistake.


Manuel

___
Haskell-prime mailing list
Haskell-prime@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-prime