`Queue#mapK` violates atomicity guarantees
The implementations are not wrapped in the relevant uncancelables, meaning that it's possible to lose elements in mapK'd Queues where it is impossible with the direct implementation.
Is it really? All mapK does is converting with an user provided f: F ~> G, e.g., take is f(self.take). If self.take is correct (meaning an appropriate F.uncancelable { poll => ... poll(...) ... }), and f transforms it into something which is not G.uncancelable { poll => ... poll(...) ... }, then I would consider that f broken.
Even if we don't consider that f broken (why?), how could we fix it? In mapK we don't have access to G.uncancelable; all we have is the f: F ~> G.
then I would consider that
fbroken
Then it should at the very least be documented, as the type signature suggests any F ~> G is valid.
how could we fix it? In
mapKwe don't have access toG.uncancelable; all we have is thef: F ~> G.
Maybe deprecate mapK and introduce a new method that requires G.uncancelable?
This is a F ~> G:
new ~>[F, G] {
def apply[A](fa: F[A]) = G.raiseError(new Exception)
}
It clearly won't work. So the F ~> G has to be, at least somewhat, "reasonable". I agree that documenting it would be good.
I would consider preserving cancellability part of this "reasonable"-ness. But maybe the problem is with my imagination, and there are useful, practical F ~> Gs which don't preserve cancellability?
Even with a MonadCancel[G] constraint, it's not immediately obvious to me, how would this fix work. Putting the whole thing in a G.uncancelable { _ => ... } doesn't seem correct, as, e.g., take is cancelable.