Skip to content

Commit e9123ca

Browse files
committed
Improve CoroutineScope documentation: mention job convention, get rid of lateinit example, discourage manual implementation of the scope
1 parent b367fae commit e9123ca

File tree

3 files changed

+24
-27
lines changed

3 files changed

+24
-27
lines changed

coroutines-guide.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ The main coroutines guide has moved to the [docs folder](docs/coroutines-guide.m
3838
* <a name='parental-responsibilities'></a>[Parental responsibilities](docs/coroutine-context-and-dispatchers.md#parental-responsibilities)
3939
* <a name='naming-coroutines-for-debugging'></a>[Naming coroutines for debugging](docs/coroutine-context-and-dispatchers.md#naming-coroutines-for-debugging)
4040
* <a name='combining-context-elements'></a>[Combining context elements](docs/coroutine-context-and-dispatchers.md#combining-context-elements)
41-
* <a name='getting-it-together'></a>[Getting it together](docs/coroutine-context-and-dispatchers.md#getting-it-together)
41+
* <a name='coroutine-scope'></a>[Coroutine scope](docs/coroutine-context-and-dispatchers.md#coroutine-scope)
4242
* <a name='thread-local-data'></a>[Thread-local data](docs/coroutine-context-and-dispatchers.md#thread-local-data)
4343
<!--- TOC_REF docs/exception-handling.md -->
4444
* <a name='exception-handling'></a>[Exception handling](docs/exception-handling.md#exception-handling)

docs/coroutine-context-and-dispatchers.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ class DispatchersGuideTest {
3030
* [Parental responsibilities](#parental-responsibilities)
3131
* [Naming coroutines for debugging](#naming-coroutines-for-debugging)
3232
* [Combining context elements](#combining-context-elements)
33-
* [Getting it together](#getting-it-together)
33+
* [Coroutine scope](#coroutine-scope)
3434
* [Thread-local data](#thread-local-data)
3535

3636
<!--- END_TOC -->
@@ -487,7 +487,7 @@ I'm working in thread DefaultDispatcher-worker-1 @test#2
487487

488488
<!--- TEST FLEXIBLE_THREAD -->
489489

490-
### Getting it together
490+
### Coroutine scope
491491

492492
Let us put our knowledge about contexts, children and jobs together. Assume that our application has
493493
an object with a lifecycle, but that object is not a coroutine. For example, we are writing an Android application
@@ -516,14 +516,15 @@ class Activity {
516516

517517
</div>
518518

519-
We can implement [CoroutineScope] interface in this `Actvity` class. The best way to do it is
519+
Alternatively, we can implement [CoroutineScope] interface in this `Actvity` class. The best way to do it is
520520
to use delegation with default factory functions.
521521
We also can combine the desired dispatcher (we used [Dispatchers.Default] in this example) with the scope:
522522

523523
<div class="sample" markdown="1" theme="idea" data-highlight-only>
524524

525525
```kotlin
526-
class Activity : CoroutineScope by CoroutineScope(Dispatchers.Default)
526+
class Activity : CoroutineScope by CoroutineScope(Dispatchers.Default) {
527+
// to be continued ...
527528
```
528529

529530
</div>

kotlinx-coroutines-core/common/src/CoroutineScope.kt

Lines changed: 18 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -6,58 +6,54 @@ package kotlinx.coroutines
66

77
import kotlinx.coroutines.internal.*
88
import kotlinx.coroutines.intrinsics.*
9-
import kotlin.coroutines.intrinsics.*
109
import kotlin.coroutines.*
10+
import kotlin.coroutines.intrinsics.*
1111

1212
/**
1313
* Defines a scope for new coroutines. Every coroutine builder
1414
* is an extension on [CoroutineScope] and inherits its [coroutineContext][CoroutineScope.coroutineContext]
1515
* to automatically propagate both context elements and cancellation.
1616
*
17+
* The best ways to obtain a standalone instance of the scope are [CoroutineScope()] and [MainScope()] factory functions.
18+
* Additional context elements can be appended to the scope using [plus][CoroutineScope.plus] operator.
19+
*
20+
* Manual implementation of this interface is not recommended, implementation by delegation should be preferred instead.
21+
* By convention, [context of the scope][CoroutineScope.coroutineContext] should contain an instance of a [job][Job] to enforce structured concurrency.
22+
*
1723
* Every coroutine builder (like [launch][CoroutineScope.launch], [async][CoroutineScope.async], etc)
1824
* and every scoping function (like [coroutineScope], [withContext], etc) provides _its own_ scope
1925
* with its own [Job] instance into the inner block of code it runs.
20-
* By convention, they all wait for all the coroutines inside
21-
* their block to complete before completing themselves, thus enforcing the
22-
* discipline of **structured concurrency**.
26+
* By convention, they all wait for all the coroutines inside their block to complete before completing themselves,
27+
* thus enforcing the discipline of **structured concurrency**.
2328
*
24-
* [CoroutineScope] should be implemented on entities with well-defined lifecycle that are responsible
29+
* [CoroutineScope] should be implemented (or used as a field) on entities with a well-defined lifecycle that are responsible
2530
* for launching children coroutines. Example of such entity on Android is Activity.
2631
* Usage of this interface may look like this:
2732
*
2833
* ```
29-
* class MyActivity : AppCompatActivity(), CoroutineScope {
30-
* lateinit var job: Job
31-
* override val coroutineContext: CoroutineContext
32-
* get() = Dispatchers.Main + job
33-
*
34-
* override fun onCreate(savedInstanceState: Bundle?) {
35-
* super.onCreate(savedInstanceState)
36-
* job = Job()
37-
* }
38-
*
34+
* class MyActivity : AppCompatActivity(), CoroutineScope by MainScope() {
3935
* override fun onDestroy() {
40-
* super.onDestroy()
41-
* job.cancel() // Cancel job on activity destroy. After destroy all children jobs will be cancelled automatically
36+
* cancel() // cancel is extension on CoroutineScope
4237
* }
4338
*
4439
* /*
4540
* * Note how coroutine builders are scoped: if activity is destroyed or any of the launched coroutines
4641
* * in this method throws an exception, then all nested coroutines are cancelled.
4742
* */
4843
* fun showSomeData() = launch { // <- extension on current activity, launched in the main thread
49-
* val data = withContext(Dispatchers.IO) {
50-
* // Provides withContext scope that is child of he outer launch scope
51-
* // blocking I/O operation
52-
* }
44+
* // ... here we can use suspending functions or coroutine builders with other dispatchers
5345
* draw(data) // draw in the main thread
5446
* }
5547
* }
5648
* ```
5749
*/
5850
public interface CoroutineScope {
5951
/**
60-
* Context of this scope.
52+
* The context of this scope.
53+
* Context is encapsulated by the scope and used for implementation of coroutine builders that are extensions on the scope.
54+
* Accessing this property in general code is not recommended for any purposes except accessing [Job] instance for advanced usages.
55+
*
56+
* By convention, should contain an instance of a [job][Job] to enforce structured concurrency.
6157
*/
6258
public val coroutineContext: CoroutineContext
6359
}

0 commit comments

Comments
 (0)