Re: unsafePerformIO safety.
I wouldn't like if unsafePerformIO could never be inlined, sometimes you want it inlined for performance. And not all uses are hacky, it's just that when I use it, then burden is on me to convince myself that it is safe. On Mar 6, 2007, at 23:56 , Neil Mitchell wrote: Hi On 3/6/07, Lennart Augustsson [EMAIL PROTECTED] wrote: Yeah, you really need {-# NOINLINE var #-} to make it reasonable safe. Couldn't GHC bake in knowledge about unsafePerformIO, and never inline it? It is a slightly hacky solution, but since unsafePerformIO is pretty much only used in hacks, I think its almost fitting. Thanks Neil ___ Glasgow-haskell-users mailing list Glasgow-haskell-users@haskell.org http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Re: unsafePerformIO safety.
Lennart Augustsson wrote: I wouldn't like if unsafePerformIO could never be inlined, sometimes you want it inlined for performance. And not all uses are hacky, it's just that when I use it, then burden is on me to convince myself that it is safe. unsafePerformIO is currently not inlined - there's a NOINLINE pragma on its definition in GHC.IOBase, and some comments in there to explain why. You're right that sometimes you really want it to be inlined - this is why there's a function called inlinePerformIO in Data.ByteString.Base, for example. You'd better really know what you're doing before using that one, though :-) Cheers, Simon ___ Glasgow-haskell-users mailing list Glasgow-haskell-users@haskell.org http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Re: unsafePerformIO safety.
-BEGIN PGP SIGNED MESSAGE- Hash: SHA1 Simon Marlow wrote: You're right that sometimes you really want it to be inlined - this is why there's a function called inlinePerformIO in Data.ByteString.Base, for example. You'd better really know what you're doing before using that one, though :-) yep, it should be generally available as unsafeInlineUnsafePerformIO (-: It's especially unsafe because... all of the IO might not be executed, due to lazy evaluation + optimization? Some of the IO might be run twice without other parts of it being so? Isaac -BEGIN PGP SIGNATURE- Version: GnuPG v1.4.3 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iD8DBQFF7p9jHgcxvIWYTTURAqAKAKCu8dJ4rpyMcMH7ebPv0HfIUyGSgACgy0Jq naeTCZk/2xZraOrSJtyObm8= =oKKG -END PGP SIGNATURE- ___ Glasgow-haskell-users mailing list Glasgow-haskell-users@haskell.org http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Re: unsafePerformIO safety.
On Tue, 06 Mar 2007 12:03:05 -0800 David Brown [EMAIL PROTECTED] wrote: I've noticed quite a few pages referencing constructs such as: var :: MVar ([Foo]) var = unsafePerformIO (newMVar ([])) and the likes. Is there a danger of different uses of 'var' getting new MVars instead of all sharing one. Having a reliable way to create a piece of global state would be very convenient. This operation is unsafe by definition. I use it extensively, without problems. The unsafe in the name reminds you that there are situations for which the function is inappropriate, but all of my deployed commercial programs have functionality of this sort. Understand the risk, but don't hesitate to use it. Seth Kurtzberg Dave ___ Glasgow-haskell-users mailing list Glasgow-haskell-users@haskell.org http://www.haskell.org/mailman/listinfo/glasgow-haskell-users ___ Glasgow-haskell-users mailing list Glasgow-haskell-users@haskell.org http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Re: unsafePerformIO safety.
Seth Kurtzberg wrote: On Tue, 06 Mar 2007 12:03:05 -0800 David Brown [EMAIL PROTECTED] wrote: I've noticed quite a few pages referencing constructs such as: var :: MVar ([Foo]) var = unsafePerformIO (newMVar ([])) and the likes. Is there a danger of different uses of 'var' getting new MVars instead of all sharing one. Having a reliable way to create a piece of global state would be very convenient. This operation is unsafe by definition. I use it extensively, without problems. The unsafe in the name reminds you that there are situations for which the function is inappropriate, but all of my deployed commercial programs have functionality of this sort. Understand the risk, but don't hesitate to use it. Do you do anything to keep 'var' from getting inlined? I can envision a case where the code would be inlined, and then each use would get a separate MVar. Thanks, Dave ___ Glasgow-haskell-users mailing list Glasgow-haskell-users@haskell.org http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Re: unsafePerformIO safety.
-BEGIN PGP SIGNED MESSAGE- Hash: SHA1 David Brown wrote: I've noticed quite a few pages referencing constructs such as: var :: MVar ([Foo]) var = unsafePerformIO (newMVar ([])) and the likes. Is there a danger of different uses of 'var' getting new MVars instead of all sharing one. If I remember correctly, you should put {-# NOINLINE var #-} on a line just before that. Having a reliable way to create a piece of global state would be very convenient. This is well known and extensively discussed - unfortunately it is a complicated (or at least controversial) issue Isaac -BEGIN PGP SIGNATURE- Version: GnuPG v1.4.3 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iD8DBQFF7fiFHgcxvIWYTTURAoMXAJ9SCryCX+daNLKrMIhWlMh/aJmVXwCghosx 6/lBweYnNslHLal57RAtX0Y= =2oIN -END PGP SIGNATURE- ___ Glasgow-haskell-users mailing list Glasgow-haskell-users@haskell.org http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Re: unsafePerformIO safety.
Yeah, you really need {-# NOINLINE var #-} to make it reasonable safe. On Mar 6, 2007, at 23:18 , David Brown wrote: Seth Kurtzberg wrote: On Tue, 06 Mar 2007 12:03:05 -0800 David Brown [EMAIL PROTECTED] wrote: I've noticed quite a few pages referencing constructs such as: var :: MVar ([Foo]) var = unsafePerformIO (newMVar ([])) and the likes. Is there a danger of different uses of 'var' getting new MVars instead of all sharing one. Having a reliable way to create a piece of global state would be very convenient. This operation is unsafe by definition. I use it extensively, without problems. The unsafe in the name reminds you that there are situations for which the function is inappropriate, but all of my deployed commercial programs have functionality of this sort. Understand the risk, but don't hesitate to use it. Do you do anything to keep 'var' from getting inlined? I can envision a case where the code would be inlined, and then each use would get a separate MVar. Thanks, Dave ___ Glasgow-haskell-users mailing list Glasgow-haskell-users@haskell.org http://www.haskell.org/mailman/listinfo/glasgow-haskell-users ___ Glasgow-haskell-users mailing list Glasgow-haskell-users@haskell.org http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Re: unsafePerformIO safety.
Hi On 3/6/07, Lennart Augustsson [EMAIL PROTECTED] wrote: Yeah, you really need {-# NOINLINE var #-} to make it reasonable safe. Couldn't GHC bake in knowledge about unsafePerformIO, and never inline it? It is a slightly hacky solution, but since unsafePerformIO is pretty much only used in hacks, I think its almost fitting. Thanks Neil ___ Glasgow-haskell-users mailing list Glasgow-haskell-users@haskell.org http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Re: unsafePerformIO safety.
Neil Mitchell wrote: On 3/6/07, Lennart Augustsson [EMAIL PROTECTED] wrote: Yeah, you really need {-# NOINLINE var #-} to make it reasonable safe. Couldn't GHC bake in knowledge about unsafePerformIO, and never inline it? It is a slightly hacky solution, but since unsafePerformIO is pretty much only used in hacks, I think its almost fitting. It seems to be used a bit more than just as a hack. Many things that interface with the real world, but try to present lazy interfaces have to use it. Maintaining a shared state that doesn't have to be passed around to everything that uses it isn't really a hack. As an example, I would like to have something that performs logging, and is used by many clients. Without the unsafePerformIO, everything has to somehow find and pass around the state of this logging system, whereas with it, it can just allocate one when first needed. Non-strict semantics are kind of a new thing for me. I'm still trying to get a good grasp of what can be lazy, what should live in the IO Monad, and what should have a carefully crafted bridge between the two. Things like hGetContents have somewhat set a trend here. Dave ___ Glasgow-haskell-users mailing list Glasgow-haskell-users@haskell.org http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Re: unsafePerformIO and NOINLINE Pragma
Am Dienstag, 13. September 2005 16:13 schrieb David Sabel: Hi, Hi! I want to analyse the laziness of a data structure. To check how many nodes are constructed I use a global counter. counter :: IORef Int counter = unsafePerformIO (newIORef 0) This counter is increased every time the constructor is called by redefining the constructor OBDD as follows. oBDD low var high = seq (unsafePerformIO (modifyIORef counter (+1))) (OBDD low var high) This works fine. When I compile with optimisations the counter is always set to one no matter how many nodes are constructed. I thought this would be caused by inlining. Therefore I have added two NOINLINE pragmata. {-# NOINLINE counter #-} {-# NOINLINE oBDD #-} Although the counter doesn't work. Is there another optimisation that can cause harm? Is there something wrong with the pragmata? Two comments: 1. There are other optimisations than inlining that can break sharing, e.g. common subexpression elimination, full-laziness-transformation. 2. I tested the following: {-# NOLINE counter #-} {-# INLINE oBDD #-} then the counter seems to work correct. In my opinion oBDD is an abstraction and can always be inlined. Sadly this solution doesn't work in my environment. The counter is always set to 2 while it should be something around 15.000. I think it's not worth going into detail of the transformations for me thus I will check the number of nodes without optimisations and the performance with optimisations. Thanks anyway. ___ Glasgow-haskell-users mailing list Glasgow-haskell-users@haskell.org http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Re: unsafePerformIO
Sven Panne wrote: Huh? I'm not sure what you mean exactly, but with the help of unsafePerformIO and a pragma for clever compilers you can simulate something like a global variable in Haskell. Here an excerpt from the GLUT menu handling module: {-# NOINLINE theMenuTable #-} theMenuTable :: IORef MenuTable theMenuTable = unsafePerformIO (newIORef emptyMenuTable) ... Definitely not something to be proud of, but quite handy from time to time. :-) Alternatives are passing the IORef to every function which needs it (but this would clutter up the GLUT API in the above case) or using the FFI for holding global data on the C side. GHC uses a similar hack internally, too, BTW. This is not just handy from time to time, but very frequently. I've just discovered it occurs about 100 times in 100K LOC that I am responsible for, so often that I have stopped feeling guilty about it. I don't really know what else I could do. One solution would be to use implicit parameters to pass a global state variable around, but this would require me to change the type of huge numbers of functions, since implicit parameters are still explicit in types. I don't remember having any actual bugs caused by unsafePerformIO. Well, only one, before I knew about putting NOINLINE in. ___ Glasgow-haskell-users mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
RE: unsafePerformIO and IORefs
Hal Daume III wrote: You can't. [...] Well, you can, but only for CAFs. This idiom/hack is used quite happily throughout GHC, HOpenGL, H/Direct, ... I think quite happily is a bit strong ;-) We'd much rather have a safe way to do what is really quite a reasonable thing. Cheers, Simon ___ Glasgow-haskell-users mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Re: unsafePerformIO and IORefs
Hal Daume III wrote: You can't. [...] Well, you can, but only for CAFs. This idiom/hack is used quite happily throughout GHC, HOpenGL, H/Direct, ... Slightly modified stuff from GHC's sources: -- global variables in Haskell :-) global :: a - IORef a global a = unsafePerformIO (newIORef a) #define GLOBAL_VAR(name,value,ty) \ name :: IORef (ty) ; \ name = global (value) ; \ {-# NOINLINE name #-} -- examples GLOBAL_VAR(counter, 0, Int) GLOBAL_VAR(flag, False, Bool) Cheers, S. ___ Glasgow-haskell-users mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Re: unsafePerformIO and IORefs
On Mon, Nov 18, 2002 at 10:36:05AM -0800, Hal Daume III wrote: You can't. CSE (common subexpression elimination) will replace any occurances of 'newState 0' in a function body with the same value. In short: don't use upIO :) Sorry, cannot resist to pour a little salt onto the wound :) [232]% grep global ghc/compiler/utils/Util.lhs , global global :: a - IORef a global a = unsafePerformIO (newIORef a) [233]% ghc/compiler/HsVersions.h: [...] #ifdef __GLASGOW_HASKELL__ #define GLOBAL_VAR(name,value,ty) \ name = Util.global (value) :: IORef (ty); \ {-# NOINLINE name #-} #endif [237]% grep -r GLOBAL_VAR ghc/compiler | wc -l 90 Muahahah... ;-P Cheers, Michael ___ Glasgow-haskell-users mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Re: unsafePerformIO
- Original Message - From: Simon Marlow [EMAIL PROTECTED] Sent: Tuesday, September 24, 2002 2:58 PM Subject: RE: unsafePerformIO [...] As for sharing, we currently don't provide any guarnatees, although we should. It is currently the case that if you write a = unsafePerformIO (putStr hello) b = unsafePerformIO (putStr hello) and both a and b are evaluated, then you may get either one or two hellos on stdout. You can currently make things more deterministic by (a) adding NOINLINE pragmas for a and b, and (b) using the flag -fno-cse to disable common sub-expression elimination. Then you'll get exactly two instances of hello on stdout, although we won't guarantee that behaviour for ever. At some point we'll fix it so that unsafePerformIO applications are never duplicated or coalesced. Are there any (short) examples available where using of unsafePerformIO leads to unexpected behaviour, especially an example with the terms a and b from above? with best regards, David - JWGU Frankfurt ___ Glasgow-haskell-users mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
RE: unsafePerformIO
The actions performed by unsafePerformIO are simply done at some entirely unpredictable time, perhaps interleaved with actions on the main execution path. The formal semantics in the notes doesn't have a good way to express that because the purely-functional part is given a denotational semantics... yet unsafePerformIO can occur in the middle of that. So it's tiresome to characterise in theory, and hard to predict in practice. You should only use it when the state it is fiddling with is well partitioned. Simon | -Original Message- | From: David Sabel [mailto:[EMAIL PROTECTED]] | Sent: 20 September 2002 13:48 | To: Simon Peyton-Jones; [EMAIL PROTECTED] | Subject: unsafePerformIO | | In read your paper Tackling the Awkward Squad: monadic input / output, | concurrency, exceptions, and foreign-language calls in Haskell, and have | a question about unsafePerformIO. | | In your operational semantic of the IO-Monad you tell nothing about, how | 'unsafe' IO actions are performed, is there another paper / documentation | about | this available, or can you - or someone else - give me a review about that? | | David | JWGU Frankfurt | ___ Glasgow-haskell-users mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
RE: unsafePerformIO
Simon Peyton-Jones wrote: | The actions performed by unsafePerformIO are simply | done at some entirely unpredictable time, perhaps | interleaved with actions on the main execution path. But it is a fact that many of us have at least some idea of what happens under the hood when we use unsafePerformIO. This is also described in your paper Stretching the storage manager: weak pointers and stable names in Haskell. However, I for example have no idea what happens when unsafely executing something that throws exceptions, performs a forkIO, something that uses MVar's, etc. It would be nice to see what happens in such a case, and at least a document that informally describes what happens. This includes issues such as loss of sharing because of inlining, etc. unsafePerformIO is the best thing since sliced bread for someone who wants to add stuff to the compiler without changing the compiler. The usefulness/portability at the moment is limited since nobody dares to say what is going on. /Koen. ___ Glasgow-haskell-users mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
RE: unsafePerformIO
But it is a fact that many of us have at least some idea of what happens under the hood when we use unsafePerformIO. This is also described in your paper Stretching the storage manager: weak pointers and stable names in Haskell. However, I for example have no idea what happens when unsafely executing something that throws exceptions, performs a forkIO, something that uses MVar's, etc. Exceptions: an exception raised by the computation inside unsafePerformIO will be propagated to the enclosing expression, as per the normal semantics for imprecise exceptions. The exception raised by an application of unsafePerformIO may of course also be imprecise; consider 'unsafePerformIO $ (1/0 + error foo) `seq` return ()'. The behaviour of forkIO and other side-effecting operations inside unsafePerforIO can I think be explained by the following statement: if an expression unsafePerformIO e has been reduced to head normal form, then all the I/O computations in e have been performed. The exact timing of the evaluation is underspecified, just as any other expression in Haskell. However, if you're using unsafePerformIO with real side effects, then I suspect that what you're doing is highly dodgy and you should find another way to do it :-) Does that help? As for sharing, we currently don't provide any guarnatees, although we should. It is currently the case that if you write a = unsafePerformIO (putStr hello) b = unsafePerformIO (putStr hello) and both a and b are evaluated, then you may get either one or two hellos on stdout. You can currently make things more deterministic by (a) adding NOINLINE pragmas for a and b, and (b) using the flag -fno-cse to disable common sub-expression elimination. Then you'll get exactly two instances of hello on stdout, although we won't guarantee that behaviour for ever. At some point we'll fix it so that unsafePerformIO applications are never duplicated or coalesced. If you're interested in when unsafePerformIO is safe to use, see: http://www.haskell.org/pipermail/glasgow-haskell-users/2002-July/003683. html (and see my followups for an alternative view). Cheers, Simon ___ Glasgow-haskell-users mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
RE: unsafePerformIO
Koen Based on this info, how would you like to write the notes you would like to see on unsafePerformIO? The starting point is at http://haskell.cs.yale.edu/ghc/docs/latest/html/base/GHC.IOBase.html#uns afePerformIO If you write the notes, we'll check their veracity and add them. We'll do the formatting too! Simon | -Original Message- | From: Simon Marlow [mailto:[EMAIL PROTECTED]] | Sent: 24 September 2002 13:59 | To: Koen Claessen; [EMAIL PROTECTED] | Subject: RE: unsafePerformIO | | But it is a fact that many of us have at least some idea of | what happens under the hood when we use unsafePerformIO. | This is also described in your paper Stretching the storage | manager: weak pointers and stable names in Haskell. | | However, I for example have no idea what happens when | unsafely executing something that throws exceptions, | performs a forkIO, something that uses MVar's, etc. | | Exceptions: an exception raised by the computation inside | unsafePerformIO will be propagated to the enclosing expression, as per | the normal semantics for imprecise exceptions. The exception raised by | an application of unsafePerformIO may of course also be imprecise; | consider 'unsafePerformIO $ (1/0 + error foo) `seq` return ()'. | | The behaviour of forkIO and other side-effecting operations inside | unsafePerforIO can I think be explained by the following statement: if | an expression unsafePerformIO e has been reduced to head normal form, | then all the I/O computations in e have been performed. The exact | timing of the evaluation is underspecified, just as any other expression | in Haskell. However, if you're using unsafePerformIO with real side | effects, then I suspect that what you're doing is highly dodgy and you | should find another way to do it :-) | | Does that help? | | As for sharing, we currently don't provide any guarnatees, although we | should. It is currently the case that if you write | | a = unsafePerformIO (putStr hello) | b = unsafePerformIO (putStr hello) | | and both a and b are evaluated, then you may get either one or two | hellos on stdout. You can currently make things more deterministic by | (a) adding NOINLINE pragmas for a and b, and (b) using the flag -fno-cse | to disable common sub-expression elimination. Then you'll get exactly | two instances of hello on stdout, although we won't guarantee that | behaviour for ever. At some point we'll fix it so that unsafePerformIO | applications are never duplicated or coalesced. | | If you're interested in when unsafePerformIO is safe to use, see: | | http://www.haskell.org/pipermail/glasgow-haskell-users/2002-July/003683. | html | | (and see my followups for an alternative view). | | Cheers, | Simon | ___ | Glasgow-haskell-users mailing list | [EMAIL PROTECTED] | http://www.haskell.org/mailman/listinfo/glasgow-haskell-users ___ Glasgow-haskell-users mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Re: unsafePerformIO
Koen Claessen [EMAIL PROTECTED] writes: However, I for example have no idea what happens when unsafely executing something that throws exceptions, performs a forkIO, something that uses MVar's, etc. I won't dare to try to characterize the difference exactly but you should expect very different behaviour between Hugs and GHC when using unsafePerformIO with threads and exceptions. The Hugs version of unsafePerformIO isn't intended to receive as much abuse as the GHC version whereas the GHC version has been (ab)used by large numbers of people. -- Alastair ___ Glasgow-haskell-users mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Re: unsafePerformIO
I'm not sure of a reference, the basic idea is this: IO a is represented by the pair (RealWorld, a) (unboxed, really but whatever) When an IO action is run (via main), a RealWorld state is provided by the compiler and passes it around. When you do unsafePerformIO, the compiler conjures up some value of type RealWorld to use. It is unsafe because it doesn't guarentee the relative order of IO actions. Of course, someone correct me if I'm mistaken. - Hal -- Hal Daume III Computer science is no more about computers| [EMAIL PROTECTED] than astronomy is about telescopes. -Dijkstra | www.isi.edu/~hdaume On Fri, 20 Sep 2002, David Sabel wrote: In read your paper Tackling the Awkward Squad: monadic input / output, concurrency, exceptions, and foreign-language calls in Haskell, and have a question about unsafePerformIO. In your operational semantic of the IO-Monad you tell nothing about, how 'unsafe' IO actions are performed, is there another paper / documentation about this available, or can you - or someone else - give me a review about that? David JWGU Frankfurt ___ Glasgow-haskell-users mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/glasgow-haskell-users ___ Glasgow-haskell-users mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
RE: unsafePerformIO around FFI calls
Hal Daume [EMAIL PROTECTED] writes: I'm curious exactly what is safe and what is unsafe to wrap unsafePerformIO around when it comes to FFI calls. Here's a simple test: Could you imagine an alternative implementation of the same API in pure Haskell? (Don't consider efficiency or effort required to write the implementation, just whether it can be done.) If so, then it is ok to use unsafePerformIO and the ffi to implement the API instead. If it fails that test, it is incredibly unlikely that it is ok and a proof that it is ok is likely to be pretty complex - maybe worth a PLDI paper or some such. That's a nice succinct way to describe it. Another way, which boils down to the same thing but which is a little more concrete, is to ask: - Does the function's result depend only on the values of its arguments? (obviously only makes sense for a top-level IO function which you want to wrap in unsafePerformIO - for a non-top-level function or expression just replace 'arguments' with 'arguments and free variables'). Cheers, Simon ___ Glasgow-haskell-users mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Re: unsafePerformIO around FFI calls
That's a nice succinct way to describe it. Another way, which boils down to the same thing but which is a little more concrete, is to ask: - Does the function's result depend only on the values of its arguments? I have two problems with this alternative test: 1) It is sometimes slightly stricter test than necessary. Consider a hypothetical pair of C functions Foo toFoo(int); int fromFoo(Foo); which satisfy the property fromFoo(toFoo(x)) == x but such that the result of toFoo does not depend on its argument. (Perhaps toFoo allocates some memory in which to stores its result and returns a pointer to that memory.) The function's result does vary independently of its values so it fails your test. But if toFoo/fromFoo are the only functions on Foo, then we could obviously have implemented the same API in Haskell with the aid of newtype so it passes my test. 2) It fails to recognise the fact that IO actions have side effects. For example, the C library function 'free' always returns the same result (i.e., '()') but it's a bad idea to call free twice on the same argument. One could argue that the side effect is part of the result because IO actions return a modified world but only a long term functional programmer would think like that so it doesn't help the man in the street. (In fact, IIRC, the Concurrent Haskell semantics doesn't use the state-passing explanation so you don't even see side effects reflected as changes in the returned world state.) -- Alastair Reid [EMAIL PROTECTED] Reid Consulting (UK) Limited http://www.reid-consulting-uk.ltd.uk/alastair/ ___ Glasgow-haskell-users mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
RE: unsafePerformIO around FFI calls
That's a nice succinct way to describe it. Another way, which boils down to the same thing but which is a little more concrete, is to ask: - Does the function's result depend only on the values of its arguments? I have two problems with this alternative test: 1) It is sometimes slightly stricter test than necessary. Consider a hypothetical pair of C functions Foo toFoo(int); int fromFoo(Foo); which satisfy the property fromFoo(toFoo(x)) == x but such that the result of toFoo does not depend on its argument. (Perhaps toFoo allocates some memory in which to stores its result and returns a pointer to that memory.) The function's result does vary independently of its values so it fails your test. But if toFoo/fromFoo are the only functions on Foo, then we could obviously have implemented the same API in Haskell with the aid of newtype so it passes my test. Ok, if we're going to nit pick :) When talking about equality you have to restrict that to observable equivalence in the context of whatever abstract types you're dealing with. If a function always returns observably equivalent results when given observably equivalent arguments, then it is safe. For example, toFoo would not be safe if you can test for equality between pointers. But if all you can do is convert it back using fromFoo, then you're ok. 2) It fails to recognise the fact that IO actions have side effects. Well, side effects are usually only visible in the IO monad so that's ok. In your free() example, the result is either () or _|_, so the function does depend on more than just the value of the argument. I think the definition holds (but only just). For example, we normally consider a function which uses some temporary allocation on the C heap as safe to use from unsafePerformIO. But its side effect is visible from the IO monad by inspecting the C heap pointer. Cheers, Simon ___ Glasgow-haskell-users mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Re: unsafePerformIO around FFI calls
Hal Daume [EMAIL PROTECTED] writes: I'm curious exactly what is safe and what is unsafe to wrap unsafePerformIO around when it comes to FFI calls. Here's a simple test: Could you imagine an alternative implementation of the same API in pure Haskell? (Don't consider efficiency or effort required to write the implementation, just whether it can be done.) If so, then it is ok to use unsafePerformIO and the ffi to implement the API instead. If it fails that test, it is incredibly unlikely that it is ok and a proof that it is ok is likely to be pretty complex - maybe worth a PLDI paper or some such. -- Alastair Reid [EMAIL PROTECTED] Reid Consulting (UK) Limited http://www.reid-consulting-uk.ltd.uk/alastair/ ___ Glasgow-haskell-users mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/glasgow-haskell-users