-
-
Save abreslav/9669252 to your computer and use it in GitHub Desktop.
// Why do we need variance | |
// Invariant class List, just like in Java | |
class List<T> { /* normal list */ } | |
fun printContents(list: List<Any>) { | |
for (item in list) { | |
println(item) | |
} | |
} | |
fun test() { | |
val list: List<String> = listOf("a", "b") | |
printContents(list) // ERROR: List<String> is not a subtype of List<Any> | |
} |
polymorphism is about having different implementations
I think it is important to mention that term "polymorphism" may have slightly different meaning depending on context. I criticize subtyping polymorphism, not the parametric polymorphism of course.
We can have variance in Java, too. In your case, we don't need to know anything about the type of the list's elements, just that they can be printed (which in Java, applies to any Object):
void printContents(list: List<?>) {
for (Object item in list) {
System.out.println(item)
}
}
In general, for any function that takes a list of elements that belong to some class or interface X, we'd define the argument as List<? extends X>. In the animal example, we'd have a feedAll(Collection<? extends Animal>) function. This will assure that we can feed it (assuming the implementation obeys the Liskov Substitution Principle), and the compiler will balk on trying to feed a list of anchovies.
The reverse case (contravariance) often comes up with callbacks, e.g. in the standard library, there are a few methods that take a Comparator (which is in a sense a callback). So not to require a Comparator of a specific type, they will usually ask for a Comparator<? super X>.
I'd imagine the reasoning within Kotlin is about the same as in Java?
I think it is important to mention that term "polymorphism" may have slightly different meaning depending on context. I criticize subtyping polymorphism, not the parametric polymorphism of course.
What you say is far too theoretical, I'm afraid.
Only parametric polymorphism is Haskell minus irrelevant piculiarities (laziness, immutable data etc). And that's too hard for people to grasp. And to be practical this kind of language would need type classes, that are even harder, and then structural subtyping for record that is impossible to implement efficiently over JVM.
I'm closing the case here. Too many keystrokes. If you want to discuss further, let's talk over skype (andrey.breslav).
@llogiq I agree with your point. Actually even the current implementation of Java is covering 95% of all practical use cases.
Ok. Andrey, thank you very much for participation and for your time. It was very interesting and informative discussion. I hope we will have a chance to continue it later.
I'm following your project with interest. Albeit we have different points of view in some controversial problems, I must admit JetBrains making the best products in its market. And there is no doubt, Kotlin is one of them.
P.S. I'm going to add you on my Skype contact list, so we will be in touch.
Just for the record. On the matter of variance in Java (which is called use-site variance): https://prezi.com/lnw_oiv1gs-j/java-8-vs-kotlin/
Returning to the example with Dogs and Cats. Virtual methods could be easily replaced with anonymous functions. Both have the same goal: customization of behaviour. But having different ways to reach the same thing makes syntax inconsistent, and difficult to understand for people as well as for machines. I hope you will not negate that syntax simplicity is an advantage.