fs2 icon indicating copy to clipboard operation
fs2 copied to clipboard

`Pull`'s public api is unsound

Open ValdemarGr opened this issue 1 year ago • 1 comments

Because of Translate we may only G ~> F, not F ~> G. However GetScope and any operator that uses GetScope is subject to a soundness hole since:

  • Scope is allocated in the initial F.
  • Scope cannot have mapK since it must be invariant in F (acquisition of child resources).

Here is an example that throws a class cast exception.

I have been looking at it for a while and I can't see any other road to a sound structure than to require F ~> G if any interaction with the open resources in necessary.

The good news is that either more stream programs can be expressed with F ~> G or at least the current semantics can be retained explicitly.

new FunctionK[F, G] {
  def apply[A](fa: F[A]): G[A] = throw new ClassCastException("Oh no, couldn't go from F to G")
}

Assuming the api is used without throwing of exceptions, a bi-directional Translate allows Scope to be exposed (or at-least a subset of Scope's operators).

As of now, the only part of the api which is exposed and subject to this issue is lease. Fortunately lease doesn't invoke any other effects than ones in Scope, so any lossy F ~> G is completely fine, say EitherT[F, String, *] ~> F. Maybe a typeclass to represent non-structure preserving translations to make the G ~> F derivable for most cases?

Another direction could be to ensure that any Pull that is built on GetScope is non-translatable. Although this might require an extra type parameter to Pull and consequently Stream unfortunately.

ValdemarGr avatar Sep 28 '24 09:09 ValdemarGr

@mpilquist could you assign me for this issue

arnavsharma990 avatar Mar 15 '25 06:03 arnavsharma990