cats-effect icon indicating copy to clipboard operation
cats-effect copied to clipboard

`Queue#mapK` violates atomicity guarantees

Open djspiewak opened this issue 3 months ago • 3 comments

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.

djspiewak avatar Sep 05 '25 19:09 djspiewak

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.

durban avatar Sep 12 '25 10:09 durban

then I would consider that f broken

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 mapK we don't have access to G.uncancelable; all we have is the f: F ~> G.

Maybe deprecate mapK and introduce a new method that requires G.uncancelable?

TomasMikula avatar Sep 14 '25 20:09 TomasMikula

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.

durban avatar Sep 15 '25 23:09 durban