Kotlin Resources
Knowledge
- Docs: "Null safety", Kotlin
Official docs for Kotlin's nullable/non-nullable type distinction, the safe-call and Elvis operators, and the platform types a Java interop boundary introduces. Use for: the primary mechanism behind writing null safety into the type system instead of into defensive checks. - Docs: "Types overview", Kotlin
Official docs explaining that Kotlin's basic types (numbers, characters, booleans) behave like regular classes despite an optimized primitive representation at runtime. Use for: exactly whyInt,Boolean, and similar types have member functions, unlike Java's primitives. - Docs: "Strings", Kotlin
Official docs on Kotlin's immutableStringtype and string templates ($variable,${expression}). Use for: string interpolation as a language feature, not string concatenation with extra syntax. - Docs: "Calling Java from Kotlin", Kotlin
Official docs on the Java-to-Kotlin direction: platform types, theT!andArray<(out) T>!notation that appears only in diagnostics, and the two documented remedies (an explicit type annotation at the use site, or nullability annotations at the source). Also synthetic properties from Java getters and setters, with the detail that a setter-only class yields no property because Kotlin has none, and backtick escaping for Java identifiers that are Kotlin keywords. Use for: the boundary where null safety is lost, and how to restore it. - Docs: "Calling Kotlin from Java", Kotlin
Official docs on the Kotlin-to-Java direction: top-level declarations compiling into a file class such asorg.example.AppKtwith@file:JvmNameand@file:JvmMultifileClassto control it,@JvmOverloadsfor default parameters (and the restriction that it cannot be used on abstract or interface methods),@JvmFieldwith its four conditions, and@Throwsfor a checked exception a Java caller has to catch. Use for: deciding what a Kotlin library owes its Java consumers. - Docs: "Generics: in, out, where", Kotlin
Official docs on type parameters and variance, opening with why Java needs wildcards (its generic types are invariant, which is what stops anIntegerreaching a list of strings) and stating plainly that Kotlin has none, offering declaration-site variance and type projections instead. Covers theoutrule and itsinmirror, use-site projections for a type likeArraythat both produces and consumes, star projections and what each declaration form makes them mean, captured types and why reads use the upper bound while writes use the lower one, and upper bounds withwhere. Use for: writing a signature that says what a caller may do with it, and for reading a projection diagnostic. - Docs: "Kotlin coroutines on Android", Android Developers
Official guide to coroutines on Android, built around main-safety: a function is main-safe when it does not block UI updates on the main thread, and the guide's shape puts thewithContext(Dispatchers.IO)inside the repository function so no caller has to remember. Also recommends injectingDispatchersinto the repository layer for easier testing, which is the same conclusionkotlinx-coroutines-testreaches from the test side. Use for: the Android half of the mission, and for where the wrapping of blocking work belongs. - Docs: "Use Kotlin coroutines with lifecycle-aware components", Android Developers
Official docs on the scopes the platform owns for you:viewModelScope, cancelled automatically when theViewModelis cleared (and replaceable by a constructor-injected scope so a test can pass aTestScope),LaunchedEffectfor composition-scoped work, andcollectAsStateWithLifecycle, which collects fromSTARTEDtoSTOPPEDby default withminActiveStateto change it. Includes the warning thatLaunchedEffectfollows the composition rather than theLifecycle, so it can run off-screen. Use for: choosing which lifetime a piece of work should follow. - Docs: "Backend development with Kotlin", Kotlin
Official orientation page for server-side Kotlin: that it keeps full compatibility with existing Java-based technology stacks, and that a large Java codebase can be migrated gradually rather than at once. Use for: context before choosing a framework, and for the interoperability argument when a team is deciding whether to start. - Docs: "Gradle Kotlin DSL Primer", Gradle
Official primer forbuild.gradle.kts: which type-safe model accessors exist in which kind of script, what to do when they are not available (configure<T>()andthe<T>()), and./gradlew kotlinDslAccessorsReportfor discovering what an applied plugin actually contributes. Use for: writing a Kotlin build script without guessing, and for the fallback when an accessor is missing. - Docs: "Version Catalogs", Gradle
Official docs ongradle/libs.versions.toml, auto-imported aslibs: the alias-to-accessor mapping where each dash becomes a dot, registering further catalogs from the settings script, the TOML format, and the limitation thatfrommay be called only once per catalog. Use for: keeping every version in one place, and for naming aliases so the generated accessors group sensibly. - Docs: "Graph Resolution", Gradle
Official docs on how Gradle builds the dependency graph and resolves conflicts: it considers every requested version and by default selects the highest, prefers versions without qualifiers by comparing base versions first, and treats a same-capability clash as a separate kind of conflict resolved during variant selection. Use for: predicting which version reaches the classpath, and for the contrast with Maven's nearest-wins rule recorded in the Java workspace's testing and build sheet. - Docs: "The Java Library Plugin", Gradle
Official docs on theapiandimplementationsplit:apidependencies are transitively exposed and appear on a consumer's compile classpath,implementationdependencies are not and do not leak into it. Use for: deciding which configuration a dependency belongs in, which is a statement about your library's surface rather than a formality. - Docs: "Creating Dependency Configurations", Gradle
Official docs on configurations by role, declarable, resolvable and consumable, with the full set each Java plugin adds, the note that a configuration is intended for a single role, and how to create a custom one. Use for: reading an unfamiliar build file, and for unlearning the assumption that a configuration is a renamed Maven scope. - Site: MockK, mocking library for Kotlin
The project site, which doubles as the reference:mockk,everyandverify, thecoforms for suspending functions (coEvery,coVerify,coJustAwait),mockkObjectfor singletons and its scoped block form,mockkStaticfor top-level and module-wide extension functions,spyk, relaxed mocks and their trouble with generic return types, and the JUnit 5 extension that unmocks everything afterwards. Use for: doubling the Kotlin constructs a subclass-based mocking library cannot reach, and for the blast radius of each technique. - Docs: "Inheritance", Kotlin
Official docs onopen, and on the rule underneath a great deal of Kotlin testing advice: classes and their members are final by default and cannot be inherited from or overridden without it. Also notes that an overriding member is itself open unless markedfinal. Use for: why mocking works differently here, and for the argument against marking a classopento satisfy a test. - API: "kotlinx-coroutines-test", kotlinx.coroutines
Package documentation for the coroutine test utilities:runTestand theTestScopeit builds, theTestCoroutineScheduleras the shared source of virtual time, the difference betweenStandardTestDispatcherandUnconfinedTestDispatcher(which enters top-level children eagerly),Dispatchers.setMain, and the section that matters most, that virtual time is not used insideDispatchers.IO,DefaultorMain, so those delays are real unless the dispatcher is replaceable. Use for: testing suspending code, and for the argument that a hardcoded dispatcher is a testability defect. - API: "kotlin-test", Kotlin
Reference for the standard library's test façade: annotations and assertions that are independent of the test framework, theAsserterabstraction they delegate to, and the artifact list (kotlin-test-junit,kotlin-test-junit5,kotlin-test-testng,kotlin-test-js) that decides which framework the annotations are mapped onto. Use for: understanding why the same@Testbehaves differently depending on a dependency. - Turbine, Cash App
The testing library forFlowthat the Kotlin flow documentation itself recommends. Coversflow.test { }withawaitItem(),awaitComplete()andawaitError(),testInfor several flows at once, the reason a Turbine test hangs rather than fails (testIncannot clean up its own coroutine, needingrunTest'sbackgroundScopeor an explicit termination),cancelAndIgnoreRemainingEvents()for a flow that never completes on its own,ensureAllEventsConsumed(),expectMostRecentItem(), and the library's own documented dependency on an unstablekotlinx-coroutines-testAPI (UnconfinedTestDispatcherinternals) to integrate withrunTest. Use for: asserting what a flow emitted, in order, including one that runs forever. - Docs: "Introduction", Kotest
Entry point for Kotest, the Kotlin-first alternative that replaces both the assertion layer and the runner: tests written in one of several styles (such as a class extendingFunSpecwithtest("...") { }blocks) and infix matchers likeshouldBe. Use for: deciding whether to adopt it wholesale, which is the only sensible way to adopt it. - Docs: "Cancellation and timeouts", Kotlin
Official docs on cancellation through theJobhandle: why it is cooperative, what a suspension point is and why asuspendcall is not always one, theyield(),ensureActive()andisActivechecks, prompt cancellation (a cancelled coroutine resumes with an exception rather than an available value),withContext(NonCancellable)for cleanup that must finish, andwithTimeoutOrNull(). Use for: making long-running code actually stop, and for cleanup that survives cancellation. Note thatcancellation-and-timeouts.htmlredirects here. - Docs: "Coroutine exceptions handling", Kotlin
Official docs on the two builder flavours (launchpropagates automatically,asyncexposes the exception throughawait), and onCoroutineExceptionHandler: that it belongs on a root coroutine, that children delegate to their parent so a handler on a child never runs, and that you cannot recover in it because the coroutine has already completed. Use for: working out where an exception from a coroutine actually surfaces. - Docs: "Flows", Kotlin
Official docs onFlow: the emitter, intermediate operator and collector roles with the upstream and downstream vocabulary, cold flows (lazy, one execution per collector) against hot flows (SharedFlowandStateFlow, whose collectors are subscribers), the rule that aflow()builder must emit from its own coroutine context,.flowOn()as a context-preserving upstream switch,channelFlow()with its buffered channel for emitting from several coroutines, and thecatchandretryoperators. Use for: streaming many values over time instead of returning one, and for deciding between a cold and a hot flow. Note thatflow.htmlredirects here. - Docs: "Coroutine context and dispatchers", Kotlin
Official docs on theCoroutineContextas a set of elements, the dispatchers and what each confines execution to,withContextfor switching and the extra dispatches a dispatcher change costs, context inheritance by children, and the two ways the parent-child relation gets overridden. Use for: reading which threads a coroutine runs on, and for why passing aJobinto a builder detaches it from its scope. - API: "Dispatchers", kotlinx.coroutines
Reference for the four standard dispatchers, including the exact wording of whatMainis confined to and whatUnconfineddoes with the initial continuation. Use for: choosing a dispatcher, and for the fact thatDefaultis what every builder falls back to. - API: "Dispatchers.IO", kotlinx.coroutines
Reference for the blocking-IO dispatcher: the parallelism property and its default of 64 threads or the core count, the elasticity oflimitedParallelismviews (with a worked MySQL and MongoDB example), and two facts that correct the obvious model, thatIOshares threads withDefaultso switching to it often does not change thread, and that its limit bounds blocking tasks rather than threads. Use for: sizing and partitioning blocking work in a service. - API: "CoroutineScope", kotlinx.coroutines
Reference with a "Structured concurrency in detail" section: that a coroutine cannot reach its final state until all its children have, that cancelling a scope cancels every child, the exact conditions under which a child's failure fails its parent, and theCoroutineScope()constructor function for a scope tied to an entity's lifetime (with the warning that cancelling it is the caller's job). Use for: deciding between a lexical scope and an owned one, and for the precise propagation rules. - API: "GlobalScope", kotlinx.coroutines
Reference for the@DelicateCoroutinesApiglobal scope, with the pitfalls stated as the library sees them (computations running when they are no longer needed or have no right to) and the narrow legitimate case of a process that must live as long as the application. Use for: arguing about aGlobalScope.launchin review, in the library authors' own terms. - Docs: "Coroutines basics", Kotlin
Official docs on thesuspendkeyword and the rule that a suspending function can only be called from another one, the three coroutine builders with what each returns, and a direct comparison of a coroutine against a JVM thread (stack size, how many of each a process holds, what happens to the thread when a coroutine suspends). Use for: the entry point to the concurrency stage, and for whydelayandThread.sleepare not interchangeable. - Docs: "Composing suspending functions", Kotlin
Official docs on combining suspending calls: sequential by default,asyncandawaitfor genuine concurrency with the elapsed times measured, lazily startedasyncviaCoroutineStart.LAZY, and the difference betweenJobandDeferred. Use for: making two independent slow operations concurrent, and for seeing thatsuspendalone never does it for you. - Spec: "Threads and Locks", Java Language Specification, Java SE 21
Chapter 17 of the JLS: the memory model itself, happens-before, and thefinalfield semantics whose freeze action happens when a constructor exits. Use for: the model Kotlin on the JVM actually runs under, since the language defines no memory model of its own on this platform. Dense; the Java workspace's concurrency sheet is the lookup-shaped companion to it. - API: "Volatile", Kotlin
Reference for the@Volatileannotation, including the distinction the name hides: operations on the annotated backing field are atomic, while a property operation through a custom accessor that touches the field several times is not. Use for: what@Volatileguarantees, and the read-modify-write case it does not cover. - API: "Synchronized", Kotlin
Reference for@Synchronized: which monitor the generated JVM method takes, why the annotation is wrong on an extension function (the facade class's monitor, not the receiver's), and the deprecation of the common declaration, an error since Kotlin 2.1. Use for: choosing between the annotation and thesynchronized(lock) { }function. - API: "LazyThreadSafetyMode", Kotlin
Reference for the three modeslazytakes:SYNCHRONIZED(the default, one initialising thread and a visible result),PUBLICATION(the initializer may run more than once, one value wins), andNONE(no locks, unspecified across threads). Use for: whyby lazyis thread-safe without being asked, and what the opt-outs actually cost. - API: "thread", Kotlin
Reference for the standard library'sthreadfunction, which creates and by default starts ajava.lang.Thread, withisDaemon,nameandpriorityas named arguments. Use for: starting a platform thread from Kotlin without theThreadsubclass orRunnableceremony. - Docs: "Aggregate operations", Kotlin
Official docs on the operations that reduce a collection to a single value:count,sum,average, the min and max family with itsOrNullandByvariants, andfold/reducewith the initial-value difference between them spelled out on a worked example. Use for: choosing between a named aggregate and a hand-written fold, and for why the same lambda gives different answers tofoldandreduce. - Docs: "Grouping", Kotlin
Official docs ongroupBy(), which materialises aMapof key to member list, andgroupingBy(), which returns aGroupingthat operations such aseachCount()consume without building those lists. Use for: the difference that decides whether a per-group aggregation allocates in proportion to the input. - Docs: "Sequences", Kotlin
Official docs onSequence<T>: lazy multistep processing, the intermediate/terminal operation split, the four ways to construct one, stateless versus stateful operations, and the explicit warning that laziness has an overhead of its own. Use for: deciding between a collection pipeline and a sequence, and for the element-by-element execution order that lets a bound liketakecut the work short. - Docs: "Collection operations overview", Kotlin
Official docs on how collection operations are declared: essential behaviour as member functions of the collection interfaces, everything else as extension functions, none of them touching the receiver. Use for: whymapandfilterare not members ofList, and why an operation whose result nobody keeps still does all its work. - Docs: "Collection transformation operations", Kotlin
Official docs onmap,mapNotNull,zip,associate,flatten/flatMapandjoinToString, each building a new collection from an existing one. Use for: the transformation half of a collection pipeline, and the fact that every step in a chain materialises a collection of its own. - Docs: "Filtering collections", Kotlin
Official docs onfilterand its variants,partition, and theany/none/allpredicate tests, includingall()returningtrueon an empty collection by vacuous truth. Use for: narrowing a collection, and the empty-input edge case a validation guard written withallgets wrong. - Docs: "Operator overloading", Kotlin
Official docs on the fixed set of operator symbols (+,*,[], comparisons, and more) and the exact function name andoperatormodifier each maps to. Use for: implementing an operator only where it means what the symbol already means to a reader, not as a way to write terse but surprising code. - Docs: "Delegation", Kotlin
Official docs on class delegation viaby: implementing an interface by forwarding to a held object, with zero boilerplate, and the subtlety that overrides in the derived class aren't seen by the delegate's own internal calls. Use for: the delegation pattern as a language feature instead of hand-written forwarding methods. - Docs: "Delegated properties", Kotlin
Official docs on property delegation (by lazy { ... }and custom delegates viagetValue()/setValue()). Use for: reusable property behavior (lazy initialization, change observation) without repeating the same accessor logic on every property that needs it. - Docs: "Inline functions", Kotlin
Official docs on theinlinemodifier's actual cost/benefit trade-off, non-local returns,noinline/crossinline, and reified type parameters, which only work because inlining erases the usual generics-erasure boundary. Use for: whyinlineandreifiedare paired, not two unrelated features. - Docs: "Higher-order functions and lambdas", Kotlin
Official docs on function types, lambda syntax, trailing-lambda convention, and function literals with receiver (A.(B) -> C), the mechanism scope functions likerunandapplyare built on. Use for: functions as real values, not just something a lambda is loosely shorthand for. - Docs: "Type-safe builders", Kotlin
Official docs on building a type-safe builder DSL from a receiver-style function type, the receiver-conflict problem a nested builder introduces (a closure carries access to every enclosing receiver, not just the nearest one), and@DslMarkeras the fix, restricting implicit member access to the nearest receiver unless an outer one is named explicitly. Use for: the construct receiver-style function types actually exist for. - Docs: "Scope functions", Kotlin
Official docs onlet,run,with,apply, andalso: the object reference each provides (itvsthis), what each returns (the lambda's result vs the context object), and the function-selection table distinguishing them. Use for: choosing the right scope function by what it actually returns, not by habit or resemblance to another one. - Docs: "Extensions", Kotlin
Official docs on extension functions and properties: called as if they were members, but resolved statically and never actually modifying the extended class or interface. Use for: adding behavior to a type you don't own (including one from a library) without inheritance or a wrapper class. - Docs: "Interfaces", Kotlin
Official docs on interfaces with default method bodies, abstract versus implemented properties (and why interfaces can't hold backing-field state), and resolving a diamond conflict withsuper<Type>.member(). Use for: modelling shared behavior across unrelated types without inheritance. - Docs: "Object declarations and expressions", Kotlin
Official docs onobjectdeclarations (thread-safe, lazily-initialized singletons), companion objects, and object expressions for anonymous, one-time instances. Use for: what replaces Java's static members and singleton-pattern boilerplate. - Docs: "Enum classes", Kotlin
Official docs on enum classes: each constant as a real object, optional per-constant anonymous class bodies, and theentries/valueOf()/name/ordinalmachinery every enum gets for free. Use for: what an enum actually is beyond a list of names, and how it differs from a sealed class covering the same kind of fixed set. - Docs: "Sealed classes and interfaces", Kotlin
Official docs on sealed hierarchies: every direct subclass known at compile time, and the compiler-enforced exhaustiveness this gives awhenexpression over one, with noelsebranch needed. Use for: type-safe state modelling where an exception or a runtime check would otherwise stand in for the type system. - Docs: "Data classes", Kotlin
Official docs on whatdata classgenerates automatically (equals()/hashCode(),toString(),componentN(),copy()), its requirements, and the subtle rule that only primary-constructor properties participate. Use for: what a data class actually buys over a hand-written class, precisely. - Docs: "Inline value classes", Kotlin
Official docs on@JvmInline value class: the single-property constraint, the compiler's preference for an unboxed runtime representation, the documented "boxed whenever used as another type" rule (generics,Any, interfaces), and the doubly-nullable case that boxes even ordinary-looking usage. Use for: the zero-cost fix for primitive obsession, and precisely where "zero-cost" stops applying. - Repo: kotlinx.serialization, Kotlin
Official repo and docs for the compiler-plugin-based, reflectionless serialization library: the two-piece setup (compiler plugin plus runtime dependency), full JVM/JS/Native multiplatform support, and the explicit, per-type serialization-strategy philosophy with no global configuration point. Use for: what a Java habit's reflective serializer (Jackson, Gson) doesn't do, and why it can't reach every Kotlin target. - API: "runCatching", Kotlin
Official stdlib reference forrunCatching'sResult<T>-returning contract, and that it catches anyThrowablea block throws, includingCancellationException. Use for: the exact stdlib contract that collides with coroutine cancellation if used unguarded. - Docs: "Routing", Ktor
Official docs for Ktor's routing DSL: the per-verb functions (get,post,put, and others), path patterns including named parameters and fullRegexsupport, androutefor grouping and nesting. Use for: routing as an application of lesson 36's type-safe builder mechanism, not a new one. - Docs: "Server plugins", Ktor
Official docs stating that routing itself is implemented as a plugin, that Ktor activates none by default, and that a plugin can be scoped to specific routes rather than only installed globally. Use for: why nothing in a Ktor application works until it's explicitly installed. - Docs: "Handling requests", Ktor
Official docs for extracting request data (requirePathParameter,requireQueryParameter,requireCookie), each throwing (MissingRequestParameterException) rather than returning null when a required value is actually absent. Use for: the boundary code lesson 31's "nullability lives at the edge" principle describes, applied concretely. - Docs: "Configuration in a file", Ktor
Official docs forapplication.conf/application.yaml, environment-variable substitution (${ENV}, and the optional${?ENV}form for overriding a prior default), custom configuration sections alongside Ktor's own reserved block, and command-line config-file overrides. Use for: the exact idiom for a value with a safe default and an environment-driven override. - Docs: "Logging in Ktor Server", Ktor
Official docs on SLF4J as Ktor's JVM logging abstraction, and its silent no-op fallback when no concrete logging framework is present. Use for: why logging calls that compile and run can still produce zero output. - Docs: "Call logging", Ktor
Official docs for theCallLoggingplugin: defaultLevel.INFO, thefilter { }block for logging only some requests, andmdc(...)for per-request diagnostic values scoped to one call's lifetime. Use for: request-level logging, and the pattern-update step MDC values need to actually appear in output. - Docs: "Working with Transactions", Exposed
Official JetBrains docs for Exposed's transaction model: synchronous, blocking execution on the current thread by default,newSuspendedTransaction/suspendedTransactionAsyncas the coroutine-friendly alternative (always starting a fresh transaction), and nested-transaction rollback scoped by SQLSAVEPOINT. Use for: why a plain Exposed transaction inside a suspending function is a real defect, and the documented fix. - Docs: "Integrate a database with Kotlin, Ktor, and Exposed", Ktor
Official docs for thewithTransaction()pattern: a suspending block run inside a new top-level transaction with the coroutine context switched toDispatchers.IO. Use for: dispatching Exposed's underlying blocking JDBC work correctly instead of stalling the handler's own thread. - Docs: "Classes", Kotlin
Official docs on Kotlin classes: the primary constructor, properties declared directly in the class header, and when the docs themselves recommend a data class or an extension function instead of a plain class. Use for: what a class actually needs to encapsulate, before reaching for one reflexively. - Docs: "Properties", Kotlin
Official docs on Kotlin properties: backing fields, custom getters and setters, and why properties replace the getter/setter boilerplate a Java class needs by hand. Use for: what a property actually compiles to, and where a custom accessor is worth writing. - Docs: "Conditions and loops", Kotlin
Official docs onifas an expression,whenand its exhaustiveness, and Kotlin'sforloop over ranges and collections. Use for: control flow as expressions producing values, not just statements. - Docs: "Ranges and progressions", Kotlin
Official docs on Kotlin's range operators (..,..<) and the progressions aforloop actually iterates over. Use for: what a range literally is, before treatingfor (i in 1..10)as unexplained syntax. - Docs: "Collections overview", Kotlin
Official docs onList/Set/Map, and the read-only/mutable interface pair behind each, including why a mutable collection held by avalis still mutable. Use for: the collection-level counterpart to lesson 2's reference-vs-object mutability distinction. - Docs: "Equality", Kotlin
Official docs distinguishing structural equality (==, callsequals()) from referential equality (===, same object identity), and which Kotlin types overrideequals()by default. Use for: exactly what==means in Kotlin, since it is not Java's==. - Docs: "Basic syntax overview", Kotlin
Official overview of Kotlin's core syntax elements, includingval/var, basic types, and control flow, each linked to its own detailed page. Use for: the language's basic building blocks, before idiom (stage 3) asks for more than syntax. - Docs: "Coroutines guide", Kotlin
Official guide to coroutines: suspending functions, structured concurrency, and dispatchers. Use for: how Kotlin's concurrency model actually works, before comparing it to anything else. - JEP 444: "Virtual Threads", OpenJDK
The official specification for Java 21's virtual threads: what problem they solve and how they're scheduled under the hood. Use for: the specific comparison point the mission names, coroutines against Java 21 virtual threads. - Docs: "Kotlin for Java developers", Kotlin
Official docs naming, directly, what's different (and what's deliberately similar) between Kotlin and Java. Use for: locating exactly where a Java habit stops applying. - Docs: "Coding conventions", Kotlin
The official style guide for idiomatic Kotlin: naming, formatting, and idioms the language expects, as opposed to code that merely compiles. Use for: recognizing Kotlin written with a Java accent versus Kotlin written idiomatically. - Site: "Kotlin on Android", Android Developers
Official entry point for Kotlin's Android-specific idioms and libraries (coroutines with lifecycle-aware scopes, Android KTX). Use for: the Android half of this mission's coverage, where it diverges from a backend/server context.
Gaps
- No source contrasting Kotlin coroutines against Java 21 virtual threads side by side. Lesson 27 needed that comparison and built it from two sources instead: the Kotlin coroutine docs listed above for the coroutine side, and the Java workspace's concurrency sheet for the virtual-thread side, whose figures are measured on one machine rather than quoted. The gap that remains is a single authoritative treatment; the two-source version is sound but its axes are this repository's own, not a citable framing.
Dispatchers.IO.limitedParallelismnumbers, and the coroutine equivalents of the concurrency sheet's measured ratios, come from no measurement of this workspace's own. Lesson 25 states the documented limits and lesson 27 attributes the ratios to the Java workspace's runs; a Kotlin-side benchmark would let both stop borrowing.