Skip to content

Instantly share code, notes, and snippets.

@milis92
Last active March 20, 2023 01:20
Show Gist options
  • Select an option

  • Save milis92/fad4a027e38457fdaa3e1fdd2ea266fc to your computer and use it in GitHub Desktop.

Select an option

Save milis92/fad4a027e38457fdaa3e1fdd2ea266fc to your computer and use it in GitHub Desktop.
Kotlin Generics Blog Content
// Where hierarchy tree looks like Animal->Dog->Husky
public static void main(String[] args) {
List<? super Dog> animals = new ArrayList<Animal>(); //Compatible type
List<? super Dog> dogs = new ArrayList<Dog>(); //Compatible type
List<? super Dog> huskies = new ArrayList<Husky>(); //Incompatible type
contravariance(new ArrayList<Animal>()); //Ok
contravariance(new ArrayList<Dog>()); //OK
contravariance(new ArrayList<Husky>()); //Compiler error
}
public static void contravariance(List<? super Dog> list) { /* ... */ }
public static void contravariance(List<? super Dog> list) {
//We can add Dogs and anything that extends Dog
list.add(new Dog()); //Ok
list.add(new Husky()); //Ok
//But we can consume anything
Dog dog = list.get(0); //Compile error
Husky husky = list.get(0);//Compile error
}
//Hierarchy tree looks like Animal->Dog->Husky
abstract class MyType<in T> {
abstract fun produce(): T //Error
abstract fun consume(type : T) //Ok
}
fun getType(type: MyType<Dog>){
type.consume(Husky()) //Ok
type.consume(Dog()) //Ok
type.consume(Animal()) //Error
}
// Where hierarchy tree looks like Animal->Dog->Husky
public static void main(String[] args) {
List<? extends Dog> animals = new ArrayList<Animal>(); //Incompatible type
List<? extends Dog> dogs = new ArrayList<Dog>(); //Compatible type
List<? extends Dog> huskies = new ArrayList<Husky>(); //Compatible types
covariance(new ArrayList<Dog>()); //OK
covariance(new ArrayList<Husky>()); //OK
covariance(new ArrayList<Animal>()); //Compiler error
}
public static void covariance(List<? extends Dog> list) { /* ... */ }
public static void covariance(List<? extends Dog> list) {
//Compiler is not sure if this list contains Dog's or subtypes of Dog so adding items is considered unsafe
list.add(new Dog()); //Compile error
list.add(new Husky()); //Compile error
//We can read dogs because of the upcast
Dog dog = list.get(0);
//But we can't read subtypes of Dog's
Husky husky = list.get(0);
}
abstract class MyType<out T> {
abstract fun produce(): T //Ok
abstract fun consume(type : T) //Error
}
fun getType(type: MyType<Dog>){
val husky : Husky = type.produce() //Error
val dog : Dog = type.produce() //Ok
val animal : Animal = type.produce() //Ok
}
List<? extends Dog> animals = new ArrayList<Dog>();
List<? extends Dog> animals = new ArrayList<Husky>();
List<? extends Dog> animals = new ArrayList<Retriever>();
// Where hierarchy tree looks like Animal->Dog->Husky
public static void main(String[] args) {
List<Dog> dogs = new ArrayList<Dog>(); //Compatible type
List<Dog> animals = new ArrayList<Animal>(); //Incompatible type
List<Dog> huskies = new ArrayList<Husky>(); //Incompatible type
invariance(new ArrayList<Dog>()); //OK
invariance(new ArrayList<Animal>()); //Compiler error
invariance(new ArrayList<Husky>()); //Compiler error
}
public static void invariance(List<Dog> list) { /* ... */ }
//Hierarchy tree looks like Animal->Dog->Husky
abstract class MyType<T> {
abstract fun produce(): T //Ok
abstract fun consume(type : T) //Ok
}
fun produceType(type: MyType<out Dog>){
type.consume(Dog()) //Error - We can't consume anything
val dog : Dog = type.produce() //Ok - we can produce values of type T
}
fun consumeType(type: MyType<in Dog>){
type.consume(Dog()) //Ok - We can consume subtypes of T
val dog:Dog = type.produce() //Error - We cant produce values of type T
}
//Where MyCustom type is generic type and <T> is a type parameter
class MyCustomType<T>()
fun main(){
//Where <String> is type argument
val myCustomTypeOfStrings = MyCustomType<String>()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment