Skip to content
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

Rename alt and altAll to or and awaitFirst #44

Merged
merged 3 commits into from
Mar 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions shared/src/main/scala/async/futures.scala
Original file line number Diff line number Diff line change
Expand Up @@ -200,14 +200,14 @@ object Future:
/** Alternative parallel composition of this task with `other` task. If either task succeeds, succeed with the
* success that was returned first. Otherwise, fail with the failure that was returned last.
*/
def alt(f2: Future[T]): Future[T] = altImpl(false)(f2)
def or(f2: Future[T]): Future[T] = orImpl(false)(f2)

/** Like `alt` but the slower future is cancelled. If either task succeeds, succeed with the success that was
/** Like `or` but the slower future is cancelled. If either task succeeds, succeed with the success that was
* returned first and the other is cancelled. Otherwise, fail with the failure that was returned last.
*/
def altWithCancel(f2: Future[T]): Future[T] = altImpl(true)(f2)
def orWithCancel(f2: Future[T]): Future[T] = orImpl(true)(f2)

inline def altImpl(inline withCancel: Boolean)(f2: Future[T]): Future[T] = Future.withResolver: r =>
inline def orImpl(inline withCancel: Boolean)(f2: Future[T]): Future[T] = Future.withResolver: r =>
Async
.raceWithOrigin(f1, f2)
.onComplete(Listener { case ((v, which), _) =>
Expand Down Expand Up @@ -327,12 +327,12 @@ object Future:

/** Race all futures, returning the first successful value. Throws the last exception received, if everything fails.
*/
def altAll(using Async): T = altImpl(false)
def awaitFirst(using Async): T = awaitFirstImpl(false)

/** Like [[altAll]], but cancels all other futures as soon as the first future succeeds. */
def altAllWithCancel(using Async): T = altImpl(true)
/** Like [[awaitFirst]], but cancels all other futures as soon as the first future succeeds. */
def awaitFirstWithCancel(using Async): T = awaitFirstImpl(true)

private inline def altImpl(withCancel: Boolean)(using Async): T =
private inline def awaitFirstImpl(withCancel: Boolean)(using Async): T =
val collector = Collector(fs*)
@scala.annotation.tailrec
def loop(attempt: Int): T =
Expand Down
32 changes: 16 additions & 16 deletions shared/src/test/scala/FutureBehavior.scala
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,11 @@ class FutureBehavior extends munit.FunSuite {
assert(false); 1
}
val res = c
.alt(Future {
.or(Future {
val res = a.await + b.await
res
})
.alt(c)
.or(c)
natsukagami marked this conversation as resolved.
Show resolved Hide resolved
.await
res
val y = Future:
Expand All @@ -51,7 +51,7 @@ class FutureBehavior extends munit.FunSuite {
val b = Future {
true
}
val res = a.alt(b).await
val res = a.or(b).await
res
val _: Future[Int | Boolean] = z
assertEquals(x.await, 33)
Expand Down Expand Up @@ -82,26 +82,26 @@ class FutureBehavior extends munit.FunSuite {
assertEquals(f.await, 55)
}

test("alt") {
test("or") {
Async.blocking:
val error = new AssertionError()
val fail = Future.now(Failure(error))
val fail1 = Future.now(Failure(error))
val succeed = Future.now(Success(13))

assert(Set(10, 20).contains(Future { 10 }.alt(Future { 20 }).await))
assertEquals(fail.alt(succeed).await, 13)
assertEquals(succeed.alt(fail).await, 13)
assertEquals(fail.alt(fail1).awaitResult, Failure(error))
assert(Set(10, 20).contains(Future { 10 }.or(Future { 20 }).await))
assertEquals(fail.or(succeed).await, 13)
assertEquals(succeed.or(fail).await, 13)
assertEquals(fail.or(fail1).awaitResult, Failure(error))
}

test("altC of 2 futures") {
test("orWithCancel of 2 futures") {
Async.blocking:
var touched = 0
Future {
sleep(200)
touched += 1
}.alt(Future {
}.or(Future {
10
}).awaitResult
sleep(300)
Expand All @@ -111,7 +111,7 @@ class FutureBehavior extends munit.FunSuite {
Future {
sleep(200)
touched += 1
}.altWithCancel(Future { 10 }).awaitResult
}.orWithCancel(Future { 10 }).awaitResult
sleep(300)
assertEquals(touched, 0)
}
Expand Down Expand Up @@ -414,23 +414,23 @@ class FutureBehavior extends munit.FunSuite {
assert(!lastFutureFinished)
}

test("future collection: altAll*") {
test("future collection: awaitFirst*") {
Async.blocking:
val range = (0 to 10)
def futs = range.map(i => Future { sleep(i * 100); i })
assert(range contains futs.altAll)
assert(range contains futs.awaitFirst)

val exc = new Exception("a")
def futsWithFail = futs ++ Seq(Future { throw exc })
assert(range contains futsWithFail.altAll)
assert(range contains futsWithFail.awaitFirst)

val excs = range.map(i => new Exception(i.toString()))
def futsAllFail = range.zip(excs).map((i, exc) => Future { sleep(i * 100); throw exc })
assertEquals(Try(futsAllFail.altAll), Failure(excs.last))
assertEquals(Try(futsAllFail.awaitFirst), Failure(excs.last))

var lastFutureFinished = false
def futsWithSleepy = futsWithFail ++ Seq(Future { sleep(200000); lastFutureFinished = true; 0 })
assert(range contains futsWithSleepy.altAll)
assert(range contains futsWithSleepy.awaitFirst)
assert(!lastFutureFinished)
}

Expand Down
2 changes: 1 addition & 1 deletion shared/src/test/scala/SourceBehavior.scala
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ class SourceBehavior extends munit.FunSuite {
assertEquals(bRan.poll(), None)
f.await
Thread.sleep(100) // onComplete of await and manual may be scheduled
aRan.zip(bRan).alt(Future(sleep(600))).await
aRan.zip(bRan).or(Future(sleep(600))).await
}

test("either") {
Expand Down
Loading