Dear foreigners Simon and I noticed this morning that ForeignObj should really be parameterised. The current type of newForeignObj is newForeignObj :: Ptr a -> IO () -> IO ForeignObj This immediately loses the type information on the Ptr! Shouldn't it be newForeignObj :: Ptr a -> IO () -> IO (ForeignObj a) Or maybe we should shorten it to (FPtr a)? ("F" for "finalised".) Similarly withFPtr :: FPtr a -> (Ptr a -> IO b) -> IO b It's bizarre to have withForeignObj :: ForeignObj -> (Ptr a -> IO b) -> IO b What think you? Simon
Simon and I noticed this morning that ForeignObj should really be parameterised. The current type of newForeignObj is newForeignObj :: Ptr a -> IO () -> IO ForeignObj This immediately loses the type information on the Ptr! Shouldn't it be newForeignObj :: Ptr a -> IO () -> IO (ForeignObj a)
I agree that once we adopt (Ptr a) in preference to Addr, ForeignObj may in some cases probably also be better parameterised as well. But *please* choose a different name (like we did with Ptr/Addr) for backward compatibility.
Or maybe we should shorten it to (FPtr a)? ("F" for "finalised".)
I dislike cryptic abbreviations on principle. "Ptr" is clear, "FPtr" is not. How about "FinalisedPtr" (only 2 chars longer than "ForeignObj")? Or indeed, "ForeignPtr", which is the same length? Regards, Malcolm
malcolm-ffi@cs.york.ac.uk wrote,
Simon and I noticed this morning that ForeignObj should really be parameterised. The current type of newForeignObj is newForeignObj :: Ptr a -> IO () -> IO ForeignObj This immediately loses the type information on the Ptr! Shouldn't it be newForeignObj :: Ptr a -> IO () -> IO (ForeignObj a)
I agree that once we adopt (Ptr a) in preference to Addr, ForeignObj may in some cases probably also be better parameterised as well. But *please* choose a different name (like we did with Ptr/Addr) for backward compatibility.
Or maybe we should shorten it to (FPtr a)? ("F" for "finalised".)
I dislike cryptic abbreviations on principle. "Ptr" is clear, "FPtr" is not. How about "FinalisedPtr" (only 2 chars longer than "ForeignObj")? Or indeed, "ForeignPtr", which is the same length?
I think, I like `ForeignPtr'. Semantically, it makes sense given that these pointers are usually used for foreign ADTs. Manuel
On Tue, 28 Nov 2000, Simon Peyton-Jones wrote:
Simon and I noticed this morning that ForeignObj should really be parameterised.
I was considering it too and IMHO it does not need to be parametrized. Values implemented as foreign objects are often exposed to the user of the module. For this reason they are usually wrapped in newtypes to make them truly abstract. So we don't worry for the external interface - it is safe anyway, the objects will not be mistaken for something from a different library. Values kept under foreign objects are usually C structs which don't have a Haskell equivalent. If the type was simple (e.g. struct RGB {double r, g, b;};), it would be represented as a Haskell record. Since the type needs a finalizer, it usually means that it's complex enough to be not exported concretely by a C library, so there is no appropriate Haskell type to make a Storable instance - it will be accessed only through functions imported from C. And since it's complex enough, it will not be marshalled as a whole - instead its fields will be extracted as needed. And since it's finalized, it usually means that its lifetime is important because it represents some external resource, so it will really not be ever marshalled! I am sure that in most cases in practice there is no appropriate type to use as ForeignObj's argument, and it will be used as ForeignObj (). We should not support such fiction. It is very different from raw pointers which are often used for simple types which do have Storable instances. And there are more kinds of pointers used in an average library than kinds of foreign objects. Since pointers are not usually exported and there are many library functions operating on pointers, they will not be wrapped in newtypes, so they must carry the type information themselves. -- Marcin 'Qrczak' Kowalczyk
"Marcin 'Qrczak' Kowalczyk" <mk167280@zodiac.mimuw.edu.pl> wrote,
On Tue, 28 Nov 2000, Simon Peyton-Jones wrote:
Simon and I noticed this morning that ForeignObj should really be parameterised.
I was considering it too and IMHO it does not need to be parametrized.
Values implemented as foreign objects are often exposed to the user of the module. For this reason they are usually wrapped in newtypes to make them truly abstract. So we don't worry for the external interface - it is safe anyway, the objects will not be mistaken for something from a different library.
Values kept under foreign objects are usually C structs which don't have a Haskell equivalent. If the type was simple (e.g. struct RGB {double r, g, b;};), it would be represented as a Haskell record. Since the type needs a finalizer, it usually means that it's complex enough to be not exported concretely by a C library, so there is no appropriate Haskell type to make a Storable instance - it will be accessed only through functions imported from C. And since it's complex enough, it will not be marshalled as a whole - instead its fields will be extracted as needed. And since it's finalized, it usually means that its lifetime is important because it represents some external resource, so it will really not be ever marshalled!
That actually also matches my experience. Foreign objects are usually used as a kind of foreign "abstract data types". Their values are only used as arguments to external routines and nothing else. This is very different to `Ptr a' values, where we use our knowledge of `a' to peek and poke into the concrete structure refereed to by the pointer. However, I can also related to what Simon said,
It's bizarre to have withForeignObj :: ForeignObj -> (Ptr a -> IO b) -> IO b
So, how about the following? Instead of the newtype Window = Window ForeignObj way of wrapping foreign ADTs that we used so far, should we use newtype WindowTag = WindowTag () type Window = ForeignObj WindowTag ? This way, we would have the uniformity of having parametrised ForeignObj and make good use of the parameter? Cheers, Manuel
Fri, 01 Dec 2000 13:10:43 +1100, Manuel M. T. Chakravarty <chak@cse.unsw.edu.au> pisze:
Instead of the
newtype Window = Window ForeignObj
way of wrapping foreign ADTs that we used so far, should we use
newtype WindowTag = WindowTag () type Window = ForeignObj WindowTag
?
This exposes the fact that Window is a ForeignObj. Ok, but maybe some people want it to be more abstract - clients need not to know that it's just a ForeignObj. Such type is usually exported. BTW, IMHO it's more natural to write data WindowTag = WindowTag and it would be yet more natural (and would avoid ghc's warning about a constructor which is never used) if we were allowed to write data WindowTag to create a void type. -- __("< Marcin Kowalczyk * qrczak@knm.org.pl http://qrczak.ids.net.pl/ \__/ ^^ SYGNATURA ZASTÊPCZA QRCZAK
qrczak@knm.org.pl (Marcin 'Qrczak' Kowalczyk) wrote,
Fri, 01 Dec 2000 13:10:43 +1100, Manuel M. T. Chakravarty <chak@cse.unsw.edu.au> pisze:
Instead of the
newtype Window = Window ForeignObj
way of wrapping foreign ADTs that we used so far, should we use
newtype WindowTag = WindowTag () type Window = ForeignObj WindowTag
?
This exposes the fact that Window is a ForeignObj. Ok, but maybe some people want it to be more abstract - clients need not to know that it's just a ForeignObj. Such type is usually exported.
I don't want to exclude that you write newtype WindowTag = WindowTag () newtype Window = ForeignObj WindowTag That's fine, too. It would still make withForeignPtr :: ForeignObj a -> (Ptr a -> IO b) -> IO b nicer, because it constrains the parameter of `Ptr'.
BTW, IMHO it's more natural to write data WindowTag = WindowTag and it would be yet more natural (and would avoid ghc's warning about a constructor which is never used) if we were allowed to write data WindowTag to create a void type.
I agree, but that would be an extension to Haskell and so is not an option right now. We have to work with what we got. Cheers, Manuel
participants (5)
-
malcolm-ffi@cs.york.ac.uk -
Manuel M. T. Chakravarty -
Marcin 'Qrczak' Kowalczyk -
qrczak@knm.org.pl -
Simon Peyton-Jones