Strangely enough, Simon and I had actually come up with another variant, which I believe is simpler than both the original and Wolfgang's proposal.
Yes, that seems to be what Daan was talking about. I'm sorry to say that I don't really like it... *) It violates requirement #4 "The specification shouldn’t explicitly require lightweight “green” threads to exist." OK, I wrote that requirement, and I might be the only one who cares. But I still think that the existance of lightweight threads should not somehow become a feature of the Haskell language. *) Using the system requires a lot of knowledge of the thread allocation issues, as all thread management has to be done manually. Special combinators like nonBlocking will have to be used far more often than the "threadbound" combinator of proposal #2. *) The blocking behaviour of foreign calls is specified with a bias towards GHC's implementation. Let's assume I have a Haskell interpreter that runs in just one thread. Now I want to add FFI support for multiple "foreign" OS threads without too much effort, and without caring for top-notch performance. I'd probably keep the interpreter running in just one thread, and send messages to other OS threads whenever I want to execute a foreign call. In this situation, threadsafe calls come for free (as far as implementation complexity is concerned). If I allow multiple Haskell threads to be bound to one OS thread, there would be blocking, but the behaviour would be different from the proposed behaviour; other Haskell threads bound to the same OS thread would not block until they issue a foreign call. *) Blocking "safe" calls will keep surprising newbies (they did surprise me once...). *) Blocking "safe" calls are a problem for libraries and for large software projects. a) If I use an IO action from a library, how do I know whether it uses the nonBlocking combinator internally? The library developer might have considered 'nonBlocking' to be too expensive or (s)he might not have been aware of the blocking behaviour of "safe" calls. To be really sure, I'd have to wrap every library call with the nonBlocking combinator, even when it's not necessary, which will be cumbersome and inefficient. [The same danger exists with "unsafe", but at least that's clearly marked as being unsafe...] b) Let's assume I'm writing a library. I want to use some foreign API that relies on thread local state internally (without exposing that fact to my library's users). I don't know whether my Haskell thread is the only Haskell thread in the OS thread, so I have to spawn a new OS thread for myself. If the program that uses the library happens to be single-threaded, that's wasted effort again. [This could probably be fixed by providing a way to query the number of threads bound to an OS thread] *) Having to deal with which Haskell threads are mapped to which OS threads seems too low-level. After all, we are willing to accept the complexity of a Haskell RTS in order to avoid always using C... I'm also willing to accept some added complexity in order to not have to manually manage all my OS threads. *) The formal semantics might be simpler, but as far as I can tell, the GHC implementation of Proposal III would be no simpler than the implementation of Proposal II. OK that's all for now, maybe I'll be back with more. But I'm sure you can utterly refute several of those arguments... Cheers, Wolfgang