ANN: H98 FFI Addendum 1.0, Release Candidate 10
Dear Haskell Folks, Release Candidate 10 of the H98 FFI Addendum 1.0 is now available from http://www.cse.unsw.edu.au/~chak/haskell/ffi/ The change log since RC 7, which was the last version circulated via haskell@haskell.org, is appended below. Please review this specification carefully. If no suggestion that leads to a serious change is made within two weeks, I will freeze version 1.0. Thanks, Manuel -=- Changes since RC9: * 1: Mentioning interaction with foreign threads as an open problem. * 2 & 3: Removed `threadsafe' again, as the proposal for thread support is still evolving and it is not yet clear whether a new safety level is required. * 5.5: Added the type synonym `FinalizerPtr' and rewrite the documentation of finalizers. * 5.6: Clarified the description of `StablePtr' * 5.8: Added `finalizerFree' * 6.2: All the types in CTypes must be newtypes that are exported abstractly. Changes since RC8: * 5.8: `MarshallAlloc.reallocBytes' is no longer permitted on memory allocated with `alloca' or `allocaBytes'. * 6.1: Deinitialisation of the RTS via `hs_exit()' followed by (re)initialisation with `hs_init()' must be supported. Changes since RC7: * Clarified the lexis of C identifiers and C header file names * In `ForeignPtr', added `mallocForeignPtrArray' and `mallocForeignPtrArray0' * Clarified spec of allocations functions adding constraints taken from the corresponding C routines * `mallocBytes' and `allocaBytes' must align memory sufficiently for any basic foreign type that fits into the allocated block * Removed typos in the description of the module `ForeignPtr' * Added Peter Gammie to the list of acknowledged people * `addForeignPtrFinalizer' guarantees that finalizers for a single foreign pointer are executed in the opposite order as they were added. * `Storable': Require that the size is divisible by the alignment * Added Ross Paterson to the list of acknowledged people * Added hs_free_fun_ptr() and hs_free_stable_ptr() * Changed order of arguments of `mkIOError' and `annotateIOError' to match with the current implementation in GHC's FFI libraries.
On Fri, May 23, 2003 at 07:33:05AM +1000, Manuel M T Chakravarty wrote:
Dear Haskell Folks,
Release Candidate 10 of the H98 FFI Addendum 1.0 is now available from
I have an ideological objection. I think that the inclusion of unsafePerformIO in an Addendum sends entirely the wrong signal. I know it's needed for marshalling for otherwise pure functions that pass their data through pointers. Very well, but the inclusion of unsafePerformIO allows many more uses. At a stroke it removes many of the trickiest design problems of Haskell, and we can't have that. I propose that the Addendum say that it permits unsafePerformIO for that purpose only, i.e. the IO calls it contains are restricted to foreign calls and functions from Storable and Marshal*, these may only access Ptr's inaccessable outside the unsafePerformIO, and no other visible side effects are permitted.
Ross Paterson <ross@soi.city.ac.uk> wrote,
On Fri, May 23, 2003 at 07:33:05AM +1000, Manuel M T Chakravarty wrote:
Dear Haskell Folks,
Release Candidate 10 of the H98 FFI Addendum 1.0 is now available from
I have an ideological objection. I think that the inclusion of unsafePerformIO in an Addendum sends entirely the wrong signal. I know it's needed for marshalling for otherwise pure functions that pass their data through pointers. Very well, but the inclusion of unsafePerformIO allows many more uses. At a stroke it removes many of the trickiest design problems of Haskell, and we can't have that.
I propose that the Addendum say that it permits unsafePerformIO for that purpose only, i.e. the IO calls it contains are restricted to foreign calls and functions from Storable and Marshal*, these may only access Ptr's inaccessable outside the unsafePerformIO, and no other visible side effects are permitted.
Well, the text already says, \item[unsafePerformIO ::\ IO a -> a] Execute an \code{IO} action in place of a pure computations. For the behaviour to be predictable, the IO computation should be free of side effects and independent of its environment. If the \code{IO} computation wrapped in \code{unsafePerformIO} performs side effects, then the relative order in which those side effects take place (relative to the main \code{IO} trunk, or other calls to \code{unsafePerformIO}) is indeterminate. Great care should be exercised in the use of this function. Not only because of the danger of introducing side effects, but also because \code{unsafePerformIO} may compromise typing, for example, when it is used in conjunction with polymorphic references. I think, the warning sign is clear. Especially in the context of the FFI, anything more is a waste of paper IMHO. After all, you can import any C function with a pure type, which also allows you to wreck arbitrary havoc. We enable the user to disguise arbitrary machine code as a Haskell function of essentially arbitrary type. In comparison, `unsafePerformIO' seems angelic. Cheers, Manuel
On Wed, Jun 04, 2003 at 11:18:59PM +1000, Manuel M T Chakravarty wrote:
[quoted description of unsafePerformIO] I think, the warning sign is clear. Especially in the context of the FFI, anything more is a waste of paper IMHO. After all, you can import any C function with a pure type, which also allows you to wreck arbitrary havoc. We enable the user to disguise arbitrary machine code as a Haskell function of essentially arbitrary type. In comparison, `unsafePerformIO' seems angelic.
Certainly the FFI enhances Haskell with the ability to shoot one's foot off. The aim isn't to prevent that, but to offer clear guidance to help programmers retain their feet, as well as various desirable properties of Haskell. And indeed the spec does say in several places "it's your responsibility to ensure such-and-such, and if not the results are undefined". So I'm going to propose some changes in wording: In 3.3, after the sin example, add: + Such a declaration asserts that the external entity is a true function, + i.e. when applied to the same argument values it always produces the + same result. In 5.1, change: - Furthermore, \code{Foreign} provides the following function: --- + Sometimes an external entity is a pure function, except that it passes + arguments and/or results via pointers. To permit the packaging of + such entities as pure functions, \code{Foreign} provides the following + primitive: Rationale: it's not a function, and this wording limits its purpose. - \item[unsafePerformIO ::\ IO a -> a] Execute an \code{IO} action in place of a - pure computations. For the behaviour to be predictable, the IO computation - should be free of side effects and independent of its environment. --- + \item[unsafePerformIO ::\ IO a -> a] + Return the value resulting from executing the \code{IO} action. + This value should be independent of the environment; + otherwise, the system behaviour is undefined. Rationale: to preserve equational reasoning, the crucial responsibility of the programmer is to ensure that the action is deterministic. Without that, all bets are off. The next paragraph deals with side effects: If the \code{IO} computation wrapped in \code{unsafePerformIO} performs side effects, then the relative order in which those side effects take place (relative to the main \code{IO} trunk, or other calls to \code{unsafePerformIO}) is indeterminate. Having washed our hands of unsafePerformIO applied to non-deterministic actions, we no longer need the third paragraph, which (though scary) provides no useful guidance: - Great care should be exercised in the use of this function. Not only - because of the danger of introducing side effects, but also because - \code{unsafePerformIO} may compromise typing, for example, when it is used - in conjunction with polymorphic references.
On Wed, 4 Jun 2003, Ross Paterson wrote:
- \item[unsafePerformIO ::\ IO a -> a] Execute an \code{IO} action in place of a - pure computations. For the behaviour to be predictable, the IO computation - should be free of side effects and independent of its environment. --- + \item[unsafePerformIO ::\ IO a -> a] + Return the value resulting from executing the \code{IO} action. + This value should be independent of the environment; + otherwise, the system behaviour is undefined.
Rationale: to preserve equational reasoning, the crucial responsibility of the programmer is to ensure that the action is deterministic. Without that, all bets are off. The next paragraph deals with side effects:
If the \code{IO} computation wrapped in \code{unsafePerformIO} performs side effects, then the relative order in which those side effects take place (relative to the main \code{IO} trunk, or other calls to \code{unsafePerformIO}) is indeterminate.
I suggest adding: Moreover, the side effects may be performed several times or not at all, depending on lazy evaluation and whether the compiler unfolds an enclosing definition. This seems to be a common "gotcha" which it would be wise to warn of.
Having washed our hands of unsafePerformIO applied to non-deterministic actions, we no longer need the third paragraph, which (though scary) provides no useful guidance:
- Great care should be exercised in the use of this function. Not only - because of the danger of introducing side effects, but also because - \code{unsafePerformIO} may compromise typing, for example, when it is used - in conjunction with polymorphic references.
Or maybe it would be better to provide some useful guidance? How about, To preserve the soundness of the type system, the result of unsafePerformIO should always have a monomorphic type. For example, listRef = unsafePerformIO (newIORef []) is unsafe, while listRef = unsafePerformIO (newIORef ([] :: [Int])) is type safe. In the first case listRef is assigned type IORef [a], which makes it possible to store a list of one type and fetch it with a different type. John
On Thu, Jun 05, 2003 at 09:25:11AM +0200, John Hughes wrote:
On Wed, 4 Jun 2003, Ross Paterson wrote:
+ \item[unsafePerformIO ::\ IO a -> a] + Return the value resulting from executing the \code{IO} action. + This value should be independent of the environment; + otherwise, the system behaviour is undefined.
Rationale: to preserve equational reasoning, the crucial responsibility of the programmer is to ensure that the action is deterministic. Without that, all bets are off. The next paragraph deals with side effects:
If the \code{IO} computation wrapped in \code{unsafePerformIO} performs side effects, then the relative order in which those side effects take place (relative to the main \code{IO} trunk, or other calls to \code{unsafePerformIO}) is indeterminate.
I suggest adding:
Moreover, the side effects may be performed several times or not at all, depending on lazy evaluation and whether the compiler unfolds an enclosing definition.
This seems to be a common "gotcha" which it would be wise to warn of.
Sure.
Having washed our hands of unsafePerformIO applied to non-deterministic actions, we no longer need the third paragraph, which (though scary) provides no useful guidance:
- Great care should be exercised in the use of this function. Not only - because of the danger of introducing side effects, but also because - \code{unsafePerformIO} may compromise typing, for example, when it is used - in conjunction with polymorphic references.
Or maybe it would be better to provide some useful guidance? How about,
To preserve the soundness of the type system, the result of unsafePerformIO should always have a monomorphic type. For example,
listRef = unsafePerformIO (newIORef [])
is unsafe, while
listRef = unsafePerformIO (newIORef ([] :: [Int]))
is type safe. In the first case listRef is assigned type IORef [a], which makes it possible to store a list of one type and fetch it with a different type.
With the proposed description of unsafePerformIO, neither of these forms would be meaningful, because they return an environment-dependent value. I'm suggesting we draw the line there and not say anything about uses of unsafePerformIO on the other side of it. That is, document unsafePerformIO enough to serve the FFI, but stipulate limits to preserve equational reasoning. Other uses of unsafePerformIO (e.g. for global variables) are useful, but I don't think they belong in the FFI spec. Maybe unsafePerformIO should have an addendum of its own.
That is, document unsafePerformIO enough to serve the FFI, but stipulate limits to preserve equational reasoning.
I think this is very hard to do. When we use unsafePerformIO in the ffi, we are using the IO monad to sequence [un]marshalling side-effects. For example, peeking and poking foreign memory locations, allocating and freeing memory, etc. We might even be making remote procedure calls over a network (for example, COM could transparently do this) or creating a temporary file which is deleted after use. These side effects might only affect this process (fiddling with memory) or they might affect the operating system (using sbrk to allocate more memory) or they might affect the network (remote procedure calls). They are certainly visible outside the confines of the Haskell code. We have to construct a semantics which says 'if you only allow observations of the form <insert your set of allowed observations here> then unsafePerformIO is safe'. The problem is that people might reasonably disagree about what a reasonable set of observations are. Most people would want to exclude any modification of the filesystem or network but, for some applications, those are entirely reasonable things to access. -- Alastair Reid
On Thu, Jun 05, 2003 at 11:06:04AM +0100, Alastair Reid wrote:
That is, document unsafePerformIO enough to serve the FFI, but stipulate limits to preserve equational reasoning.
I think this is very hard to do.
When we use unsafePerformIO in the ffi, we are using the IO monad to sequence [un]marshalling side-effects. For example, peeking and poking foreign memory locations, allocating and freeing memory, etc. We might even be making remote procedure calls over a network (for example, COM could transparently do this) or creating a temporary file which is deleted after use.
These side effects might only affect this process (fiddling with memory) or they might affect the operating system (using sbrk to allocate more memory) or they might affect the network (remote procedure calls). They are certainly visible outside the confines of the Haskell code.
I don't propose to outlaw side-effects (there is language there that says they're hard to predict, and John suggests more), but to demand that the value returned is independent of the environment, which is needed for equational reasoning. I'm just talking about equations of values, not of values + side effects.
John Hughes <rjmh@cs.chalmers.se> wrote,
If the \code{IO} computation wrapped in \code{unsafePerformIO} performs side effects, then the relative order in which those side effects take place (relative to the main \code{IO} trunk, or other calls to \code{unsafePerformIO}) is indeterminate.
I suggest adding:
Moreover, the side effects may be performed several times or not at all, depending on lazy evaluation and whether the compiler unfolds an enclosing definition.
This seems to be a common "gotcha" which it would be wise to warn of.
I added that.
- Great care should be exercised in the use of this function. Not only - because of the danger of introducing side effects, but also because - \code{unsafePerformIO} may compromise typing, for example, when it is used - in conjunction with polymorphic references.
Or maybe it would be better to provide some useful guidance? How about,
To preserve the soundness of the type system, the result of unsafePerformIO should always have a monomorphic type. For example,
listRef = unsafePerformIO (newIORef [])
is unsafe, while
listRef = unsafePerformIO (newIORef ([] :: [Int]))
is type safe. In the first case listRef is assigned type IORef [a], which makes it possible to store a list of one type and fetch it with a different type.
Unfortunately, this example is not directly applicable. As Ross pointed out, it is already ruled out by the determinism requirement. Moreover, `IORef's are neither part of H98 nor of the FFI. The construction of a corresponding example with `Ptr' that uses `unsafePerformIO' deterministically is possible, but IMHO a bit to verbose for inclusion at this point. However, I have changed the above cited warning to read Great care should be exercised in the use of this function. Not only because of the danger of introducing side effects, but also because \code{unsafePerformIO} may compromise typing; in particular, the result of \code{unsafePerformIO} should always have a monomorphic type. This at least describes the typing problem more precisely. Cheers, Manuel
- Great care should be exercised in the use of this function. Not only - because of the danger of introducing side effects, but also because - \code{unsafePerformIO} may compromise typing, for example, when it is used - in conjunction with polymorphic references.
Or maybe it would be better to provide some useful guidance? How about,
To preserve the soundness of the type system, the result of unsafePerformIO should always have a monomorphic type. For example,
listRef = unsafePerformIO (newIORef [])
is unsafe, while
listRef = unsafePerformIO (newIORef ([] :: [Int]))
is type safe. In the first case listRef is assigned type IORef [a], which makes it possible to store a list of one type and fetch it with a different type.
Unfortunately, this example is not directly applicable. As Ross pointed out, it is already ruled out by the determinism requirement. Moreover, `IORef's are neither part of H98 nor of the FFI. The construction of a corresponding example with `Ptr' that uses `unsafePerformIO' deterministically is possible, but IMHO a bit to verbose for inclusion at this point. However, I have changed the above cited warning to read
Great care should be exercised in the use of this function. Not only because of the danger of introducing side effects, but also because \code{unsafePerformIO} may compromise typing; in particular, the result of \code{unsafePerformIO} should always have a monomorphic type.
This at least describes the typing problem more precisely.
Cheers, Manuel
Manuel, "should always have" is unfortunately ambiguous: does it mean "you should ensure that...", or "we believe that..., but we're not completely sure". I suggest changing the last phrase to ...; to avoid this, the programmer should ensure that the result of unsafePerformIO has a monomorphic type. John
John Hughes <rjmh@cs.chalmers.se> wrote,
"should always have" is unfortunately ambiguous: does it mean "you should ensure that...", or "we believe that..., but we're not completely sure". I suggest changing the last phrase to
...; to avoid this, the programmer should ensure that the result of unsafePerformIO has a monomorphic type.
Done. Thanks, Manuel
Ross Paterson <ross@soi.city.ac.uk> wrote,
In 3.3, after the sin example, add:
+ Such a declaration asserts that the external entity is a true function, + i.e. when applied to the same argument values it always produces the + same result.
Done.
In 5.1, change:
- Furthermore, \code{Foreign} provides the following function: --- + Sometimes an external entity is a pure function, except that it passes + arguments and/or results via pointers. To permit the packaging of + such entities as pure functions, \code{Foreign} provides the following + primitive:
Rationale: it's not a function, and this wording limits its purpose.
Done.
- \item[unsafePerformIO ::\ IO a -> a] Execute an \code{IO} action in place of a - pure computations. For the behaviour to be predictable, the IO computation - should be free of side effects and independent of its environment. --- + \item[unsafePerformIO ::\ IO a -> a] + Return the value resulting from executing the \code{IO} action. + This value should be independent of the environment; + otherwise, the system behaviour is undefined.
Done.
Having washed our hands of unsafePerformIO applied to non-deterministic actions, we no longer need the third paragraph, which (though scary) provides no useful guidance:
- Great care should be exercised in the use of this function. Not only - because of the danger of introducing side effects, but also because - \code{unsafePerformIO} may compromise typing, for example, when it is used - in conjunction with polymorphic references.
I don't quite agree with this. John's IORef example is indeed outlawed by the determinism requirement. However, it is possible to construct examples that are deterministic, but still dubious from a typing perspective. Let's assume a C routine void *foo(); that *always returns the same pointer* to a buffer area. To bind this in Haskell as foreign import ccall foo :: Ptr a is problematic[1]. Using peek and poke, we can eg write a Char and read an Int. One might argue that this is not quite as bad as for IORef's, because the type argument to `Ptr' is a dummy anyway and we have `Ptr.castPtr' to convert between pointers of different type. However, it avoids an explicit `castPtr', which is not nice. Moreover, we could use a stable pointer to store a reference to an IORef in C land and use this to construct something not unlike John's example. In contrast, to John's example, we would always get the same IORef (so the function is deterministic), but could still give it the polymorphic type that it shouldn't have. Cheers, Manuel [1] I haven't explicitly used `unsafePerformIO' in this example, but binding C functions with a pure type is essentially the same thing. In fact, they are a short hand for binding the function with an IO type and then using `unsafePerformIO' to obtain the same function with a pure type.
On Sun, Jun 08, 2003 at 10:36:48PM +1000, Manuel M T Chakravarty wrote:
Done. Done. Done.
Thanks, that's much safer. It's just nitpicking now, but:
Having washed our hands of unsafePerformIO applied to non-deterministic actions, we no longer need the third paragraph, which (though scary) provides no useful guidance:
- Great care should be exercised in the use of this function. Not only - because of the danger of introducing side effects, but also because - \code{unsafePerformIO} may compromise typing, for example, when it is used - in conjunction with polymorphic references.
I don't quite agree with this. John's IORef example is indeed outlawed by the determinism requirement. However, it is possible to construct examples that are deterministic, but still dubious from a typing perspective. Let's assume a C routine
void *foo();
that *always returns the same pointer* to a buffer area. To bind this in Haskell as
foreign import ccall foo :: Ptr a
is problematic[1].
I wouldn't consider that an environment-independent value.
Great care should be exercised in the use of this function. Not only because of the danger of introducing side effects, but also because \code{unsafePerformIO} may compromise typing; in particular, the result of \code{unsafePerformIO} should always have a monomorphic type.
Unlike the other restrictions, this one could be checked by a compiler, but perhaps it's too strict. The problem isn't polymorphism as such, but polymorphic storage references, and I claim they're either environment-dependent or ill-typed. I also suspect there may be some perfectly reasonable polymorphic examples, though I can't think of a realistic example offhand. In any case, it's not accurate to call it a function.
Moreover, we could use a stable pointer to store a reference to an IORef in C land and use this to construct something not unlike John's example. In contrast, to John's example, we would always get the same IORef (so the function is deterministic), but could still give it the polymorphic type that it shouldn't have.
I don't see how this will fly. Typo: in 6.2 CTypes, the second and third bulleted paras have T for CT.
Ross Paterson <ross@soi.city.ac.uk> wrote,
Great care should be exercised in the use of this function. Not only because of the danger of introducing side effects, but also because \code{unsafePerformIO} may compromise typing; in particular, the result of \code{unsafePerformIO} should always have a monomorphic type.
Unlike the other restrictions, this one could be checked by a compiler, but perhaps it's too strict. The problem isn't polymorphism as such, but polymorphic storage references, and I claim they're either environment-dependent or ill-typed. I also suspect there may be some perfectly reasonable polymorphic examples, though I can't think of a realistic example offhand.
In any case, it's not accurate to call it a function.
I changed "function" to "primitive" (as in the text preceding the type signature).
Typo: in 6.2 CTypes, the second and third bulleted paras have T for CT.
Fixed. Cheers, Manuel
participants (4)
-
Alastair Reid -
John Hughes -
Manuel M T Chakravarty -
Ross Paterson