Is a list of Ebooks a list of Products? For a read-only List, yes: you can only take products out. For a MutableList, no: code holding it as MutableList<Product> could add a paper book. Kotlin marks this on the type parameter. out T only produces T and is covariant; in T only consumes T and is contravariant; no modifier means invariant. Hence List<out E>, Comparable<in T>, MutableList<E> and Flow<out T> (Coroutines and Flow).

The compiler enforces both rules:
open class Product
class Ebook : Product()
interface Source<out T> { fun push(item: T) }
val products: MutableList<Product> = mutableListOf<Ebook>()varerr.kt:3:42: error: type parameter 'T' is declared as 'out' but occurs in 'in' position in type 'T (of interface Source<out T>)'. varerr.kt:4:36: error: initializer type mismatch: expected 'MutableList<Product>', actual 'MutableList<Ebook>'.
When a class is invariant but a function only reads or only writes it, put the modifier at the use site. This type projection is Java's ? extends and ? super. A star projection, List<*>, reads elements as Any? and accepts no additions.
open class Product(val title: String) { override fun toString() = title }
class Ebook(title: String) : Product(title)
fun interface Sink<in T> { fun accept(item: T) }
fun copyInto(from: MutableList<out Product>, to: MutableList<in Product>) { to += from }
fun main() {
val products: List<Product> = listOf(Ebook("Patterns of the Deep Web")) // out
val log: Sink<Ebook> = Sink<Any> { println("Logged $it") } // in
log.accept(Ebook("Gardens in Glass"))
val shelf: MutableList<Any> = mutableListOf("header")
copyInto(mutableListOf(Ebook("Salt and Saffron")), shelf)
val unknown: List<*> = shelf
println("${products.size} product; shelf has ${unknown.size}: $unknown")
}Logged Gardens in Glass 1 product; shelf has 2: [header, Salt and Saffron]
TypeScript 4.7 added optional in and out annotations with the same meaning.