Skip to content

Commit 5c8e650

Browse files
authored
Increase the deprecation levels for BroadcastChannel APIs (#4197)
1 parent d010110 commit 5c8e650

21 files changed

+47
-182
lines changed

benchmarks/src/jmh/kotlin/benchmarks/scheduler/StatefulAwaitsBenchmark.kt

+1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ import java.util.concurrent.*
4040
@BenchmarkMode(Mode.AverageTime)
4141
@OutputTimeUnit(TimeUnit.MICROSECONDS)
4242
@State(Scope.Benchmark)
43+
@Suppress("DEPRECATION_ERROR")
4344
open class StatefulAsyncBenchmark : ParametrizedDispatcherBase() {
4445

4546
private val stateSize = 2048

kotlinx-coroutines-core/api/kotlinx-coroutines-core.api

-1
Original file line numberDiff line numberDiff line change
@@ -987,7 +987,6 @@ public final class kotlinx/coroutines/flow/FlowKt {
987987
public static final fun asFlow (Lkotlin/ranges/IntRange;)Lkotlinx/coroutines/flow/Flow;
988988
public static final fun asFlow (Lkotlin/ranges/LongRange;)Lkotlinx/coroutines/flow/Flow;
989989
public static final fun asFlow (Lkotlin/sequences/Sequence;)Lkotlinx/coroutines/flow/Flow;
990-
public static final fun asFlow (Lkotlinx/coroutines/channels/BroadcastChannel;)Lkotlinx/coroutines/flow/Flow;
991990
public static final fun asFlow ([I)Lkotlinx/coroutines/flow/Flow;
992991
public static final fun asFlow ([J)Lkotlinx/coroutines/flow/Flow;
993992
public static final fun asFlow ([Ljava/lang/Object;)Lkotlinx/coroutines/flow/Flow;

kotlinx-coroutines-core/api/kotlinx-coroutines-core.klib.api

-1
Original file line numberDiff line numberDiff line change
@@ -825,7 +825,6 @@ final fun <#A: kotlin/Any?> (kotlin.coroutines/SuspendFunction0<#A>).kotlinx.cor
825825
final fun <#A: kotlin/Any?> (kotlin.sequences/Sequence<#A>).kotlinx.coroutines.flow/asFlow(): kotlinx.coroutines.flow/Flow<#A> // kotlinx.coroutines.flow/asFlow|[email protected]<0:0>(){0§<kotlin.Any?>}[0]
826826
final fun <#A: kotlin/Any?> (kotlin/Array<#A>).kotlinx.coroutines.flow/asFlow(): kotlinx.coroutines.flow/Flow<#A> // kotlinx.coroutines.flow/asFlow|[email protected]<0:0>(){0§<kotlin.Any?>}[0]
827827
final fun <#A: kotlin/Any?> (kotlin/Function0<#A>).kotlinx.coroutines.flow/asFlow(): kotlinx.coroutines.flow/Flow<#A> // kotlinx.coroutines.flow/asFlow|[email protected]<0:0>(){0§<kotlin.Any?>}[0]
828-
final fun <#A: kotlin/Any?> (kotlinx.coroutines.channels/BroadcastChannel<#A>).kotlinx.coroutines.flow/asFlow(): kotlinx.coroutines.flow/Flow<#A> // kotlinx.coroutines.flow/asFlow|[email protected]<0:0>(){0§<kotlin.Any?>}[0]
829828
final fun <#A: kotlin/Any?> (kotlinx.coroutines.channels/ReceiveChannel<#A>).kotlinx.coroutines.channels/broadcast(kotlin/Int = ..., kotlinx.coroutines/CoroutineStart = ...): kotlinx.coroutines.channels/BroadcastChannel<#A> // kotlinx.coroutines.channels/broadcast|[email protected]<0:0>(kotlin.Int;kotlinx.coroutines.CoroutineStart){0§<kotlin.Any?>}[0]
830829
final fun <#A: kotlin/Any?> (kotlinx.coroutines.channels/ReceiveChannel<#A>).kotlinx.coroutines.channels/distinct(): kotlinx.coroutines.channels/ReceiveChannel<#A> // kotlinx.coroutines.channels/distinct|[email protected]<0:0>(){0§<kotlin.Any?>}[0]
831830
final fun <#A: kotlin/Any?> (kotlinx.coroutines.channels/ReceiveChannel<#A>).kotlinx.coroutines.channels/drop(kotlin/Int, kotlin.coroutines/CoroutineContext = ...): kotlinx.coroutines.channels/ReceiveChannel<#A> // kotlinx.coroutines.channels/drop|[email protected]<0:0>(kotlin.Int;kotlin.coroutines.CoroutineContext){0§<kotlin.Any?>}[0]

kotlinx-coroutines-core/common/src/channels/Broadcast.kt

+5-81
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
@file:Suppress("DEPRECATION")
1+
@file:Suppress("DEPRECATION", "DEPRECATION_ERROR")
22

33
package kotlinx.coroutines.channels
44

@@ -10,36 +10,10 @@ import kotlin.coroutines.*
1010
import kotlin.coroutines.intrinsics.*
1111

1212
/**
13-
* Broadcasts all elements of the channel.
14-
* This function [consumes][ReceiveChannel.consume] all elements of the original [ReceiveChannel].
15-
*
16-
* The kind of the resulting channel depends on the specified [capacity] parameter:
17-
* when `capacity` is positive (1 by default), but less than [UNLIMITED] -- uses [BroadcastChannel] with a buffer of given capacity,
18-
* when `capacity` is [CONFLATED] -- uses [ConflatedBroadcastChannel] that conflates back-to-back sends;
19-
* Note that resulting channel behaves like [ConflatedBroadcastChannel] but is not an instance of [ConflatedBroadcastChannel].
20-
* otherwise -- throws [IllegalArgumentException].
21-
*
22-
* ### Cancelling broadcast
23-
*
24-
* **To stop broadcasting from the underlying channel call [cancel][BroadcastChannel.cancel] on the result.**
25-
*
26-
* Do not use [close][BroadcastChannel.close] on the resulting channel.
27-
* It causes eventual failure of the broadcast coroutine and cancellation of the underlying channel, too,
28-
* but it is not as prompt.
29-
*
30-
* ### Future replacement
31-
*
32-
* This function has an inappropriate result type of [BroadcastChannel] which provides
33-
* [send][BroadcastChannel.send] and [close][BroadcastChannel.close] operations that interfere with
34-
* the broadcasting coroutine in hard-to-specify ways.
35-
*
36-
* **Note: This API is obsolete since 1.5.0.** It is deprecated with warning in 1.7.0.
37-
* It is replaced with [Flow.shareIn][kotlinx.coroutines.flow.shareIn] operator.
38-
*
39-
* @param start coroutine start option. The default value is [CoroutineStart.LAZY].
13+
* @suppress obsolete since 1.5.0, WARNING since 1.7.0, ERROR since 1.9.0
4014
*/
4115
@ObsoleteCoroutinesApi
42-
@Deprecated(level = DeprecationLevel.WARNING, message = "BroadcastChannel is deprecated in the favour of SharedFlow and is no longer supported")
16+
@Deprecated(level = DeprecationLevel.ERROR, message = "BroadcastChannel is deprecated in the favour of SharedFlow and is no longer supported")
4317
public fun <E> ReceiveChannel<E>.broadcast(
4418
capacity: Int = 1,
4519
start: CoroutineStart = CoroutineStart.LAZY
@@ -56,60 +30,10 @@ public fun <E> ReceiveChannel<E>.broadcast(
5630
}
5731

5832
/**
59-
* Launches new coroutine to produce a stream of values by sending them to a broadcast channel
60-
* and returns a reference to the coroutine as a [BroadcastChannel]. The resulting
61-
* object can be used to [subscribe][BroadcastChannel.openSubscription] to elements produced by this coroutine.
62-
*
63-
* The scope of the coroutine contains [ProducerScope] interface, which implements
64-
* both [CoroutineScope] and [SendChannel], so that coroutine can invoke
65-
* [send][SendChannel.send] directly. The channel is [closed][SendChannel.close]
66-
* when the coroutine completes.
67-
*
68-
* Coroutine context is inherited from a [CoroutineScope], additional context elements can be specified with [context] argument.
69-
* If the context does not have any dispatcher nor any other [ContinuationInterceptor], then [Dispatchers.Default] is used.
70-
* The parent job is inherited from a [CoroutineScope] as well, but it can also be overridden
71-
* with corresponding [context] element.
72-
*
73-
* Uncaught exceptions in this coroutine close the channel with this exception as a cause and
74-
* the resulting channel becomes _failed_, so that any attempt to receive from such a channel throws exception.
75-
*
76-
* The kind of the resulting channel depends on the specified [capacity] parameter:
77-
* - when `capacity` is positive (1 by default), but less than [UNLIMITED] -- uses [BroadcastChannel] with a buffer of given capacity,
78-
* - when `capacity` is [CONFLATED] -- uses [ConflatedBroadcastChannel] that conflates back-to-back sends;
79-
* Note that resulting channel behaves like [ConflatedBroadcastChannel] but is not an instance of [ConflatedBroadcastChannel].
80-
* - otherwise -- throws [IllegalArgumentException].
81-
*
82-
* **Note:** By default, the coroutine does not start until the first subscriber appears via [BroadcastChannel.openSubscription]
83-
* as [start] parameter has a value of [CoroutineStart.LAZY] by default.
84-
* This ensures that the first subscriber does not miss any sent elements.
85-
* However, later subscribers may miss elements.
86-
*
87-
* See [newCoroutineContext] for a description of debugging facilities that are available for newly created coroutine.
88-
*
89-
* ### Cancelling broadcast
90-
*
91-
* **To stop broadcasting from the underlying channel call [cancel][BroadcastChannel.cancel] on the result.**
92-
*
93-
* Do not use [close][BroadcastChannel.close] on the resulting channel.
94-
* It causes failure of the `send` operation in broadcast coroutine and would not cancel it if the
95-
* coroutine is doing something else.
96-
*
97-
* ### Future replacement
98-
*
99-
* This API is obsolete since 1.5.0 and deprecated with warning since 1.7.0.
100-
* This function has an inappropriate result type of [BroadcastChannel] which provides
101-
* [send][BroadcastChannel.send] and [close][BroadcastChannel.close] operations that interfere with
102-
* the broadcasting coroutine in hard-to-specify ways.
103-
* It is replaced with [Flow.shareIn][kotlinx.coroutines.flow.shareIn] operator.
104-
*
105-
* @param context additional to [CoroutineScope.coroutineContext] context of the coroutine.
106-
* @param capacity capacity of the channel's buffer (1 by default).
107-
* @param start coroutine start option. The default value is [CoroutineStart.LAZY].
108-
* @param onCompletion optional completion handler for the producer coroutine (see [Job.invokeOnCompletion]).
109-
* @param block the coroutine code.
33+
* @suppress obsolete since 1.5.0, WARNING since 1.7.0, ERROR since 1.9.0
11034
*/
11135
@ObsoleteCoroutinesApi
112-
@Deprecated(level = DeprecationLevel.WARNING, message = "BroadcastChannel is deprecated in the favour of SharedFlow and is no longer supported")
36+
@Deprecated(level = DeprecationLevel.ERROR, message = "BroadcastChannel is deprecated in the favour of SharedFlow and is no longer supported")
11337
public fun <E> CoroutineScope.broadcast(
11438
context: CoroutineContext = EmptyCoroutineContext,
11539
capacity: Int = 1,

kotlinx-coroutines-core/common/src/channels/BroadcastChannel.kt

+14-62
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
@file:Suppress("FunctionName", "DEPRECATION")
1+
@file:Suppress("FunctionName", "DEPRECATION", "DEPRECATION_ERROR")
22

33
package kotlinx.coroutines.channels
44

@@ -10,62 +10,35 @@ import kotlinx.coroutines.channels.Channel.Factory.CONFLATED
1010
import kotlinx.coroutines.channels.Channel.Factory.UNLIMITED
1111
import kotlinx.coroutines.internal.*
1212
import kotlinx.coroutines.selects.*
13-
import kotlin.native.concurrent.*
1413

1514
/**
16-
* Broadcast channel is a non-blocking primitive for communication between the sender and multiple receivers
17-
* that subscribe for the elements using [openSubscription] function and unsubscribe using [ReceiveChannel.cancel]
18-
* function.
19-
*
20-
* See `BroadcastChannel()` factory function for the description of available
21-
* broadcast channel implementations.
22-
*
23-
* **Note: This API is obsolete since 1.5.0 and deprecated for removal since 1.7.0**
24-
* It is replaced with [SharedFlow][kotlinx.coroutines.flow.SharedFlow].
15+
* @suppress obsolete since 1.5.0, WARNING since 1.7.0, ERROR since 1.9.0
2516
*/
2617
@ObsoleteCoroutinesApi
27-
@Deprecated(level = DeprecationLevel.WARNING, message = "BroadcastChannel is deprecated in the favour of SharedFlow and is no longer supported")
18+
@Deprecated(level = DeprecationLevel.ERROR, message = "BroadcastChannel is deprecated in the favour of SharedFlow and is no longer supported")
2819
public interface BroadcastChannel<E> : SendChannel<E> {
2920
/**
30-
* Subscribes to this [BroadcastChannel] and returns a channel to receive elements from it.
31-
* The resulting channel shall be [cancelled][ReceiveChannel.cancel] to unsubscribe from this
32-
* broadcast channel.
21+
* @suppress
3322
*/
3423
public fun openSubscription(): ReceiveChannel<E>
3524

3625
/**
37-
* Cancels reception of remaining elements from this channel with an optional cause.
38-
* This function closes the channel with
39-
* the specified cause (unless it was already closed), removes all buffered sent elements from it,
40-
* and [cancels][ReceiveChannel.cancel] all open subscriptions.
41-
* A cause can be used to specify an error message or to provide other details on
42-
* a cancellation reason for debugging purposes.
26+
* @suppress
4327
*/
4428
public fun cancel(cause: CancellationException? = null)
4529

4630
/**
47-
* @suppress This method has bad semantics when cause is not a [CancellationException]. Use [cancel].
31+
* @suppress
4832
*/
4933
@Deprecated(level = DeprecationLevel.HIDDEN, message = "Binary compatibility only")
5034
public fun cancel(cause: Throwable? = null): Boolean
5135
}
5236

5337
/**
54-
* Creates a broadcast channel with the specified buffer capacity.
55-
*
56-
* The resulting channel type depends on the specified [capacity] parameter:
57-
*
58-
* - when `capacity` positive, but less than [UNLIMITED] -- creates `ArrayBroadcastChannel` with a buffer of given capacity.
59-
* **Note:** this channel looses all items that have been sent to it until the first subscriber appears;
60-
* - when `capacity` is [CONFLATED] -- creates [ConflatedBroadcastChannel] that conflates back-to-back sends;
61-
* - when `capacity` is [BUFFERED] -- creates `ArrayBroadcastChannel` with a default capacity.
62-
* - otherwise -- throws [IllegalArgumentException].
63-
*
64-
* **Note: This API is obsolete since 1.5.0 and deprecated for removal since 1.7.0**
65-
* It is replaced with [SharedFlow][kotlinx.coroutines.flow.SharedFlow] and [StateFlow][kotlinx.coroutines.flow.StateFlow].
38+
* @suppress obsolete since 1.5.0, WARNING since 1.7.0, ERROR since 1.9.0
6639
*/
6740
@ObsoleteCoroutinesApi
68-
@Deprecated(level = DeprecationLevel.WARNING, message = "BroadcastChannel is deprecated in the favour of SharedFlow and StateFlow, and is no longer supported")
41+
@Deprecated(level = DeprecationLevel.ERROR, message = "BroadcastChannel is deprecated in the favour of SharedFlow and StateFlow, and is no longer supported")
6942
public fun <E> BroadcastChannel(capacity: Int): BroadcastChannel<E> =
7043
when (capacity) {
7144
0 -> throw IllegalArgumentException("Unsupported 0 capacity for BroadcastChannel")
@@ -76,49 +49,28 @@ public fun <E> BroadcastChannel(capacity: Int): BroadcastChannel<E> =
7649
}
7750

7851
/**
79-
* Broadcasts the most recently sent element (aka [value]) to all [openSubscription] subscribers.
80-
*
81-
* Back-to-send sent elements are _conflated_ -- only the most recently sent value is received,
82-
* while previously sent elements **are lost**.
83-
* Every subscriber immediately receives the most recently sent element.
84-
* Sender to this broadcast channel never suspends and [trySend] always succeeds.
85-
*
86-
* A secondary constructor can be used to create an instance of this class that already holds a value.
87-
* This channel is also created by `BroadcastChannel(Channel.CONFLATED)` factory function invocation.
88-
*
89-
* In this implementation, [opening][openSubscription] and [closing][ReceiveChannel.cancel] subscription
90-
* takes linear time in the number of subscribers.
91-
*
92-
* **Note: This API is obsolete since 1.5.0 and deprecated for removal since 1.7.0**
93-
* It is replaced with [SharedFlow][kotlinx.coroutines.flow.StateFlow].
52+
* @suppress obsolete since 1.5.0, WARNING since 1.7.0, ERROR since 1.9.0
9453
*/
9554
@ObsoleteCoroutinesApi
96-
@Deprecated(level = DeprecationLevel.WARNING, message = "ConflatedBroadcastChannel is deprecated in the favour of SharedFlow and is no longer supported")
55+
@Deprecated(level = DeprecationLevel.ERROR, message = "ConflatedBroadcastChannel is deprecated in the favour of SharedFlow and is no longer supported")
9756
public class ConflatedBroadcastChannel<E> private constructor(
9857
private val broadcast: BroadcastChannelImpl<E>
9958
) : BroadcastChannel<E> by broadcast {
10059
public constructor(): this(BroadcastChannelImpl<E>(capacity = CONFLATED))
10160
/**
102-
* Creates an instance of this class that already holds a value.
103-
*
104-
* It is as a shortcut to creating an instance with a default constructor and
105-
* immediately sending an element: `ConflatedBroadcastChannel().apply { offer(value) }`.
61+
* @suppress
10662
*/
10763
public constructor(value: E) : this() {
10864
trySend(value)
10965
}
11066

11167
/**
112-
* The most recently sent element to this channel.
113-
*
114-
* Access to this property throws [IllegalStateException] when this class is constructed without
115-
* initial value and no value was sent yet or if it was [closed][close] without a cause.
116-
* It throws the original [close][SendChannel.close] cause exception if the channel has _failed_.
68+
* @suppress
11769
*/
11870
public val value: E get() = broadcast.value
71+
11972
/**
120-
* The most recently sent element to this channel or `null` when this class is constructed without
121-
* initial value and no value was sent yet or if it was [closed][close].
73+
* @suppress
12274
*/
12375
public val valueOrNull: E? get() = broadcast.valueOrNull
12476
}

kotlinx-coroutines-core/common/src/channels/Deprecated.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import kotlin.jvm.*
1818
* Safe to remove in 1.9.0 as was inline before.
1919
*/
2020
@ObsoleteCoroutinesApi
21-
@Suppress("DEPRECATION")
21+
@Suppress("DEPRECATION_ERROR")
2222
@Deprecated(level = DeprecationLevel.ERROR, message = "BroadcastChannel is deprecated in the favour of SharedFlow and is no longer supported")
2323
public inline fun <E, R> BroadcastChannel<E>.consume(block: ReceiveChannel<E>.() -> R): R {
2424
val channel = openSubscription()

kotlinx-coroutines-core/common/src/flow/Channels.kt

-19
Original file line numberDiff line numberDiff line change
@@ -131,25 +131,6 @@ private class ChannelAsFlow<T>(
131131
override fun additionalToStringProps(): String = "channel=$channel"
132132
}
133133

134-
/**
135-
* Represents the given broadcast channel as a hot flow.
136-
* Every flow collector will trigger a new broadcast channel subscription.
137-
*
138-
* ### Cancellation semantics
139-
* 1) Flow consumer is cancelled when the original channel is cancelled.
140-
* 2) Flow consumer completes normally when the original channel completes (~is closed) normally.
141-
* 3) If the flow consumer fails with an exception, subscription is cancelled.
142-
*/
143-
@Suppress("DEPRECATION")
144-
@Deprecated(
145-
level = DeprecationLevel.ERROR,
146-
message = "'BroadcastChannel' is obsolete and all corresponding operators are deprecated " +
147-
"in the favour of StateFlow and SharedFlow"
148-
) // Since 1.5.0, ERROR since 1.7.0, was @FlowPreview, safe to remove in 1.8.0
149-
public fun <T> BroadcastChannel<T>.asFlow(): Flow<T> = flow {
150-
emitAll(openSubscription())
151-
}
152-
153134
/**
154135
* Creates a [produce] coroutine that collects the given flow.
155136
*

kotlinx-coroutines-core/common/test/CancelledParentAttachTest.kt

+8-7
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ class CancelledParentAttachTest : TestBase() {
99

1010
@Test
1111
fun testAsync() = runTest {
12-
CoroutineStart.values().forEach { testAsyncCancelledParent(it) }
12+
CoroutineStart.entries.forEach { testAsyncCancelledParent(it) }
1313
}
1414

1515
private suspend fun testAsyncCancelledParent(start: CoroutineStart) {
@@ -25,14 +25,14 @@ class CancelledParentAttachTest : TestBase() {
2525
}
2626
}
2727
expectUnreached()
28-
} catch (e: CancellationException) {
28+
} catch (_: CancellationException) {
2929
// Expected
3030
}
3131
}
3232

3333
@Test
3434
fun testLaunch() = runTest {
35-
CoroutineStart.values().forEach { testLaunchCancelledParent(it) }
35+
CoroutineStart.entries.forEach { testLaunchCancelledParent(it) }
3636
}
3737

3838
private suspend fun testLaunchCancelledParent(start: CoroutineStart) {
@@ -48,7 +48,7 @@ class CancelledParentAttachTest : TestBase() {
4848
}
4949
}
5050
expectUnreached()
51-
} catch (e: CancellationException) {
51+
} catch (_: CancellationException) {
5252
// Expected
5353
}
5454
}
@@ -67,9 +67,10 @@ class CancelledParentAttachTest : TestBase() {
6767

6868
@Test
6969
fun testBroadcast() = runTest {
70-
CoroutineStart.values().forEach { testBroadcastCancelledParent(it) }
70+
CoroutineStart.entries.forEach { testBroadcastCancelledParent(it) }
7171
}
7272

73+
@Suppress("DEPRECATION_ERROR")
7374
private suspend fun testBroadcastCancelledParent(start: CoroutineStart) {
7475
try {
7576
withContext(Job()) {
@@ -83,7 +84,7 @@ class CancelledParentAttachTest : TestBase() {
8384
}
8485
}
8586
expectUnreached()
86-
} catch (e: CancellationException) {
87+
} catch (_: CancellationException) {
8788
// Expected
8889
}
8990
}
@@ -105,7 +106,7 @@ class CancelledParentAttachTest : TestBase() {
105106
block()
106107
}
107108
expectUnreached()
108-
} catch (e: CancellationException) {
109+
} catch (_: CancellationException) {
109110
// Expected
110111
}
111112
}

kotlinx-coroutines-core/common/test/ParentCancellationTest.kt

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ package kotlinx.coroutines
44

55
import kotlinx.coroutines.testing.*
66
import kotlinx.coroutines.channels.*
7-
import kotlin.coroutines.*
87
import kotlin.test.*
98

109
/**
@@ -57,6 +56,7 @@ class ParentCancellationTest : TestBase() {
5756
}
5857

5958
@Test
59+
@Suppress("DEPRECATION_ERROR")
6060
fun testBroadcastChild() = runTest {
6161
testParentCancellation(runsInScopeContext = true) { fail ->
6262
broadcast<Unit> { fail() }.openSubscription()
@@ -165,4 +165,4 @@ class ParentCancellationTest : TestBase() {
165165
}
166166
finish(3)
167167
}
168-
}
168+
}

0 commit comments

Comments
 (0)