-
Notifications
You must be signed in to change notification settings - Fork 529
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
MVar: add "tryRead" fixes #732 #739
Conversation
The implementation looks fantastic here! Thank you! The problem (and the reason the build failed) is binary compatibility. I should have thought of that earlier, but basically it stems from the fact that |
Deprecate and rename |
@djspiewak Thanks for looking into it! I haven't checked the implementation of If we want to leave the current What do you think? |
We could in theory define a new trait, I'm not sure if there is another meaningful approach here. The name thing is kind of annoying, and maybe we can come up with something better than |
💯 to Daniel's last point about |
Agreed. @kubum would you like to take a crack at restructuring this change to use the |
Sounds good to me, thank you! I'll do it and ping you in the discussion for another review if you wouldn't mind. |
Sounds perfect! |
6d649b3
to
bb87b2d
Compare
@djspiewak thanks! I updated the PR. Could let me know is it something you had in mind? I couldn't add |
The silencer plugin can help with that deprecation issue. |
@rossabaker thanks for the link! I wasn't sure if adding a dependency was appropriate. Just pushed a separate commit with the silencer. Have a look, and please let me know what you think. I am happy to keep it or remove it. I added silencer under a separate |
9bbfcff
to
9b86716
Compare
Yes, I think silencer is an appropriate addition, and the only way we can get the experience we want without turning off fatal warnings or breaking binary compatibility. It looks like we also need to silence some references in tests. |
4310daf
to
a7df3b5
Compare
@rossabaker Well spotted, I just updated the PR. What do you think? Thank you! |
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.
Thanks! The code looks good to me. Docs need a little more mopup.
I milestoned this as 2.2.0 for proper semver, but the version number is negotiable.
If we still want to add swap
, we should do it here, or be sure it gets done before we release again, or else we'll have an MVar3
and be doing this dance again. Are any other methods missing?
a7df3b5
to
0a9b094
Compare
Thanks for the review @rossabaker! I added "swap" with tests too. Please have a look and let me know what you think. |
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.
Thanks for looking into it! I haven't checked the implementation of MVar in Monix. Surprisingly, it already has tryRead implemented.
@kubum yes, Monix's implementation has tryRead
. This must have happened after we released Cats-Effect 1.0.0 and as you can see, adding new methods ain't easy.
In the next Cats-Effect I'm thinking that these shouldn't be abstract classes, because it prevents us from adding new methods. And there's not much value in maintaining different implementations in a project like Monix. I'm also thinking that these should be in a sub-project separate from the core exposing the type classes (e.g. cats-effect-data
or something) but I digress.
build.sbt
Outdated
@@ -238,6 +239,10 @@ lazy val core = crossProject(JSPlatform, JVMPlatform) | |||
"org.typelevel" %%% "cats-laws" % CatsVersion % Test, | |||
"org.typelevel" %%% "discipline-scalatest" % DisciplineScalatestVersion % Test | |||
), | |||
libraryDependencies ++= Seq( | |||
compilerPlugin(("com.github.ghik" % "silencer-plugin" % SilencerVersion).cross(CrossVersion.full)), | |||
("com.github.ghik" % "silencer-lib" % SilencerVersion % Provided).cross(CrossVersion.full) |
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 like provided libs, because they end up in the generated pom.xml
anyway. Would be cool to have a setup that filters these out.
I'm using something like this:
/**
* Filter out dependencies from the generated `pom.xml`.
*
* E.g. to exclude Scoverage:
* {{{
* filterOutDependencyFromGeneratedPomXml("groupId" -> "org\\.scoverage".r)
* }}}
*
* Or to exclude based on both `groupId` and `artifactId`:
* {{{
* filterOutDependencyFromGeneratedPomXml("groupId" -> "io\\.estatico".r, "artifactId" -> "newtype".r)
* }}}
*/
def filterOutDependencyFromGeneratedPomXml(conditions: (String, Regex)*) = {
def shouldExclude(e: Elem) =
e.label == "dependency" && {
conditions.forall { case (key, regex) =>
e.child.exists(child => child.label == key && regex.findFirstIn(child.text).isDefined)
}
}
if (conditions.isEmpty) Nil else {
Seq(
pomPostProcess := { (node: xml.Node) =>
new RuleTransformer(new RewriteRule {
override def transform(node: xml.Node): Seq[xml.Node] = node match {
case e: Elem if shouldExclude(e) => Nil
case _ => Seq(node)
}
}).transform(node).head
},
)
}
}
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.
Ah, I didn't know "provided" still keeps it in the pom.xml
. Thank you, this snipper is amazing. I added it to a separate file and called it to exclude both: "scoverage" and "silencer". What do you think?
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.
👍
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 think we already have something a bit like this with the CompileOnly
scope, or something like that. I can't remember. We used it for simulacrum.
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.
Simulacrum is still Provided
in cats, with a similar pom-stripping trick to this. Maybe @djspiewak is thinking of the @compileTimeOnly
annotation?
@@ -119,6 +123,36 @@ abstract class MVar[F[_], A] { | |||
new TransformedMVar(this, f) | |||
} | |||
|
|||
/** | |||
* The `MVar2` is the successor of `MVar` with [[tryRead]] and [[swap]]. It was implemented separately only to maintain | |||
* binary compatibility with `MVar`. |
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.
We want to provide good ScalaDocs. I wonder what we can do here, because people are going to be looking at the description of MVar2
, which has this sentence that has technical implementation details and with no link to MVar
. And then if they'll take a look at the ScalaDoc for MVar
, they'll see it as being deprecated.
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.
Good point. It seems there are two ways:
- Reference both. The downside of it is that tools (IDE helpers) won't give the relevant docs immediately.
- Copy docs from
MVar
toMVar2
. The downside is maintaining the two copies.
Are there something else? What do you think?
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.
You can define reusable documentation via @define
in ScalaDoc.
And definitions get inherited, so if you @define
something on MVar
, it should then be available in MVar2
. And a trick would be to do something like ...
/**
* @define mvarDescription An MVar is a mutable location that can be empty or
* contain a value, asynchronously blocking reads when empty and
* blocking writes when full.
*
* Use-cases:
* - bla bla ...
*/
private[concurrent] trait MVarDocs extends Any {}
/**
* $mvarDescription
*/
abstract class MVar[F[_], A] extends MVarDocs
/**
* $mvarDescription
*/
abstract class MVar2[F[_], A] extends MVar[F, A]
It's just a template value, so you can add your warning before or after 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.
Ah, it is a great suggestion, thank you. I just added it.
I have tried to avoid the redundant trait
, but scaladocs kept crashing with expansion errors.
Motivation: - "provided" does not remove dependencies from a pom.xml - use a snippet from typelevel#739 to exclude undesired dependencies - apply PomFilter to exlude scoverage too.
Motivation: - "provided" does not remove dependencies from a pom.xml - use a snippet from typelevel#739 to exclude undesired dependencies - apply PomFilter to exlude scoverage too.
9fab372
to
23b8138
Compare
Motivation: - "provided" does not remove dependencies from a pom.xml - use a snippet from typelevel#739 to exclude undesired dependencies - apply PomFilter to exlude scoverage too.
23b8138
to
746d5f1
Compare
Ping @rossabaker? I defer to you on all of this. :-) |
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 looks good to me. I've never used MVar
, so I'm not the most qualified, but I note a few functions that are missing compared to the Haskell version:
withMVar
modifyMVar_
modifyMVar
We don't use MVar
in the method names, and might rename withMVar
to use
since with
is a keyword.
The only reason I bring them up now is that adding them later would result in an MVar3
. We could do it in a separate PR, but we should do it before 2.2.0 if we think we might want those.
build.sbt
Outdated
@@ -238,6 +239,10 @@ lazy val core = crossProject(JSPlatform, JVMPlatform) | |||
"org.typelevel" %%% "cats-laws" % CatsVersion % Test, | |||
"org.typelevel" %%% "discipline-scalatest" % DisciplineScalatestVersion % Test | |||
), | |||
libraryDependencies ++= Seq( | |||
compilerPlugin(("com.github.ghik" % "silencer-plugin" % SilencerVersion).cross(CrossVersion.full)), | |||
("com.github.ghik" % "silencer-lib" % SilencerVersion % Provided).cross(CrossVersion.full) |
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.
Simulacrum is still Provided
in cats, with a similar pom-stripping trick to this. Maybe @djspiewak is thinking of the @compileTimeOnly
annotation?
Actually I was thinking of this: https://github.com/typelevel/cats-effect/blob/master/build.sbt#L28 So in other words, if you swap |
Hi @djspiewak, I wonder if you know the answer, but when I swap
but
Do you know a way to make |
Modification: - add `tryRead: F[Option[A]]` similar to Control-Concurrent-MVar#tryRead - add `swap(newValue: A): F[A]` similar to Control-Concurrent-MVar#swapMVar - add a test and a line into the docs - add MVar2 to keep binary compatibility with MVar
Motivation: - "provided" does not remove dependencies from a pom.xml - use a snippet from typelevel#739 to exclude undesired dependencies - apply PomFilter to exlude scoverage too.
Just updated the doc and rebased. I couldn't make |
I had the same problem in http4s last night trying to use |
When it's in libraryDependencies ++= Seq(
compilerPlugin(("com.github.ghik" % "silencer-plugin" % SilencerVersion).cross(CrossVersion.full)),
("com.github.ghik" % "silencer-lib" % SilencerVersion % CompileTime).cross(CrossVersion.full),
("com.github.ghik" % "silencer-lib" % SilencerVersion % Test).cross(CrossVersion.full)
), For whatever it's worth, @kubum has done great work on this, and I'd like to see us get it merged ASAP. I'll add a follow-up ticket to get the other relevant methods from |
Motivation: Add "deprecated" warnings for the users, but avoid compilation errors when used internally for the period of migration. Modification: - Add sbt silencer to `build.sbt` - Deprecate `MVar` and promote `MVar2`
@rossabaker Your idea worked fantastic! I just removed the last commit with the pom filter, bumped silencer to 1.6.0 and followed the suggested way to include both in test and compile time. Thank you! |
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.
👍 on green.
Terribly sorry for missing this! I didn't notice the approval. 🎉 |
Thank you so much for following this through, @kubum! |
Motivation:
I found an open good first issue #732 while reading about
MVar
. This branch contains an attempt to implement it.Modification:
tryRead: F[Option[A]]
similar to Control-Concurrent-MVar#tryReadI wonder does it do what is it intended to do? I am happy to amend it if I've missed something, suggestions are welcome. Thank you!