(apologies for my delay in coming back to this thread)
I think there’s quite a lot of value in this thread! I certainly learned a lot from all the links that were shared here, so thank you! This thread has a lot of resources and knowledge that was once scattered across different places and I guess the lack of a definite answer is an answer in and of itself: How to use
unsafePerformIO safely? Well, it depends!
To rely on
unsafePerformIO, it seems to be necessary to safeguard against any assumptions on the order and number of executions: your
unsafePerformIO is at the mercy of the runtime system and it may be executed multiple times or none at all; these runs might happen sequentially in some unspecified order or concurrently.
Is that sufficient to conclude a use of
unsafePerformIO is safe? In general, not at all. The full answer is inherently domain specific: what do you care about in terms of side-effects? There is already a myriad of ways in which we pretend operations are pure, but in reality they are not (memory allocation, for instance).
Nevertheless, I’m convinced that it is worth the effort to conduct this analysis: if it is possible to rely on
unsafePerformIO f, this will keep IO hidden from the rest of the code and the benefits of that are huge!
Moreover, you now only have to reason about a small piece of the code being “safe”, whatever that means in your context.
I’m not sure how being in
IO would help anything in this case. Is it simply because now you’d have to pick an order in which these libraries are called, therefore “acknowledging” their interaction? Because they would still interact.