Skip to content

Commit 1e27699

Browse files
committed
Fixes
1 parent 09fb524 commit 1e27699

File tree

8 files changed

+83
-60
lines changed

8 files changed

+83
-60
lines changed

reactive/kotlinx-coroutines-jdk9/src/Await.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
package kotlinx.coroutines.jdk9
66

7-
import kotlinx.coroutines.Job
7+
import kotlinx.coroutines.*
88
import java.util.concurrent.*
99
import org.reactivestreams.FlowAdapters
1010
import kotlinx.coroutines.reactive.*

reactive/kotlinx-coroutines-jdk9/test/AwaitTest.kt

+3-4
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,8 @@
55
package kotlinx.coroutines.jdk9
66

77
import kotlinx.coroutines.*
8-
import kotlinx.coroutines.CancellationException
98
import org.junit.*
10-
import java.util.concurrent.*
9+
import java.util.concurrent.Flow as JFlow
1110

1211
class AwaitTest: TestBase() {
1312

@@ -16,8 +15,8 @@ class AwaitTest: TestBase() {
1615
@Test
1716
fun testAwaitCancellation() = runTest {
1817
expect(1)
19-
val publisher = Flow.Publisher<Int> { s ->
20-
s.onSubscribe(object : Flow.Subscription {
18+
val publisher = JFlow.Publisher<Int> { s ->
19+
s.onSubscribe(object : JFlow.Subscription {
2120
override fun request(n: Long) {
2221
expect(3)
2322
}

reactive/kotlinx-coroutines-reactive/src/Await.kt

+30-4
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import org.reactivestreams.Publisher
99
import org.reactivestreams.Subscriber
1010
import org.reactivestreams.Subscription
1111
import java.lang.IllegalStateException
12-
import kotlin.NoSuchElementException
1312
import kotlin.coroutines.*
1413

1514
/**
@@ -90,14 +89,23 @@ public suspend fun <T> Publisher<T>.awaitSingle(): T = awaitOne(Mode.SINGLE)
9089
* If the [Job] of the current coroutine is cancelled or completed while the suspending function is waiting, this
9190
* function immediately cancels its [Subscription] and resumes with [CancellationException].
9291
*
92+
* ### Deprecation
93+
*
94+
* This method is deprecated because the conventions established in Kotlin mandate that an operation with the name
95+
* `awaitSingleOrDefault` returns the default value instead of throwing in case there is an error; however, this would
96+
* also mean that this method would return the default value if there are *too many* values. This could be confusing to
97+
* those who expect this function to validate that there is a single element or none at all emitted, and cases where
98+
* there are no elements are indistinguishable from those where there are too many, though these cases have different
99+
* meaning.
100+
*
93101
* @throws NoSuchElementException if the publisher does not emit any value
94102
* @throws IllegalArgumentException if the publisher emits more than one value
95103
*/
96104
@Deprecated(
97105
message = "Deprecated without a replacement due to its name incorrectly conveying the behavior. " +
98106
"Please consider using awaitFirstOrDefault().",
99107
level = DeprecationLevel.WARNING
100-
)
108+
) // Warning since 1.5, error in 1.6, hidden in 1.7
101109
public suspend fun <T> Publisher<T>.awaitSingleOrDefault(default: T): T = awaitOne(Mode.SINGLE_OR_DEFAULT, default)
102110

103111
/**
@@ -109,6 +117,15 @@ public suspend fun <T> Publisher<T>.awaitSingleOrDefault(default: T): T = awaitO
109117
* If the [Job] of the current coroutine is cancelled or completed while the suspending function is waiting, this
110118
* function immediately cancels its [Subscription] and resumes with [CancellationException].
111119
*
120+
* ### Deprecation
121+
*
122+
* This method is deprecated because the conventions established in Kotlin mandate that an operation with the name
123+
* `awaitSingleOrNull` returns `null` instead of throwing in case there is an error; however, this would
124+
* also mean that this method would return `null` if there are *too many* values. This could be confusing to
125+
* those who expect this function to validate that there is a single element or none at all emitted, and cases where
126+
* there are no elements are indistinguishable from those where there are too many, though these cases have different
127+
* meaning.
128+
*
112129
* @throws IllegalArgumentException if the publisher emits more than one value
113130
*/
114131
@Deprecated(
@@ -117,7 +134,7 @@ public suspend fun <T> Publisher<T>.awaitSingleOrDefault(default: T): T = awaitO
117134
"Alternatively, please consider using awaitFirstOrNull().",
118135
level = DeprecationLevel.WARNING,
119136
replaceWith = ReplaceWith("this.awaitSingleOrNull()", "kotlinx.coroutines.reactor")
120-
)
137+
) // Warning since 1.5, error in 1.6, hidden in 1.7
121138
public suspend fun <T> Publisher<T>.awaitSingleOrNull(): T? = awaitOne(Mode.SINGLE_OR_DEFAULT)
122139

123140
/**
@@ -129,13 +146,22 @@ public suspend fun <T> Publisher<T>.awaitSingleOrNull(): T? = awaitOne(Mode.SING
129146
* If the [Job] of the current coroutine is cancelled or completed while the suspending function is waiting, this
130147
* function immediately cancels its [Subscription] and resumes with [CancellationException].
131148
*
149+
* ### Deprecation
150+
*
151+
* This method is deprecated because the conventions established in Kotlin mandate that an operation with the name
152+
* `awaitSingleOrElse` returns the calculated value instead of throwing in case there is an error; however, this would
153+
* also mean that this method would return the calculated value if there are *too many* values. This could be confusing
154+
* to those who expect this function to validate that there is a single element or none at all emitted, and cases where
155+
* there are no elements are indistinguishable from those where there are too many, though these cases have different
156+
* meaning.
157+
*
132158
* @throws IllegalArgumentException if the publisher emits more than one value
133159
*/
134160
@Deprecated(
135161
message = "Deprecated without a replacement due to its name incorrectly conveying the behavior. " +
136162
"Please consider using awaitFirstOrElse().",
137163
level = DeprecationLevel.WARNING
138-
)
164+
) // Warning since 1.5, error in 1.6, hidden in 1.7
139165
public suspend fun <T> Publisher<T>.awaitSingleOrElse(defaultValue: () -> T): T =
140166
awaitOne(Mode.SINGLE_OR_DEFAULT) ?: defaultValue()
141167

reactive/kotlinx-coroutines-reactor/src/Mono.kt

+21-43
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,7 @@ public suspend fun <T> Mono<T>.awaitSingleOrNull(): T? = suspendCancellableCorou
5353
}
5454

5555
override fun onComplete() {
56-
if (!seenValue)
57-
cont.resume(null)
56+
if (!seenValue) cont.resume(null)
5857
}
5958

6059
override fun onNext(t: T) {
@@ -136,87 +135,66 @@ public fun <T> CoroutineScope.mono(
136135
): Mono<T> = monoInternal(this, context, block)
137136

138137
/**
139-
* Awaits the first value from the given publisher without blocking the thread and returns the resulting value, or, if
140-
* the publisher has produced an error, throws the corresponding exception.
141-
*
142-
* This suspending function is cancellable.
143-
* If the [Job] of the current coroutine is cancelled or completed while the suspending function is waiting, this
144-
* function immediately cancels its [Subscription] and resumes with [CancellationException].
145-
*
146-
* @throws NoSuchElementException if the publisher does not emit any value
138+
* This function is deprecated in favor of [Mono.awaitSingle].
139+
* Both functions await the first value, or throw [NoSuchElementException] if there is none, but the name
140+
* [Mono.awaitSingle] better reflects the semantics of [Mono].
147141
*/
148142
@Deprecated(
149143
message = "Mono produces at most one value, so the semantics of dropping the remaining elements are not useful. " +
150144
"Please use awaitSingle() instead.",
151145
level = DeprecationLevel.WARNING,
152146
replaceWith = ReplaceWith("this.awaitSingle()")
153-
)
147+
) // Warning since 1.5, error in 1.6, hidden in 1.7
154148
public suspend fun <T> Mono<T>.awaitFirst(): T = awaitSingle()
155149

156150
/**
157-
* Awaits the first value from the given publisher, or returns the [default] value if none is emitted, without blocking
158-
* the thread, and returns the resulting value, or, if this publisher has produced an error, throws the corresponding
159-
* exception.
160-
*
161-
* This suspending function is cancellable.
162-
* If the [Job] of the current coroutine is cancelled or completed while the suspending function is waiting, this
163-
* function immediately cancels its [Subscription] and resumes with [CancellationException].
151+
* This function is deprecated in favor of [Mono.awaitSingleOrNull].
152+
* Both functions await the first value or return some special value if there is none, but the name
153+
* [Mono.awaitSingleOrNull] better reflects the semantics of [Mono] than an operation with a "first" in its name.
164154
*/
165155
@Deprecated(
166156
message = "Mono produces at most one value, so the semantics of dropping the remaining elements are not useful. " +
167157
"Please use awaitSingleOrNull() instead.",
168158
level = DeprecationLevel.WARNING,
169159
replaceWith = ReplaceWith("this.awaitSingleOrNull() ?: default")
170-
)
160+
) // Warning since 1.5, error in 1.6, hidden in 1.7
171161
public suspend fun <T> Mono<T>.awaitFirstOrDefault(default: T): T = awaitSingleOrNull() ?: default
172162

173163
/**
174-
* Awaits the first value from the given publisher, or returns `null` if none is emitted, without blocking the thread,
175-
* and returns the resulting value, or, if this publisher has produced an error, throws the corresponding exception.
176-
*
177-
* This suspending function is cancellable.
178-
* If the [Job] of the current coroutine is cancelled or completed while the suspending function is waiting, this
179-
* function immediately cancels its [Subscription] and resumes with [CancellationException].
164+
* This function is deprecated in favor of [Mono.awaitSingleOrNull].
165+
* Both functions await the first value or return some special value if there is none, but the name
166+
* [Mono.awaitSingleOrNull] better reflects the semantics of [Mono].
180167
*/
181168
@Deprecated(
182169
message = "Mono produces at most one value, so the semantics of dropping the remaining elements are not useful. " +
183170
"Please use awaitSingleOrNull() instead.",
184171
level = DeprecationLevel.WARNING,
185172
replaceWith = ReplaceWith("this.awaitSingleOrNull()")
186-
)
173+
) // Warning since 1.5, error in 1.6, hidden in 1.7
187174
public suspend fun <T> Mono<T>.awaitFirstOrNull(): T? = awaitSingleOrNull()
188175

189176
/**
190-
* Awaits the first value from the given publisher, or calls [defaultValue] to get a value if none is emitted, without
191-
* blocking the thread, and returns the resulting value, or, if this publisher has produced an error, throws the
192-
* corresponding exception.
193-
*
194-
* This suspending function is cancellable.
195-
* If the [Job] of the current coroutine is cancelled or completed while the suspending function is waiting, this
196-
* function immediately cancels its [Subscription] and resumes with [CancellationException].
177+
* This function is deprecated in favor of [Mono.awaitSingleOrNull].
178+
* Both functions await the first value or return some special value if there is none, but the name
179+
* [Mono.awaitSingleOrNull] better reflects the semantics of [Mono] than an operation with a "first" in its name.
197180
*/
198181
@Deprecated(
199182
message = "Mono produces at most one value, so the semantics of dropping the remaining elements are not useful. " +
200183
"Please use awaitSingleOrNull() instead.",
201184
level = DeprecationLevel.WARNING,
202185
replaceWith = ReplaceWith("this.awaitSingleOrNull() ?: defaultValue()")
203-
)
186+
) // Warning since 1.5, error in 1.6, hidden in 1.7
204187
public suspend fun <T> Mono<T>.awaitFirstOrElse(defaultValue: () -> T): T = awaitSingleOrNull() ?: defaultValue()
205188

206189
/**
207-
* Awaits the last value from the given publisher without blocking the thread and
208-
* returns the resulting value, or, if this publisher has produced an error, throws the corresponding exception.
209-
*
210-
* This suspending function is cancellable.
211-
* If the [Job] of the current coroutine is cancelled or completed while the suspending function is waiting, this
212-
* function immediately cancels its [Subscription] and resumes with [CancellationException].
213-
*
214-
* @throws NoSuchElementException if the publisher does not emit any value
190+
* This function is deprecated in favor of [Mono.awaitSingle].
191+
* Both functions await the only value or return some special value if there is none, but the name
192+
* "awaitLast" strongly suggests that there is more than one value, which is not the case.
215193
*/
216194
@Deprecated(
217195
message = "Mono produces at most one value, so the last element is the same as the first. " +
218196
"Please use awaitSingle() instead.",
219197
level = DeprecationLevel.WARNING,
220198
replaceWith = ReplaceWith("this.awaitSingle()")
221-
)
199+
) // Warning since 1.5, error in 1.6, hidden in 1.7
222200
public suspend fun <T> Mono<T>.awaitLast(): T = awaitSingle()

reactive/kotlinx-coroutines-rx2/src/RxAwait.kt

+12-2
Original file line numberDiff line numberDiff line change
@@ -71,12 +71,17 @@ public suspend fun <T> MaybeSource<T>.awaitSingle(): T = awaitSingleOrNull() ?:
7171
* This suspending function is cancellable.
7272
* If the [Job] of the current coroutine is cancelled or completed while this suspending function is waiting, this function
7373
* immediately resumes with [CancellationException].
74+
*
75+
* ### Deprecation
76+
*
77+
* Deprecated in favor of [awaitSingleOrNull] in order to reflect that `null` can be returned to denote the absence of
78+
* a value, as opposed to throwing in such case.
7479
*/
7580
@Deprecated(
7681
message = "Deprecated in favor of awaitSingleOrNull()",
7782
level = DeprecationLevel.WARNING,
7883
replaceWith = ReplaceWith("this.awaitSingleOrNull()")
79-
)
84+
) // Warning since 1.5, error in 1.6, hidden in 1.7
8085
public suspend fun <T> MaybeSource<T>.await(): T? = awaitSingleOrNull()
8186

8287
/**
@@ -87,12 +92,17 @@ public suspend fun <T> MaybeSource<T>.await(): T? = awaitSingleOrNull()
8792
* This suspending function is cancellable.
8893
* If the [Job] of the current coroutine is cancelled or completed while this suspending function is waiting, this function
8994
* immediately resumes with [CancellationException].
95+
*
96+
* ### Deprecation
97+
*
98+
* Deprecated in favor of [awaitSingleOrNull] for naming consistency (see the deprecation of [MaybeSource.await] for
99+
* details).
90100
*/
91101
@Deprecated(
92102
message = "Deprecated in favor of awaitSingleOrNull()",
93103
level = DeprecationLevel.WARNING,
94104
replaceWith = ReplaceWith("this.awaitSingleOrNull() ?: default")
95-
)
105+
) // Warning since 1.5, error in 1.6, hidden in 1.7
96106
public suspend fun <T> MaybeSource<T>.awaitOrDefault(default: T): T = awaitSingleOrNull() ?: default
97107

98108
// ------------------------ SingleSource ------------------------

reactive/kotlinx-coroutines-rx2/test/MaybeTest.kt

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@ import io.reactivex.disposables.*
99
import io.reactivex.exceptions.*
1010
import io.reactivex.internal.functions.Functions.*
1111
import kotlinx.coroutines.*
12+
import kotlinx.coroutines.CancellationException
1213
import org.junit.*
1314
import org.junit.Test
1415
import java.util.concurrent.*
15-
import java.util.concurrent.CancellationException as jCancellationException
1616
import kotlin.test.*
1717

1818
class MaybeTest : TestBase() {
@@ -235,7 +235,7 @@ class MaybeTest : TestBase() {
235235
expect(4)
236236
try {
237237
delay(Long.MAX_VALUE)
238-
} catch (e: jCancellationException) {
238+
} catch (e: CancellationException) {
239239
expect(6)
240240
}
241241
42

reactive/kotlinx-coroutines-rx3/src/RxAwait.kt

+12-2
Original file line numberDiff line numberDiff line change
@@ -71,12 +71,17 @@ public suspend fun <T> MaybeSource<T>.awaitSingle(): T = awaitSingleOrNull() ?:
7171
* This suspending function is cancellable.
7272
* If the [Job] of the current coroutine is cancelled or completed while this suspending function is waiting, this function
7373
* immediately resumes with [CancellationException].
74+
*
75+
* ### Deprecation
76+
*
77+
* Deprecated in favor of [awaitSingleOrNull] in order to reflect that `null` can be returned to denote the absence of
78+
* a value, as opposed to throwing in such case.
7479
*/
7580
@Deprecated(
7681
message = "Deprecated in favor of awaitSingleOrNull()",
7782
level = DeprecationLevel.WARNING,
7883
replaceWith = ReplaceWith("this.awaitSingleOrNull()")
79-
)
84+
) // Warning since 1.5, error in 1.6, hidden in 1.7
8085
public suspend fun <T> MaybeSource<T>.await(): T? = awaitSingleOrNull()
8186

8287
/**
@@ -87,12 +92,17 @@ public suspend fun <T> MaybeSource<T>.await(): T? = awaitSingleOrNull()
8792
* This suspending function is cancellable.
8893
* If the [Job] of the current coroutine is cancelled or completed while this suspending function is waiting, this function
8994
* immediately resumes with [CancellationException].
95+
*
96+
* ### Deprecation
97+
*
98+
* Deprecated in favor of [awaitSingleOrNull] for naming consistency (see the deprecation of [MaybeSource.await] for
99+
* details).
90100
*/
91101
@Deprecated(
92102
message = "Deprecated in favor of awaitSingleOrNull()",
93103
level = DeprecationLevel.WARNING,
94104
replaceWith = ReplaceWith("this.awaitSingleOrNull() ?: default")
95-
)
105+
) // Warning since 1.5, error in 1.6, hidden in 1.7
96106
public suspend fun <T> MaybeSource<T>.awaitOrDefault(default: T): T = awaitSingleOrNull() ?: default
97107

98108
// ------------------------ SingleSource ------------------------

reactive/kotlinx-coroutines-rx3/test/MaybeTest.kt

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@ import io.reactivex.rxjava3.disposables.*
99
import io.reactivex.rxjava3.exceptions.*
1010
import io.reactivex.rxjava3.internal.functions.Functions.*
1111
import kotlinx.coroutines.*
12+
import kotlinx.coroutines.CancellationException
1213
import org.junit.*
1314
import org.junit.Test
1415
import java.util.concurrent.*
15-
import java.util.concurrent.CancellationException as jCancellationException
1616
import kotlin.test.*
1717

1818
class MaybeTest : TestBase() {
@@ -235,7 +235,7 @@ class MaybeTest : TestBase() {
235235
expect(4)
236236
try {
237237
delay(Long.MAX_VALUE)
238-
} catch (e: jCancellationException) {
238+
} catch (e: CancellationException) {
239239
expect(6)
240240
}
241241
42

0 commit comments

Comments
 (0)