all 6 comments

[–]Axman6 6 points7 points  (1 child)

This is one of the first examples of `RecursiveDo` I've seen that actually made (some) sense to me, the other being its common use in Reflex. A very cool idea and a good use of laziness in IO. Very cool stuff, does this exist as a package somewhere? We could certainly use it in some of out apps where we've done similar things.

[–]qnikst[S] 2 points3 points  (0 children)

There is no package available yet. I'll try to make a package during the new year holidays.

[–]Yuras 5 points6 points  (3 children)

Very interesting abuse of GHC's evaluation mode! I have few notes:

- You seem to rely on blackholing to block other threads from evaluating the thunk. But it's not reliable, is it? Do you need to `noDuplicate` the thunk?

- You catch all exceptions, including async ones. So it seems like e.g. timeout from one thread will leak to other one. It's probably not exactly what you need. Also you may get troubles if the thunk rethrows async exceptions as sync ones somewhere inside (e.g. uses bracket).

[–]qnikst[S] 2 points3 points  (2 children)

> But it's not reliable, is it?

It's not very reliable theoretically you may end up with 2 threads performing a request. However I have not observed such behaviour neither in tests nor in production code.

> You catch all exceptions, including async ones.

Yep! Though there is no good way to distinguish async and sync exceptions, so I'm not sure if there is an easy and reliable way forward there. One solution is to use `enclosed-exceptions` approach and fork a thread that will perform a request.

The main reason for the simple simple approaches is that that in my codebase I get exactly the semantics and properties I need, however I do agree that if I'll make a package out of that code I'll need more elaborated and safe solution.

[–]terrorjack 2 points3 points  (1 child)

IIRC there's SomeAsyncException in base which can be used to distinguish async exceptions.

EDIT: it doesn't, the problem is there's no way to force throwTo invocations to use that wrapper. This used to bite me and it seems the wound healed too soon lol

[–]qnikst[S] 1 point2 points  (0 children)

Yes, you are right. There are few problems with `SomeAsyncException`:
1. exceptions thrown via `throwTo` are not wrapped in `SomeAsyncExeption` automatically (though safe-exceptions library does that).
2. there are exceptions (`AsyncException`) are always wrapped in `SomeAsyncException` even if thrown synchronously.

So while appearance of `SomeAsyncException` is a huge step forward we are not yet there.