Question
I am having trouble understanding the out keyword in Kotlin, and I could not clearly find its meaning.
For example, what does this mean?
CopyList<out T>
Could someone explain what out does in Kotlin generics and when it is used?
Short Answer
By the end of this page, you will understand what out means in Kotlin generics, why it is used for covariance, and how it affects what a class or function can safely do with a type parameter. You will also see practical examples and common mistakes beginners make when reading or writing out T.
Concept
Kotlin's out keyword is used in generics to say that a type parameter is only produced and not consumed.
In simple terms:
out Tmeans: "This generic type gives you values of typeT"- It should not accept values of type
Tas input in unsafe ways - This makes the type covariant
Why this matters
Suppose Cat is a subtype of Animal.
If a generic type only produces values, then a Producer<Cat> can safely be used where a Producer<Animal> is expected, because every Cat is also an Animal.
That is exactly what out allows.
The core idea
class Box<out T>(private val value: T) {
fun get(): T = value
}
Here, Box<out T> means:
Mental Model
Think of out as a vending machine.
- A vending machine gives items out
- You can take items from it
- But you do not put random items back into it
If a machine says it gives out Cat, then it is safe to treat it as a machine that gives out Animal, because every cat is an animal.
So:
out= output only- safe to read from
- not safe to write into
A short memory trick:
out-> producerin-> consumer
Another way to remember it:
- Producer = out
- Consumer = in
This is often called the PECS idea from generics:
- Producer Extends -> like
out - Consumer Super -> like
in
Syntax and Examples
Basic syntax
class Producer<out T>(private val item: T) {
fun produce(): T = item
}
Here, T is marked with out, so Producer is only allowed to expose T as output.
Example with animals
open class Animal {
fun speak() = println("animal sound")
}
class Cat : Animal()
class Cage<out T>(private val animal: T) {
fun getAnimal(): T = animal
}
fun main() {
catCage: Cage<Cat> = Cage(Cat())
animalCage: Cage<Animal> = catCage
animal = animalCage.getAnimal()
animal.speak()
}
Step by Step Execution
Consider this example:
open class Animal
class Cat : Animal()
class Source<out T>(private val value: T) {
fun get(): T = value
}
fun main() {
val catSource: Source<Cat> = Source(Cat())
val animalSource: Source<Animal> = catSource
val animal: Animal = animalSource.get()
println(animal)
}
Step by step
1. Animal is the parent type
open class Animal
class Cat : Animal()
Catinherits fromAnimal- So every
Catis also an
Real World Use Cases
out is useful when a type is mainly a source of values.
Common use cases
Read-only collections
fun printAnimals(animals: List<Animal>) {
for (animal in animals) {
println(animal)
}
}
Because List is covariant, you can pass List<Cat> to a function expecting List<Animal>.
API response wrappers
sealed class Result<out T> {
data class Success<T>(val value: T) : Result<T>()
data class Error(val message: String) : Result<Nothing>()
}
A Result<Cat> can be used where Result<Animal> is expected if the result only carries output data.
Real Codebase Usage
In real projects, developers use out when designing APIs that are meant to be read-only or producer-oriented.
Common patterns
Read-only interfaces
A mutable class may have internal state, but the public interface exposes only output operations.
interface ReadOnlyBox<out T> {
fun get(): T
}
This makes the API more flexible and safer.
Return-type wrappers
Wrappers like Result<T>, Response<T>, or Resource<T> often use out because callers mostly read the wrapped value.
Guarding against invalid writes
If a type should not accept outside values, marking it as out communicates that clearly in the type system.
Safer function parameters
A function that only reads from a generic source can accept covariant types more easily.
fun logAnimals {
println(source.())
}
Common Mistakes
1. Thinking out means "outside"
It does not mean scope or visibility. It refers to the direction of type usage.
out= values go out of the generic typein= values go into the generic type
2. Trying to use T as input in an out class
Broken example:
class Box<out T> {
fun put(item: T) {
// Error
}
}
Why it fails:
item: Tis an input positionout Tonly allows output positions
3. Assuming MutableList<Cat> can become MutableList<Animal>
This is unsafe.
val cats: MutableList<Cat> = mutableListOf(Cat())
Comparisons
| Concept | Meaning | Safe assignment example | Typical use |
|---|---|---|---|
out T | Covariant, producer of T | Source<Cat> -> Source<Animal> | Read-only APIs, lists, results |
in T | Contravariant, consumer of T | Consumer<Animal> -> Consumer<Cat> | Comparators, handlers, processors |
plain T | Invariant | No subtype substitution | Mutable structures, read-write types |
out vs
Cheat Sheet
Quick rules
out Tmeans the generic type producesToutmakes the type parameter covariant- You can return
T - You should not accept
Tin input positions
Safe idea
interface Source<out T> {
fun get(): T
}
Unsafe idea
interface Box<out T> {
fun set(value: T) // Not allowed
}
Assignment rule
If Cat : Animal, then with out:
Source<Cat> -> Source<Animal>
Memory trick
FAQ
What does out mean in Kotlin?
out marks a generic type parameter as covariant. It means the type is used for output only, so the generic type can safely produce values of that type.
Why is List declared with out in Kotlin?
Because a read-only list only provides items. It does not allow adding new ones, so covariance is safe.
What is the difference between out and in in Kotlin?
outis for producersinis for consumers
Use out when values come from the type, and in when values go into the type.
Can I use a type parameter with both input and output if it is marked out?
No. If a type parameter is marked out, Kotlin restricts it from being used in unsafe input positions.
Is out the same as Java extends in generics?
It is similar to Java's ? extends T in many cases. Both express covariance.
Mini Project
Description
Build a small Kotlin example that models a read-only animal provider. This project demonstrates why out is useful when a generic type only returns values and should support safe subtype substitution.
Goal
Create a covariant generic provider that can return Cat objects and still be used where an Animal provider is expected.
Requirements
- Define a parent class
Animaland at least one subclassCat. - Create a generic interface or class using
out T. - Add a function that returns a value of type
T. - Show that an instance with
Catcan be assigned to a variable expectingAnimal. - Print or use the returned value to prove the assignment works.
Keep learning
Related questions
Accessing Kotlin Extension Functions from Java
Learn how Kotlin extension functions are compiled and how to call them correctly from Java with clear examples and common pitfalls.
Allow HTTP and HTTPS in Android 9 Pie with Network Security Configuration
Learn how Android 9 Pie handles cleartext HTTP traffic and how to allow HTTP and HTTPS safely using network security config.
Android AlarmManager Example: Scheduling Tasks with AlarmManager
Learn how to use Android AlarmManager to schedule tasks, set alarms, and handle broadcasts with a simple beginner example.