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
flatMap
cancels all involved futures
#390
Conversation
Error in Travis is because of binary incompatibility. I wasn't aware that returning a more specific type could cause this. |
Codecov Report
@@ Coverage Diff @@
## master #390 +/- ##
==========================================
+ Coverage 87.49% 87.66% +0.16%
==========================================
Files 293 293
Lines 8114 8112 -2
Branches 1156 1149 -7
==========================================
+ Hits 7099 7111 +12
+ Misses 1015 1001 -14 |
@@ -115,18 +116,28 @@ object FutureUtils { | |||
* | |||
* Similar to `Future.transformWith` from Scala 2.12. | |||
*/ | |||
def transformWith[A,B](source: Future[A], f: Try[A] => Future[B])(implicit ec: ExecutionContext): Future[B] = { | |||
def transformWith[A,B](source: Future[A], f: Try[A] => Future[B])(implicit ec: ExecutionContext): CancelableFuture[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.
Chiming in since asked on twitter https://twitter.com/ktosopl/status/892221038242570240
This is binary incompatible, MiMa is right.
Changing the type like this will cause NoSuchMethodError
.
Simple way to test those things if you think MiMa may be mistaken:
$ ls *scala
it.scala lol.scala main.scala
ktoso @ 三日月/tmp
$ cat *scala
object f { def f(): A = null }
trait A
trait B extends A
object Main extends App {
val a = f.f()
}
ktoso @ 三日月/tmp
$ scalac *.scala
ktoso @ 三日月/tmp
$ java -cp /Users/ktoso/.ivy2/cache/org.scala-lang/scala-library/jars/scala-library-2.12.2.jar:. Main
ktoso @ 三日月/tmp
$ vim it.scala
ktoso @ 三日月/tmp
$ scalac it.scala
ktoso @ 三日月/tmp
$ cat it.scala
object f { def f(): B = null }
ktoso @ 三日月/tmp
$ java -cp /Users/ktoso/.ivy2/cache/org.scala-lang/scala-library/jars/scala-library-2.12.2.jar:. Main
Exception in thread "main" java.lang.NoSuchMethodError: f$.f()LA;
Hope this helps
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.
Yeah, it helps. I'll have to rework this change to make it binary compatible.
@alexandru WDYT?
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.
Sounds like good timing if you can break now 👍
@larsrh this change is for master and master has upgraded to depending on cats-core directly. This means that binary compatibility is already broken heavily, because This is why we have a big list of incompatibilities documented for 3.0.0. So don't worry about it. If there's a time to break binary compatibility, it is now. |
p.future | ||
|
||
source match { | ||
case c: Cancelable => cancelable.orderedUpdate(c, order = 1) |
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 correct, but you already have source
when initializing your val cancelable
so it might be a better idea to initialize that as MultiAssignmentCancelable(source)
(thus source
being an initial underlying reference), because we avoid doing an Atomic.compareAndSet
that way.
And so instead of the second orderedUpdate(order = 2)
, you can just use :=
, because orderedUpdate
also implies some extra logic.
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.
Will update accordingly.
@@ -161,6 +172,10 @@ object FutureUtils { | |||
p.future | |||
} | |||
|
|||
/** Creates a future that never completes. */ | |||
def never[A]: Future[A] = | |||
Promise[A].future |
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.
Since I got notified since I chimed in about the MiMa thing thought I'll share some insight here too. Feel free to tell me to go away if you'd prefer that :-)
I would say 👎, since this can create memory leaks in the form of callbacks registered on this future, which will never trigger, however still will be registered and kept in memory.
Explanations: http://viktorklang.com/blog/Futures-in-Scala-2.12-part-6.html
Scala 2.12 solution: https://github.com/scala/scala/blob/2.12.x/src/library/scala/concurrent/Future.scala#L561
Sneaky little edge case, isn't 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 only use this for testing. I could move this to the test suite, such that nobody will accidentally use 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.
The other option would be copy-pasting this from Scala into Monix, but I'm not sure whether that's a good idea.
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.
Yeah if it's just in tests then ok I guess, would move it out from src/main though then. Your call :)
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.
OH, I now see that it is basically never
from Scala 2.12. Nice.
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.
@alexandru I'll use that, then.
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.
But then never
from Scala 2.12 overrides everything else, e.g. flatMap
.
@ktoso If we aren't overriding the other methods likeflatMap
, I think that represents a potential memory leak as well.
@larsrh we might need to do a Scala 2.11 specific object (in a scala_2.11
directory) and just rely on Scala's never
for 2.12.
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.
@ktoso sorry for the noise, just wanted to mention that your input is greatly appreciated. Thanks.
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 problem, cheers!
I've addressed all feedback & Travis is green. |
@alexandru Are you planning to release milestone builds of 3.0.0? |
@larsrh yes, snapshots get published automatically whenever I merge master into I started a new build, when finished you should have a new version published if you want to play: https://travis-ci.org/monix/monix/builds/259733983 |
Your publish script might be failing:
(see build log) |
@larsrh unfortunately I've been having issues due to tooling, like Coursier, not recognizing empty projects (i.e. projects where the POM itself is the artifact,with no JAR file) and the root monix project is one. Cannot reproduce it locally, but I've just pushed an attempted fix for it, a build is in progress: https://travis-ci.org/monix/monix/builds/259961033 |
@larsrh the latest build succeeded after those fixes, you should see |
Indeed, thanks! |
Fixes #381