New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Cats Effect: STM & TRef #791 #796
Conversation
Exactly what I was hoping for! I'll comment more when you're ready, but this is looking great. |
@jdegoes A couple of question has raised in my head while doing this PR:
I would appreciate if you could elaborate on this questions and of course leave comments in code if you spot other issues. |
Yes, it's ok they are put there (in the
I would reference origin docs (definitely not copy them along).
This makes sense to me. Of course you can probably do that generically for any
One iteration through the iterable is not that significant. It will be much faster doing it this way. ^^^ Thanks for your work on this, will do a PR review later today! |
Update master
@@ -73,8 +74,8 @@ abstract class CatsInstances extends CatsInstances1 { | |||
|
|||
implicit def taskEffectInstances[R]( | |||
implicit runtime: Runtime[R] | |||
): effect.ConcurrentEffect[TaskR[R, ?]] with SemigroupK[TaskR[R, ?]] = | |||
new CatsConcurrentEffect[R](runtime) | |||
): effect.ConcurrentEffect[TaskR[R, ?]] with SemigroupK[TaskR[R, ?]] with FunctionK[TaskR[R, ?], effect.IO] = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is FunctionK
really intended to be used as an implicit
? This would not be true for, e.g., Scalaz's NaturalTransformation
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed
/** | ||
* See [[scalaz.zio.stm.STM]] | ||
*/ | ||
final class STM[F[+ _], +A] private[stm] (private[stm] val underlying: ZSTM[Throwable, A])( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd have this class extend AnyVal
, which you will be able to do when removing the implicit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would like to make it AnyVal too, but scala compiler says value class may not wrap another user-defined value class
, because ZSTM is also an AnyVal. I don't see how to overcome this restriction for now.
* See [[scalaz.zio.stm.STM]] | ||
*/ | ||
final class STM[F[+ _], +A] private[stm] (private[stm] val underlying: ZSTM[Throwable, A])( | ||
implicit liftIO: ZIO[Any, Throwable, ?] ~> F |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we need this implicit. We should be able to go directly from ZIO
to any F[_]
that supports Async
(or maybe Effect
or ConcurrentEffect
), given an implicit Runtime
. And we can push that down to atomically
since that's the only one that needs it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I found a way to implement atomically using Async
and Runtime[Any]
, and removed all useless FunctionK
implicits, please check if it's done right.
(self map (Left[A, B](_))) orElse (that map (Right[A, B](_))) | ||
|
||
/** | ||
* See scalaz.zio.stm.STM.unit |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No Scaladoc link?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did this because in this case sbt doc
command fails with err message like Could not find any member to link for "scalaz.zio.stm.STM.unit".
I suspect this is because it sees unit
in the STM
class and also in companion object, and fails to resolve which unit
to link.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No worries!
final def unit: STM[F, Unit] = const(()) | ||
|
||
/** | ||
* See scalaz.zio.stm.STM.unit |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No Scaladoc link?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same problem here.
|
||
object STM { | ||
|
||
final def succeed[F[+ _], A](a: A)(implicit liftIO: ZIO[Any, Throwable, ?] ~> F): STM[F, A] = new STM(ZSTM.succeed(a)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't need an implicit.
|
||
final def succeed[F[+ _], A](a: A)(implicit liftIO: ZIO[Any, Throwable, ?] ~> F): STM[F, A] = new STM(ZSTM.succeed(a)) | ||
|
||
final def atomically[F[+ _], A](stm: STM[F, A])(implicit liftIO: ZIO[Any, Throwable, ?] ~> F): F[A] = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can make do with an implicit Runtime[Any]
, then no need for implicit FunctionK
.
final def atomically[F[+ _], A](stm: STM[F, A])(implicit liftIO: ZIO[Any, Throwable, ?] ~> F): F[A] = | ||
liftIO(ZSTM.atomically(stm.underlying)) | ||
|
||
final def check[F[+ _]](p: Boolean)(implicit liftIO: ZIO[Any, Throwable, ?] ~> F): STM[F, Unit] = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't need an implicit.
|
||
final def collectAll[F[+ _], A]( | ||
i: Iterable[STM[F, A]] | ||
)(implicit liftIO: ZIO[Any, Throwable, ?] ~> F): STM[F, List[A]] = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't need an implicit.
)(implicit liftIO: ZIO[Any, Throwable, ?] ~> F): STM[F, List[A]] = | ||
new STM(ZSTM.collectAll(i.map(_.underlying))) | ||
|
||
final def die[F[+ _]](t: Throwable)(implicit liftIO: ZIO[Any, Throwable, ?] ~> F): STM[F, Nothing] = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't need an implicit.
final def die[F[+ _]](t: Throwable)(implicit liftIO: ZIO[Any, Throwable, ?] ~> F): STM[F, Nothing] = | ||
succeedLazy(throw t) | ||
|
||
final def dieMessage[F[+ _]](m: String)(implicit liftIO: ZIO[Any, Throwable, ?] ~> F): STM[F, Nothing] = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't need an implicit.
final def dieMessage[F[+ _]](m: String)(implicit liftIO: ZIO[Any, Throwable, ?] ~> F): STM[F, Nothing] = | ||
die(new RuntimeException(m)) | ||
|
||
final def fail[F[+ _]](e: Throwable)(implicit liftIO: ZIO[Any, Throwable, ?] ~> F): STM[F, Nothing] = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't need an implicit.
final def fail[F[+ _]](e: Throwable)(implicit liftIO: ZIO[Any, Throwable, ?] ~> F): STM[F, Nothing] = | ||
new STM(ZSTM.fail(e)) | ||
|
||
final def foreach[F[+ _], A, B]( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't need an implicit.
)(f: A => STM[F, B])(implicit liftIO: ZIO[Any, Throwable, ?] ~> F): STM[F, List[B]] = | ||
collectAll(as.map(f)) | ||
|
||
final def fromEither[F[+ _], A](e: Either[Throwable, A])(implicit liftIO: ZIO[Any, Throwable, ?] ~> F): STM[F, A] = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't need an implicit.
final def fromEither[F[+ _], A](e: Either[Throwable, A])(implicit liftIO: ZIO[Any, Throwable, ?] ~> F): STM[F, A] = | ||
new STM(ZSTM.fromEither(e)) | ||
|
||
final def fromTry[F[+ _], A](a: => Try[A])(implicit liftIO: ZIO[Any, Throwable, ?] ~> F): STM[F, A] = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't need an implicit.
final def fromTry[F[+ _], A](a: => Try[A])(implicit liftIO: ZIO[Any, Throwable, ?] ~> F): STM[F, A] = | ||
new STM(ZSTM.fromTry(a)) | ||
|
||
final def partial[F[+ _], A](a: => A)(implicit liftIO: ZIO[Any, Throwable, ?] ~> F): STM[F, A] = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't need an implicit.
final def partial[F[+ _], A](a: => A)(implicit liftIO: ZIO[Any, Throwable, ?] ~> F): STM[F, A] = | ||
fromTry(Try(a)) | ||
|
||
final def retry[F[+ _]](implicit liftIO: ZIO[Any, Throwable, ?] ~> F): STM[F, Nothing] = new STM(ZSTM.retry) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't need an implicit.
|
||
final def retry[F[+ _]](implicit liftIO: ZIO[Any, Throwable, ?] ~> F): STM[F, Nothing] = new STM(ZSTM.retry) | ||
|
||
final def succeedLazy[F[+ _], A](a: => A)(implicit liftIO: ZIO[Any, Throwable, ?] ~> F): STM[F, A] = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't need an implicit.
final def succeedLazy[F[+ _], A](a: => A)(implicit liftIO: ZIO[Any, Throwable, ?] ~> F): STM[F, A] = | ||
new STM(ZSTM.succeedLazy(a)) | ||
|
||
final def unit[F[+ _]](implicit liftIO: ZIO[Any, Throwable, ?] ~> F): STM[F, Unit] = succeed(()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't need an implicit.
import scalaz.zio.ZIO | ||
import scalaz.zio.stm.{ TRef => ZTRef } | ||
|
||
class TRef[F[+ _], A] private (underlying: ZTRef[A])(implicit liftIO: ZIO[Any, Throwable, ?] ~> F) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment here for the implicit FunctionK
. I'd delete that, make TRef
extend AnyVal
, and push the implicit Runtime[Any]
to the commit
method. I won't comment individually on these methods.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
|
||
object TRef { | ||
|
||
final def make[F[+ _], A](a: => A)(implicit liftIO: ZIO[Any, Throwable, ?] ~> F): STM[F, TRef[F, A]] = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This won't won't need an implicit.
final def make[F[+ _], A](a: => A)(implicit liftIO: ZIO[Any, Throwable, ?] ~> F): STM[F, TRef[F, A]] = | ||
new STM(ZTRef.make(a).map(new TRef(_))) | ||
|
||
final def makeCommit[F[+ _], A](a: => A)(implicit liftIO: ZIO[Any, Throwable, ?] ~> F): F[TRef[F, A]] = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This one will just need the implicit runtime.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is looking great! Just a minor comment on how we lift ZIO to some F[_], and once those changes are in, we should be good to merge. 🎉
/** | ||
* See [[scalaz.zio.stm.STM]] | ||
*/ | ||
final class STM[F[+ _], +A] private[stm] (private[stm] val underlying: ZSTM[Throwable, A]) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks super clean. I think you can extend AnyVal
here, too, now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would like to, but scala compiler has issue with nested AnyVal classes, actually it does not support this feature yet. I didn't find any workarounds at this point. Anyways I think AnyVal has a bunch of restrictions that could make all workarounds meaningless (e.g. passing underlying ZSTM as a trait or other type leads to allocation).
|
||
final def succeed[F[+ _], A](a: A): STM[F, A] = new STM(ZSTM.succeed(a)) | ||
|
||
final def atomically[F[+ _], A](stm: STM[F, A])(implicit R: Runtime[Any], A: Async[F]): F[A] = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Beautiful! Just this single method needs the implicit.
|
||
object TRef { | ||
|
||
final def make[F[+ _], A](a: => A): STM[F, TRef[F, A]] = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This all looks good to me! I'd just sort the methods alphabetically, then it looks good to merge! 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
Thanks @jdegoes! Please let me know if we need to add |
@VladKopanev That would be phenomenal! |
* Implement effect-polymorphic class atop STM zio#791 * Implement effect-polymorphic TRef zio#791 * remove unnecessary type parameters zio#791 * Add 'FunctionK' instance for converting TaskR to cats.IO zio#791 * Link to original documentation zio#791 * More efficient `collectAll` zio#791 * Make every method final zio#791 * Revert: Add 'FunctionK' instance for converting TaskR to cats.IO zio#791 (37d17db) * Push implicits down to atomically zio#791 * Reorder methods alphabetically zio#791 * Fix formatting zio#791
Cats Effect: STM & TRef #791