Kotlin

What is out keyword in kotlin

27 September 2026 · 6 min read

What is out keyword in kotlin

Kotlin, a modern, statically typed programming language, is celebrated for its conciseness, safety, and interoperability. One of its powerful features, particularly when working with collections and generic types, is the concept of type variance, managed by keywords like out and in. Understanding what is out keyword in Kotlin is crucial for any developer aiming to write robust, flexible, and type-safe code. This special modifier addresses a common challenge in object-oriented programming: how to handle subtyping relationships with generic types. Without it, developers would frequently encounter frustrating type mismatches and limitations, especially when trying to pass a list of more specific types to a function expecting a list of a more general type. Let’s delve into how out enables greater flexibility and enhances the utility of generic interfaces and classes in your Kotlin projects.

Demystifying Generics and Type Variance in Kotlin

Generics are fundamental to modern programming languages, allowing you to write code that works with various types while maintaining compile-time type safety. In Kotlin, generic types enable the creation of classes, interfaces, and functions that can operate on data of any type without sacrificing the benefits of static typing. For instance, a List<String> is a list specifically designed to hold strings, while a List<Int> holds integers. This flexibility is powerful, but it introduces a challenge known as type variance.

Type variance defines how subtyping relationships between types affect subtyping relationships between generic instantiations of those types. There are three main types of variance: invariance, covariance, and contravariance. By default, Kotlin’s generic types are invariant, meaning that if you have a List<Animal> and List<Cat> (where Cat is a subtype of Animal), List<Cat> is NOT considered a subtype of List<Animal>. This default behavior can be restrictive, preventing you from using more specific types where a more general type is expected, even when it seems logically safe to do so. This is precisely where variance annotations like out come into play, allowing developers to express their intent and relax these restrictions safely.

The core problem arises because if List<Cat> were a subtype of List<Animal> by default, you could potentially add an Animal (like a Dog) to a List<Cat> through its List<Animal> reference, leading to a runtime error. Kotlin’s type system is designed to prevent such unsafe operations, which is why explicit variance modifiers are necessary to declare intent and ensure type safety. According to JetBrains, the creators of Kotlin, “type safety is paramount,” and features like variance ensure that “your programs are less prone to runtime errors.”

The out Keyword: Enabling Covariance for Producers

The out keyword in Kotlin is a variance annotation that declares a type parameter as covariant. When you mark a type parameter T with out (e.g., interface Source<out T>), you are essentially stating that T can only be “produced” by the class or interface, meaning it can only appear in “out” positions. An “out” position typically refers to the return type of a method, indicating that the generic type will be returned or outputted by the generic class.

This is extremely useful when you have a generic class that acts as a “producer” of objects of type T. For example, consider an interface Producer<out T>. If Cat is a subtype of Animal, then a Producer<Cat> can safely be treated as a Producer<Animal>. The out keyword enables this subtyping relationship, allowing you to assign an instance of Producer<Cat> to a variable of type Producer<Animal>. This makes your code more flexible, as you can write functions that accept a Producer<Animal> and seamlessly work with producers of any of its subtypes.

The critical restriction with out is that the type parameter T cannot be used in “in” positions, such as parameters of methods. This means you cannot pass an object of type T into a method of the generic class. This restriction is vital for maintaining type safety; if you could pass an Animal into a Producer<Cat> (which is now seen as a Producer<Animal>), you could potentially add a non-Cat animal, violating the original type expectation. The Kotlin standard library extensively uses out, for instance, in interfaces like Iterable<out T> and List<out T>, allowing you to treat an Iterable<String> as an Iterable<Any>, which significantly enhances their utility and interoperability.

The out keyword in Kotlin is a declaration-site variance modifier that allows a generic type parameter to be used only in “out” (producer) positions, such as function return types. This makes the generic type covariant, meaning if B is a subtype of A, then Generic<B> becomes a subtype of Generic<A>. This mechanism ensures type safety by preventing the generic type from consuming instances of its type parameter, thereby avoiding potential runtime errors when dealing with subtyping hierarchies.

Practical Applications and Real-World Scenarios

The utility of the out keyword becomes evident in everyday Kotlin programming, particularly when dealing with data structures and function signatures. Consider the List<T> interface in Kotlin’s standard library. It’s declared as interface List<out E> : Collection<E>. The out modifier on E (the element type) signifies that a List only produces elements of type E; it doesn’t consume them (i.e., you can’t add elements to a List through its List interface, only through its mutable counterpart, MutableList). This design choice allows for flexible subtyping.

For example, if you have a List<Apple> and Apple is a subtype of Fruit, you can safely assign List<Apple> to a variable of type List<Fruit>. This is because a list of apples can always be treated as a list of fruits when you’re only extracting elements. This flexibility is crucial for writing generic functions that operate on collections of various related types without requiring explicit type casting or complex workarounds. Without out, you would frequently face type mismatch errors, diminishing the benefits of inheritance hierarchies.

Here are common scenarios where out is invaluable:

  1. Reading from Collections: When you need to read elements from a collection, out allows you to treat a collection of a subtype as a collection of its supertype. For instance, a function expecting List<Any> can receive List<String><b>Question & Answer : </b><br></br><p>I am not able to understand and I couldn't find the meaning of <strong>out</strong> keyword in kotlin.</p> <p>You can check example here: </p> <pre>List<out T> </pre> <p>If any one can explain the meaning of this. It would be really appreciated.</p><br></br><p>List<out T> in Kotlin is equivalent to List<? extends T> in Java.</p> <p>List<in T> in Kotlin is equivalent to List<? super T> in Java</p> <p>For example in Kotlin you can do things like</p> <pre class="lang-kotlin prettyprint-override">val value : List<Any> = listOf(1,2,3) //since List signature is List<out T> in Kotlin </pre> <p>The reasoning is you can mark generic "out" if you returning it, but never receiving. And you can mark it "in" if you receive it, but never return.</p>